LeaveMessage.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  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; height: 77vh;overflow-y: scroll;">
  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='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: window.url_https_ajax,//图片路径域
  232. fileList:[],
  233. imgUrl:'',
  234. users:[],
  235. fit:'contain',
  236. isSendMessage:false,//是否提交
  237. size:'small',//表单大小
  238. isUpImg:false,//是否提交图片片
  239. img_number:'',//图片数量
  240. uploadImg:'',//
  241. };
  242. },
  243. components: {
  244. leftNav,
  245. hader,
  246. historicalRecord,
  247. messageCenter
  248. },
  249. mounted() {
  250. // this.img_http = window.url_https_ajax;
  251. this.uploadImg = this.img_http+"/index/upload/uploadImg"
  252. this.frceArr = frce.frce;
  253. this.value = this.options[2].value;
  254. if(typeof this.$store.getters.get_user_info != 'string'){
  255. this.users = this.$store.getters.get_user_info;
  256. }else if(this.$store.getters.get_user_info!= ""){
  257. this.users = JSON.parse(this.$store.getters.get_user_info);
  258. }
  259. this.getStartEndAjaxTime(this.value)
  260. },
  261. computed: {
  262. },
  263. watch: {
  264. },
  265. methods: {
  266. /******************上一页*****************/
  267. upData(e) {
  268. this.getSessionList(e)
  269. },
  270. /*********************下一页******************/
  271. downData(e) {
  272. this.getSessionList(e)
  273. },
  274. /*******************选择页数******************/
  275. current_page(e) {
  276. this.getSessionList(e)
  277. },
  278. // 上传之前
  279. beforeAvatarUpload(file) {
  280. // console.log(file, '上传之前')
  281. // const isJPG = file.type == 'image/jpeg' || 'image/jpg' || 'image/png' || 'image/svg';
  282. // const isLt1M = file.size / 1024 / 1024 < 0.5;
  283. // if (!isJPG) {
  284. // this.$message.error('上传只能是图片格式!');
  285. // }
  286. // if (!isLt1M) {
  287. // this.$message.error('上传图片大小单张不能超过0.5MB!');
  288. // }
  289. //return isJPG && isLt1M;
  290. },
  291. // 上传成功时的回调
  292. uploadSuccess(res, file, fileList) {
  293. console.log();
  294. this.img_number ++;
  295. this.imgUrl = this.imgUrl ? this.imgUrl + "," + res.data.src :res.data.src;
  296. if(this.fileList.length == this.img_number){
  297. console.log(this.imgUrl);
  298. this.sendData();
  299. }
  300. },
  301. // 发送中
  302. onProgress() {
  303. },
  304. // 上传失败
  305. uploadError() {
  306. this.$message.error('上传失败,请重新上传')
  307. },
  308. //删除回掉
  309. handleRemove(file, fileList,) {
  310. this.fileList = fileList;
  311. // this.uploadImg = fileList;
  312. },
  313. // 每次改变图片状态返回的回调
  314. uploadChange(file, fileList) {
  315. // console.log(file)
  316. const isJPG = file.raw.type == 'image/jpeg' || 'image/jpg' || 'image/png' || 'image/svg';
  317. const isLt1M = file.size / 1024 / 1024 < 0.5;
  318. if (!isJPG) {
  319. this.$message.error('上传只能是图片格式!');
  320. fileList.pop();
  321. this.fileList = fileList;
  322. return false
  323. }
  324. if (!isLt1M) {
  325. this.$message.error('上传图片大小单张不能超过0.5MB!');
  326. fileList.pop()
  327. this.fileList = fileList;
  328. return false
  329. }
  330. this.$refs.upload.clearFiles();
  331. if(!this.isUpImg){
  332. this.fileList.push(file)
  333. }else{
  334. this.fileList = fileList
  335. }
  336. },
  337. handleExceed(files, fileList) {
  338. this.$message.error(`图片上传数量最多4张`);
  339. },
  340. //提交留你数据
  341. sendData(){
  342. let parmas = {
  343. "user_id":this.users.id,
  344. "message_id":this.uid,
  345. "reply_content":this.leaveInfor,
  346. "images":this.imgUrl,
  347. }
  348. this.$http.post(this.$ports.Message.dealmessage, parmas).then(res => {
  349. this.$message.success(res.data.msg);
  350. this.leaveInfor = '';
  351. this.drawer = false;
  352. this.getSessionList(1)
  353. this.$refs.upload.clearFiles();
  354. this.fileList =[];
  355. })
  356. },
  357. //提交留言
  358. sendMessage() {
  359. if(this.leaveInfor && this.isSendMessage){
  360. if(this.fileList.length <1){
  361. this.sendData();
  362. }else{
  363. this.isUpImg = true;
  364. this.$refs.upload.submit();
  365. this.img_number = 0;
  366. this.isSendMessage = false;
  367. }
  368. // setTimeout(()=>{
  369. // },1500)
  370. }else{
  371. this.$message.error(`请输入留言信息`);
  372. }
  373. },
  374. /*****************获取当前聊天用户信息****************/
  375. get_user(id) {
  376. let obj = {
  377. headers: {
  378. "apiToken": this.$md5('accountInfo' + "customer-service" + 'service' + 'service'),
  379. 'userToken': this.token
  380. },
  381. };
  382. this.$http.post(this.$ports.userInfo.accountInfo, {
  383. account_id: id
  384. },obj).then(res => {
  385. if (res.data.code == 1) {
  386. this.userInfo = res.data.data;
  387. }
  388. })
  389. },
  390. widthCheck(str, len) {
  391. var temp = 0
  392. for (var i = 0; i < str.value.length; i++) {
  393. if (str.value.length < 4) {
  394. str.value = ''
  395. }
  396. }
  397. },
  398. // 获取请求参数开始和结束时间
  399. getStartEndAjaxTime(e) {
  400. console.log(e);
  401. let time = new Date();
  402. let time2 = new Date(time)
  403. function getDate(year, month, date) {
  404. return year + '-' + ((month + 1) < 10 ? '0' + (month + 1) : month + 1) + '-' + (date < 10 ? '0' + date : date)
  405. }
  406. if (e == "今日") {
  407. time2.setDate(time.getDate())
  408. } else if (e == "最近3天") {
  409. time2.setDate(time.getDate() - 3)
  410. } else if (e == "最近7天") {
  411. time2.setDate(time.getDate() - 7)
  412. } else if (e == "最近15天") {
  413. time2.setDate(time.getDate() - 15)
  414. } else if (e == "最近30天") {
  415. time2.setDate(time.getDate() - 30)
  416. }
  417. this.endTime = getDate(time.getFullYear(), time.getMonth(), time.getDate())
  418. this.startTime = getDate(time2.getFullYear(), time2.getMonth(), time2.getDate())
  419. this.getSessionList(1)
  420. },
  421. // 获取列表数据
  422. getSessionList(page, size=10) {
  423. let searchText =this.input3
  424. let str = "index" + "customer-service" + "message" + "service";
  425. this.$http.get(this.$ports.Message.index, {params:{
  426. start_time: this.startTime,
  427. end_time: this.endTime,
  428. pageSize: size,
  429. pageNumber:page,
  430. searchText:searchText,
  431. },headers: {
  432. apiToken: this.$md5(str),
  433. userToken: this.token
  434. }}
  435. ).then(res => {
  436. if (res.data.status == 1) {
  437. this.tableData = res.data.data.list;
  438. //this.pages = res.data.data.length;
  439. this.pages = res.data.data.total;
  440. // console.log(res.data.data)
  441. }
  442. });
  443. },
  444. //获取留言列表数据(行)
  445. click_row(row, column, event) {
  446. this.uid = row.message_id;
  447. this.drawer = true;
  448. this.isSendMessage = true;
  449. this.getUserItem = row;
  450. if(this.getUserItem.image){
  451. if(this.getUserItem.image.includes(',') && typeof this.getUserItem.image == 'string'){
  452. this.getUserItem.image = this.getUserItem.image.split(',');
  453. }else{
  454. if(typeof this.getUserItem.image == 'string'){
  455. this.getUserItem.image =[this.getUserItem.image]
  456. }else{
  457. this.getUserItem.image =this.getUserItem.image
  458. }
  459. }
  460. }
  461. if(this.getUserItem.images){
  462. if(this.getUserItem.images.includes(',') && typeof this.getUserItem.images == 'string'){
  463. this.getUserItem.images = this.getUserItem.images.split(',');
  464. }else{
  465. if(typeof this.getUserItem.images == 'string'){
  466. this.getUserItem.images = [this.getUserItem.images]
  467. }else{
  468. this.getUserItem.images = this.getUserItem.images
  469. }
  470. }
  471. }
  472. // console.log(this.getUserItem.images);
  473. this.get_user(row.account_id)
  474. },
  475. childValue(e) {
  476. //console.log(e);
  477. //this.drawer =true;
  478. // this.isShow = e;
  479. },
  480. filterTag(value, row) {
  481. return row.tag === value;
  482. }
  483. }
  484. };
  485. </script>
  486. <style>
  487. .el-upload--picture-card {
  488. width: 100px !important;
  489. height: 100px !important;
  490. line-height: 100px !important;
  491. }
  492. .el-upload-list--picture-card .el-upload-list__item {
  493. width: 100px !important;
  494. height: 100px !important;
  495. line-height: 100px !important;
  496. }
  497. </style>
  498. <style lang="less" scoped>
  499. .name-wrapper{
  500. width: 240px;
  501. overflow: hidden;
  502. text-overflow: ellipsis;
  503. white-space: nowrap;
  504. }
  505. .chatting {
  506. text-align: center;
  507. }
  508. .serive {
  509. padding: 0 10px;
  510. text-align: right;
  511. .serive_text {
  512. width: 100%;
  513. margin-top: 20px;
  514. background: #F5F5F5;
  515. border: 1px solid #EEEEEE;
  516. padding: 20px;
  517. font-size: 14px;
  518. color: #666;
  519. word-wrap: break-word;
  520. }
  521. }
  522. .user {
  523. .user_text {
  524. width: 100%;
  525. margin-top: 20px;
  526. background: #F5F5F5;
  527. border: 1px solid #EEEEEE;
  528. padding: 20px;
  529. font-size: 14px;
  530. color: #666;
  531. word-wrap: break-word;
  532. // line-height: 1.8;
  533. }
  534. .img {
  535. margin-top: 20px;
  536. }
  537. }
  538. .netSendCol {
  539. cursor: not-allowed;
  540. }
  541. .content_box {
  542. .chat_user {
  543. border-top: 1px solid #D5E5FF;
  544. .block{
  545. // padding: 10px 0;
  546. text-align: center;
  547. border: 1px solid #eff2f6;
  548. display: inline-block;
  549. width: 20%;
  550. box-sizing: border-box;
  551. vertical-align: top;
  552. margin-left: 10px;
  553. }
  554. }
  555. }
  556. .user_box {
  557. height: 100vh;
  558. }
  559. .el-pagination .btn-next .el-icon {
  560. display: none;
  561. }
  562. .cell {
  563. text-align: center;
  564. }
  565. .el-pagination {
  566. text-align: center;
  567. font-size: 0;
  568. }
  569. .el-table::before {
  570. z-index: 0 !important;
  571. }
  572. .input-with-select {
  573. width: 100%;
  574. }
  575. .name_box {
  576. margin-left: 20px;
  577. font-size: 14px;
  578. font-weight: bold;
  579. color: rgba(102, 102, 102, 1);
  580. }
  581. .box {
  582. width: 100%;
  583. }
  584. .right_box {
  585. position: fixed;
  586. top: 33px;
  587. right: 0;
  588. width: 100%;
  589. /* height: 100vh;
  590. background: red; */
  591. /* //background: rgba(255, 255, 255, 0.315); */
  592. }
  593. .el-input-group__append {
  594. text-align: center;
  595. }
  596. .el-table td {
  597. padding: 8px 0;
  598. }
  599. .headers {
  600. display: flex;
  601. justify-content: flex-start;
  602. padding: 0 20px;
  603. height: 50px;
  604. line-height: 50px;
  605. }
  606. .user_box {
  607. padding: 20px;
  608. background: #F6F8FF;
  609. }
  610. .chuli {
  611. width: 70px;
  612. height: 30px;
  613. border-radius: 5px;
  614. color: #fff;
  615. background: #FF6600
  616. }
  617. .title {
  618. font-weight: bold;
  619. color: #333333;
  620. font-size: 14px;
  621. }
  622. li {
  623. margin: 10px 0;
  624. color: #999999;
  625. }
  626. ul {
  627. margin: 0;
  628. padding: 0;
  629. }
  630. #main {
  631. height: 65vh;
  632. }
  633. .icons {
  634. padding: 0 20px;
  635. height: 40px;
  636. line-height: 40px;
  637. }
  638. .send {
  639. margin: 0 auto;
  640. color: #fff;
  641. width: 60%;
  642. height: 40px;
  643. background: rgba(221, 221, 221, 1);
  644. opacity: 1;
  645. border-radius: 5px;
  646. }
  647. .send.sendCol {
  648. background: linear-gradient(90deg, rgba(22, 84, 209, 1) 0%, rgba(9, 52, 173, 1) 100%);
  649. }
  650. </style>