LeaveMessage.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. <template>
  2. <div>
  3. <div class="row allAlignment">
  4. <leftNav/>
  5. <div>
  6. <hader/>
  7. <messageCenter></messageCenter>
  8. <div class="column allAlignment box" style="background:#F6F8FF; ">
  9. <div style="height:8vh; background:#FFF; " class="row allAlignment">
  10. <div class="name_box row center">
  11. <span>留言列表</span>
  12. </div>
  13. <div class="row center allAlignment">
  14. <el-select v-model="value" size="mini" @change="getStartEndAjaxTime(value)" style="width: 28%;" placeholder="请选择">
  15. <el-option
  16. v-for="item in options"
  17. :key="item.value"
  18. :label="item.label"
  19. :value="item.value"
  20. ></el-option>
  21. </el-select>
  22. <div>
  23. <el-input
  24. placeholder="请输入内容"
  25. size="mini"
  26. v-model="input3"
  27. class="input-with-select"
  28. >
  29. <el-button slot="append" icon="el-icon-search"></el-button>
  30. </el-input>
  31. </div>
  32. </div>
  33. </div>
  34. <div style="margin:0 20px;">
  35. <el-table
  36. :header-cell-style="{background:'#eef1f6',color:'#606266'}"
  37. :row-style="{background:'#ffffff',color:'#606266'}"
  38. :data="tableData"
  39. stripe
  40. @row-dblclick="click_row"
  41. :size="size"
  42. style="width: 100%;"
  43. :default-sort = "{prop: 'sortable', order: 'message_status'}"
  44. >
  45. <el-table-column prop="nick_name" width="120" label="用户名"></el-table-column>
  46. <el-table-column prop="add_time" width="160" label="留言时间" sortable></el-table-column>
  47. <el-table-column prop="content" label="留言内容">
  48. <template slot-scope="scope">
  49. <el-popover width="800" trigger="hover" placement="top">
  50. <p >{{ scope.row.content }}</p>
  51. <div slot="reference" class="name-wrapper">
  52. <el-tag size="medium">{{ scope.row.content }}</el-tag>
  53. </div>
  54. </el-popover>
  55. </template>
  56. </el-table-column>
  57. <el-table-column prop="phone" width="160" label="手机"></el-table-column>
  58. <el-table-column prop="email" width="240" label="邮箱"></el-table-column>
  59. <el-table-column prop="message_status" width="120" label="当前状态" sortable>
  60. <template slot-scope="scope">
  61. <span style="color:#FF6600" v-if="scope.row.message_status == '0'"> 未回复</span>
  62. <span v-if="scope.row.message_status == '1'">已处理</span>
  63. </template>
  64. </el-table-column>
  65. <el-table-column prop="user_name" width="160"label="处理人"></el-table-column>
  66. </el-table>
  67. </div>
  68. <div v-show="pages >9" style=" padding: 10px;">
  69. <el-pagination background layout="prev, pager, next" prev-text='上一页' next-text='下一页' :total="pages" @prev-click='upData'
  70. @next-click="downData" @current-change="current_page"></el-pagination>
  71. </div>
  72. <div class="right_box" v-show="isShow">
  73. <historicalRecord :show="isShow" :uid="uid" v-on:childValue="childValue"/>
  74. </div>
  75. </div>
  76. </div>
  77. <!-- 详情抽屉-->
  78. <el-drawer
  79. id="leaveMessage"
  80. :close-on-press-escape="true"
  81. :show-close="false"
  82. :visible.sync="drawer"
  83. size="1000px">
  84. <el-row class="content_box">
  85. <el-row class="headers">
  86. <el-col :span="12">留言信息</el-col>
  87. <!-- <el-col :span="12" style="text-align: right">-->
  88. <!-- <el-button class="chuli" type="warning">未处理</el-button>-->
  89. <!-- </el-col>-->
  90. </el-row>
  91. <el-row class="chat_user">
  92. <el-col style=" height: 88vh;background:#e6d0d033;overflow-y:auto; padding-bottom: 30px;" :span="16">
  93. <div class="chat_box">
  94. <!-- 内容展示 -->
  95. <el-row id="main">
  96. <el-col class="user">
  97. <span style="color: #999999;">用户<span style="color:#666;">{{userInfo.account_name}}</span>留言</span>
  98. <div class="user_text">{{getUserItem.content}}</div>
  99. <div class="img block " v-for="item in getUserItem.image">
  100. <el-image
  101. style="width: 100px; height: 100px"
  102. :src="img_http +item"
  103. :fit="fit"
  104. :preview-src-list="[img_http +item]">
  105. </el-image>
  106. </div>
  107. </el-col>
  108. <div v-if="getUserItem.message_status == 0">
  109. <el-col class="serive">
  110. <el-input class="serive_text" resize="none" type="textarea"
  111. @blur="widthCheck($event.target, 100)" placeholder="请回复用户留言"
  112. maxlength="120" show-word-limit
  113. v-model.trim="leaveInfor"></el-input>
  114. </el-col>
  115. <el-col>
  116. <el-upload style="margin:10px;"
  117. action="https://manage.281570.com/index/upload/uploadImg"
  118. :before-upload="beforeAvatarUpload"
  119. :on-change='uploadChange'
  120. :on-success='uploadSuccess'
  121. :on-error="uploadError"
  122. :on-remove="handleRemove"
  123. :auto-upload="false"
  124. list-type="picture-card"
  125. ref="upload"
  126. :file-list="fileList"
  127. :limit="4"
  128. :on-exceed="handleExceed"
  129. >
  130. <i slot="default" class="el-icon-plus"></i>
  131. </el-upload>
  132. <el-dialog>
  133. <img width="100%" :src="dialogImageUrl" alt="">
  134. </el-dialog>
  135. </el-col>
  136. </div>
  137. <div v-else>
  138. <el-col class="serive">
  139. <span style="color: #999999;">客服<span style="color: #5399f5">{{getUserItem.user_name}}</span>回复用户<span style="color:#666;">{{userInfo.account_name}}</span>留言</span>
  140. <div class="serive_text">{{getUserItem.reply_content}}</div>
  141. <div style="padding: 10px 15px;">
  142. <div class="img block" v-for="item in getUserItem.images">
  143. <el-image
  144. style="width: 100px; height: 100px"
  145. :src="img_http +item"
  146. :fit="fit"
  147. :preview-src-list="[img_http +item]">
  148. </el-image>
  149. </div>
  150. </div>
  151. </el-col>
  152. </div>
  153. </el-row>
  154. <div v-if="getUserItem.message_status == 0" class="chatting">
  155. <el-button class="send" type="primary" @click="sendMessage">提交</el-button>
  156. </div>
  157. </div>
  158. </el-col>
  159. <el-col :span="8">
  160. <div class="user_box">
  161. <ul>
  162. <li class="title">用户信息</li>
  163. <li>账号:{{userInfo.account_name}}</li>
  164. <li>标签:{{userInfo.label}}</li>
  165. <li>昵称:{{userInfo.nick_name}}</li>
  166. <li>手机:{{userInfo.account_phone}}</li>
  167. <li>邮箱:{{userInfo.account_email}}</li>
  168. <li>地址:{{userInfo.address}}</li>
  169. <li>备注:{{userInfo.remark}}</li>
  170. </ul>
  171. <ul>
  172. <li class="title">访问信息</li>
  173. <li>来源ip:{{getUserItem.account_ip}}</li>
  174. <li>来源终端:{{getUserItem.system}}-{{getUserItem.browse}}</li>
  175. </ul>
  176. </div>
  177. </el-col>
  178. </el-row>
  179. </el-row>
  180. </el-drawer>
  181. </div>
  182. </div>
  183. </template>
  184. <script>
  185. import "@/css/index.css";
  186. import leftNav from "@/components/leftNav";
  187. import hader from "@/components/hader";
  188. import historicalRecord from "@/components/historicalRecord";
  189. import messageCenter from "@/components/messageCenter";
  190. import frce from '../assets/frce.js';
  191. export default {
  192. name: "SessionHistory",
  193. data() {
  194. return {
  195. isShow: false,
  196. uid: "",
  197. pages: 0,
  198. tableData: [],
  199. options: [
  200. {
  201. value: "今日",
  202. label: "今日"
  203. },
  204. {
  205. value: "最近3天",
  206. label: "最近3天"
  207. },
  208. {
  209. value: "最近7天",
  210. label: "最近7天"
  211. },
  212. {
  213. value: "最近15天",
  214. label: "最近15天"
  215. },
  216. {
  217. value: "最近30天",
  218. label: "最近30天"
  219. }
  220. ],
  221. value: "",
  222. input3: "",
  223. startTime: "", // 请求结果开始时间
  224. endTime: "", // 请求结果结束时间
  225. drawer: false,
  226. sendCol: false, // 发送按钮切换样式
  227. leaveInfor: '', // 留言信息
  228. dialogImageUrl: '',
  229. userInfo: [], //用户信息
  230. getUserItem: [],
  231. img_http: 'https://manage.281570.com',//图片路径域
  232. fileList:[],
  233. imgUrl:'',
  234. users:[],
  235. fit:'contain',
  236. isSendMessage:false,//是否提交
  237. size:'small',//表单大小
  238. isUpImg:false,//是否提交图片片
  239. };
  240. },
  241. components: {
  242. leftNav,
  243. hader,
  244. historicalRecord,
  245. messageCenter
  246. },
  247. mounted() {
  248. this.frceArr = frce.frce;
  249. this.value = this.options[2].value;
  250. if(typeof this.$store.getters.get_user_info != 'string'){
  251. this.users = this.$store.getters.get_user_info;
  252. }else if(this.$store.getters.get_user_info!= ""){
  253. this.users = JSON.parse(this.$store.getters.get_user_info);
  254. }
  255. this.getStartEndAjaxTime(this.value)
  256. },
  257. computed: {
  258. },
  259. watch: {
  260. },
  261. methods: {
  262. /******************上一页*****************/
  263. upData(e) {
  264. this.getSessionList(e)
  265. },
  266. /*********************下一页******************/
  267. downData(e) {
  268. this.getSessionList(e)
  269. },
  270. /*******************选择页数******************/
  271. current_page(e) {
  272. this.getSessionList(e)
  273. },
  274. // 上传之前
  275. beforeAvatarUpload(file) {
  276. // console.log(file, '上传之前')
  277. // const isJPG = file.type == 'image/jpeg' || 'image/jpg' || 'image/png' || 'image/svg';
  278. // const isLt1M = file.size / 1024 / 1024 < 0.5;
  279. // if (!isJPG) {
  280. // this.$message.error('上传只能是图片格式!');
  281. // }
  282. // if (!isLt1M) {
  283. // this.$message.error('上传图片大小单张不能超过0.5MB!');
  284. // }
  285. //return isJPG && isLt1M;
  286. },
  287. // 上传成功时的回调
  288. uploadSuccess(res, file, fileList) {
  289. this.imgUrl = this.imgUrl ? this.imgUrl + "," + res.data.src :res.data.src;
  290. },
  291. // 发送中
  292. onProgress() {
  293. },
  294. // 上传失败
  295. uploadError() {
  296. this.$message.error('上传失败,请重新上传')
  297. },
  298. //删除回掉
  299. handleRemove(file, fileList,) {
  300. this.fileList = fileList;
  301. // this.uploadImg = fileList;
  302. },
  303. // 每次改变图片状态返回的回调
  304. uploadChange(file, fileList) {
  305. // console.log(file)
  306. const isJPG = file.raw.type == 'image/jpeg' || 'image/jpg' || 'image/png' || 'image/svg';
  307. const isLt1M = file.size / 1024 / 1024 < 0.5;
  308. if (!isJPG) {
  309. this.$message.error('上传只能是图片格式!');
  310. fileList.pop();
  311. this.fileList = fileList;
  312. return false
  313. }
  314. if (!isLt1M) {
  315. this.$message.error('上传图片大小单张不能超过0.5MB!');
  316. fileList.pop()
  317. this.fileList = fileList;
  318. return false
  319. }
  320. this.$refs.upload.clearFiles();
  321. if(!this.isUpImg){
  322. this.fileList.push(file)
  323. }else{
  324. this.fileList = fileList
  325. }
  326. },
  327. handleExceed(files, fileList) {
  328. this.$message.error(`图片上传数量最多4张`);
  329. },
  330. //提交留言
  331. sendMessage() {
  332. if(this.leaveInfor){
  333. this.isUpImg = true;
  334. this.$refs.upload.submit();
  335. this.isSendMessage = false;
  336. setTimeout(()=>{
  337. let parmas = {
  338. "user_id":this.users.id,
  339. "message_id":this.uid,
  340. "reply_content":this.leaveInfor,
  341. "images":this.imgUrl,
  342. }
  343. this.$http.post(this.$ports.Message.dealmessage, parmas).then(res => {
  344. this.$message.success(res.data.msg);
  345. this.leaveInfor = '';
  346. this.drawer = false;
  347. this.getSessionList(1)
  348. this.$refs.upload.clearFiles();
  349. this.fileList =[];
  350. })
  351. },1500)
  352. }else{
  353. this.$message.error(`请输入留言信息`);
  354. }
  355. },
  356. /*****************获取当前聊天用户信息****************/
  357. get_user(id) {
  358. let obj = {
  359. headers: {
  360. "apiToken": this.$md5('accountInfo' + "customer-service" + 'service' + 'service'),
  361. 'userToken': this.token
  362. },
  363. };
  364. this.$http.post(this.$ports.userInfo.accountInfo, {
  365. account_id: id
  366. },obj).then(res => {
  367. if (res.data.code == 1) {
  368. this.userInfo = res.data.data;
  369. }
  370. })
  371. },
  372. widthCheck(str, len) {
  373. var temp = 0
  374. for (var i = 0; i < str.value.length; i++) {
  375. if (str.value.length < 4) {
  376. str.value = ''
  377. }
  378. }
  379. },
  380. // 获取请求参数开始和结束时间
  381. getStartEndAjaxTime(e) {
  382. console.log(e);
  383. let time = new Date();
  384. let time2 = new Date(time)
  385. function getDate(year, month, date) {
  386. return year + '-' + ((month + 1) < 10 ? '0' + (month + 1) : month + 1) + '-' + (date < 10 ? '0' + date : date)
  387. }
  388. if (e == "今日") {
  389. time2.setDate(time.getDate())
  390. } else if (e == "最近3天") {
  391. time2.setDate(time.getDate() - 3)
  392. } else if (e == "最近7天") {
  393. time2.setDate(time.getDate() - 7)
  394. } else if (e == "最近15天") {
  395. time2.setDate(time.getDate() - 15)
  396. } else if (e == "最近30天") {
  397. time2.setDate(time.getDate() - 30)
  398. }
  399. this.endTime = getDate(time.getFullYear(), time.getMonth(), time.getDate())
  400. this.startTime = getDate(time2.getFullYear(), time2.getMonth(), time2.getDate())
  401. this.getSessionList(1)
  402. },
  403. // 获取列表数据
  404. getSessionList(page, size=10) {
  405. let searchText =this.input3
  406. let str = "index" + "customer-service" + "message" + "service";
  407. this.$http.get(this.$ports.Message.index, {params:{
  408. start_time: this.startTime,
  409. end_time: this.endTime,
  410. pageSize: size,
  411. pageNumber:page,
  412. searchText:searchText,
  413. },headers: {
  414. apiToken: this.$md5(str),
  415. userToken: this.token
  416. }}
  417. ).then(res => {
  418. if (res.data.status == 1) {
  419. this.tableData = res.data.data.list;
  420. //this.pages = res.data.data.length;
  421. this.pages = res.data.data.total;
  422. // console.log(res.data.data)
  423. }
  424. });
  425. },
  426. //获取留言列表数据(行)
  427. click_row(row, column, event) {
  428. this.uid = row.message_id;
  429. this.drawer = true;
  430. this.isSendMessage = true;
  431. this.getUserItem = row;
  432. if(this.getUserItem.image){
  433. if(this.getUserItem.image.includes(',') && typeof this.getUserItem.image == 'string'){
  434. this.getUserItem.image = this.getUserItem.image.split(',');
  435. }else{
  436. if(typeof this.getUserItem.image == 'string'){
  437. this.getUserItem.image =[this.getUserItem.image]
  438. }else{
  439. this.getUserItem.image =this.getUserItem.image
  440. }
  441. }
  442. }
  443. if(this.getUserItem.images){
  444. if(this.getUserItem.images.includes(',') && typeof this.getUserItem.images == 'string'){
  445. this.getUserItem.images = this.getUserItem.images.split(',');
  446. }else{
  447. if(typeof this.getUserItem.images == 'string'){
  448. this.getUserItem.images = [this.getUserItem.images]
  449. }else{
  450. this.getUserItem.images = this.getUserItem.images
  451. }
  452. }
  453. }
  454. // console.log(this.getUserItem.images);
  455. this.get_user(row.account_id)
  456. },
  457. childValue(e) {
  458. //console.log(e);
  459. //this.drawer =true;
  460. // this.isShow = e;
  461. },
  462. filterTag(value, row) {
  463. return row.tag === value;
  464. }
  465. }
  466. };
  467. </script>
  468. <style>
  469. .el-upload--picture-card {
  470. width: 100px !important;
  471. height: 100px !important;
  472. line-height: 100px !important;
  473. }
  474. .el-upload-list--picture-card .el-upload-list__item {
  475. width: 100px !important;
  476. height: 100px !important;
  477. line-height: 100px !important;
  478. }
  479. </style>
  480. <style lang="less" scoped>
  481. .name-wrapper{
  482. width: 240px;
  483. overflow: hidden;
  484. text-overflow: ellipsis;
  485. white-space: nowrap;
  486. }
  487. .chatting {
  488. text-align: center;
  489. }
  490. .serive {
  491. padding: 0 10px;
  492. text-align: right;
  493. .serive_text {
  494. width: 100%;
  495. margin-top: 20px;
  496. background: #F5F5F5;
  497. border: 1px solid #EEEEEE;
  498. padding: 20px;
  499. font-size: 14px;
  500. color: #666;
  501. word-wrap: break-word;
  502. }
  503. }
  504. .user {
  505. .user_text {
  506. width: 100%;
  507. margin-top: 20px;
  508. background: #F5F5F5;
  509. border: 1px solid #EEEEEE;
  510. padding: 20px;
  511. font-size: 14px;
  512. color: #666;
  513. word-wrap: break-word;
  514. // line-height: 1.8;
  515. }
  516. .img {
  517. margin-top: 20px;
  518. }
  519. }
  520. .netSendCol {
  521. cursor: not-allowed;
  522. }
  523. .content_box {
  524. .chat_user {
  525. border-top: 1px solid #D5E5FF;
  526. .block{
  527. // padding: 10px 0;
  528. text-align: center;
  529. border: 1px solid #eff2f6;
  530. display: inline-block;
  531. width: 20%;
  532. box-sizing: border-box;
  533. vertical-align: top;
  534. margin-left: 10px;
  535. }
  536. }
  537. }
  538. .user_box {
  539. height: 100vh;
  540. }
  541. .el-pagination .btn-next .el-icon {
  542. display: none;
  543. }
  544. .cell {
  545. text-align: center;
  546. }
  547. .el-pagination {
  548. text-align: center;
  549. font-size: 0;
  550. }
  551. .el-table::before {
  552. z-index: 0 !important;
  553. }
  554. .input-with-select {
  555. width: 100%;
  556. }
  557. .name_box {
  558. margin-left: 20px;
  559. font-size: 14px;
  560. font-weight: bold;
  561. color: rgba(102, 102, 102, 1);
  562. }
  563. .box {
  564. width: 100%;
  565. }
  566. .right_box {
  567. position: fixed;
  568. top: 33px;
  569. right: 0;
  570. width: 100%;
  571. /* height: 100vh;
  572. background: red; */
  573. /* //background: rgba(255, 255, 255, 0.315); */
  574. }
  575. .el-input-group__append {
  576. text-align: center;
  577. }
  578. .el-table td {
  579. padding: 8px 0;
  580. }
  581. .headers {
  582. display: flex;
  583. justify-content: flex-start;
  584. padding: 0 20px;
  585. height: 50px;
  586. line-height: 50px;
  587. }
  588. .user_box {
  589. padding: 20px;
  590. background: #F6F8FF;
  591. }
  592. .chuli {
  593. width: 70px;
  594. height: 30px;
  595. border-radius: 5px;
  596. color: #fff;
  597. background: #FF6600
  598. }
  599. .title {
  600. font-weight: bold;
  601. color: #333333;
  602. font-size: 14px;
  603. }
  604. li {
  605. margin: 10px 0;
  606. color: #999999;
  607. }
  608. ul {
  609. margin: 0;
  610. padding: 0;
  611. }
  612. #main {
  613. height: 65vh;
  614. }
  615. .icons {
  616. padding: 0 20px;
  617. height: 40px;
  618. line-height: 40px;
  619. }
  620. .send {
  621. margin: 0 auto;
  622. color: #fff;
  623. width: 60%;
  624. height: 40px;
  625. background: rgba(221, 221, 221, 1);
  626. opacity: 1;
  627. border-radius: 5px;
  628. }
  629. .send.sendCol {
  630. background: linear-gradient(90deg, rgba(22, 84, 209, 1) 0%, rgba(9, 52, 173, 1) 100%);
  631. }
  632. </style>