TheCurrentSession.vue 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822
  1. <template>
  2. <div class="row allAlignment">
  3. <leftNav/>
  4. <div>
  5. <hader/>
  6. <messageCenter></messageCenter>
  7. <div class="row">
  8. <!-- 聊天列表模块 -->
  9. <div class="sessionList">
  10. <el-collapse>
  11. <el-collapse-item>
  12. <template slot="title">
  13. <span>会话中 <span>({{sessionList.length }})</span></span>
  14. <!-- <span class="sessionList_span">排队人数(10)</span> -->
  15. </template>
  16. <div :class="{session_choose:dataIndex ==index && sessionType ==1}"
  17. class="user session_style" @click="chooseDialogue(1,index)"
  18. v-for="(item,index) in sessionList" :key="index">
  19. <div class="row allAlignment item-center">
  20. <span style="font-weight:bold;color:#666;font-size:14px;">{{item.name}}</span>
  21. <span style="color:#999;font-size:.12px;">{{item.intime}}</span>
  22. </div>
  23. <div class="row allAlignment item-center">
  24. <div style="width:90%;font-size:.12px;" class="ellipsis">
  25. <span v-html="item.text"></span>
  26. </div>
  27. <span v-if="item.num > 0" class="markNumber">{{item.num}}</span>
  28. </div>
  29. </div>
  30. </el-collapse-item>
  31. <el-collapse-item>
  32. <template slot="title">
  33. <span>已离线<span>({{offlineList.length }})</span></span>
  34. </template>
  35. <div :class="{session_choose:dataIndex == index && sessionType ==2}"
  36. class="user session_style" @click="chooseDialogue(2,index)"
  37. v-for="(item,index) in offlineList" :key="index">
  38. <div class="row allAlignment item-center">
  39. <span style="font-weight:bold;color:#999;font-size:14px;">{{item.name}}</span>
  40. <span style="color:#999;font-size:12px;">{{item.intime}}</span>
  41. </div>
  42. <div class="row allAlignment item-center">
  43. <div style="width:90%;color:#999;font-size:12px;" class="ellipsis">
  44. <span v-html="item.text"></span>
  45. </div>
  46. </div>
  47. </div>
  48. </el-collapse-item>
  49. <!-- <el-collapse-item>
  50. <template slot="title">
  51. <span>排队中<span>({{lineUp.length}})</span></span>
  52. </template>
  53. <div class="user" v-for="item in lineUp">
  54. <div class="row allAlignment item-center">
  55. <span style="font-weight:bold;color:#666;font-size:14px;">{{item}}</span>
  56. <span style="color:#999;font-size:12px;">{{item}}</span>
  57. </div>
  58. </div>
  59. </el-collapse-item> -->
  60. </el-collapse>
  61. </div>
  62. <!-- 聊天模块 -->
  63. <div class="chat">
  64. <div class="chatTop row item-center allAlignment" style="padding:0 10px;">
  65. <p class="ellipsis"
  66. style="width:40%;font-size:14px;font-weight:bold;color:#666;"
  67. >{{sessionName}}</p>
  68. <div class="row item-center rightAlignment"
  69. style="width:50%;height:100%;color:#999;font-size:12px;">
  70. <p class="row item-center" @click="getServiceList()">
  71. <!-- 转接 -->
  72. <el-popover placement="right" width="400" trigger="click">
  73. <el-table :data="transferList">
  74. <el-table-column width="150" property="groupname" label="组名"></el-table-column>
  75. <el-table-column width="100" property="kfname" label="姓名"></el-table-column>
  76. <el-table-column label="操作">
  77. <template slot-scope="scope">
  78. <el-button size="mini" @click="transfer(scope.$index, scope.row)">转入
  79. </el-button>
  80. </template>
  81. </el-table-column>
  82. </el-table>
  83. <el-button slot="reference"><i style="font-size:14px" class="el-icon-refresh"></i>
  84. 转接
  85. </el-button>
  86. </el-popover>
  87. </p>
  88. <p class="row item-center" style="margin-left:10px;">
  89. <el-button size="mini" type="text" @click="open">
  90. <i style="font-size:15px" class="el-icon-close"></i>结束服务
  91. </el-button>
  92. </p>
  93. </div>
  94. </div>
  95. <div class="history-info">
  96. <el-button type="text" size="small" :loading="historyLoading"
  97. @click="getHistoryInfo">{{historyProcess}}</el-button>
  98. </div>
  99. <div class="chat-box scroll" id='chat_box'>
  100. <div v-for="(item,index) in data" :key="index">
  101. <!-- 系统转接 -->
  102. <!-- <div class="row center" v-if="item.type == 'system'">
  103. <p style="font-size:12px;color:#bbb;">09.30.45 由问答机器人转接</p>
  104. </div> -->
  105. <!-- 用户消息 -->
  106. <div style="padding:0 10px;margin-top:20px;" v-if="item.type == 'user'">
  107. <div style="height:37px;font-size:.12px;color:#bbb;"
  108. class="row item-center"
  109. >{{item.time}}
  110. </div>
  111. <div class="row">
  112. <div class="user_box row center" v-if="item.content.img != ''">
  113. <el-image style="max-width:100%;"
  114. @click="handlePictureCardPreview(img_http+item.content.img)"
  115. :src="img_http + item.content.img" :fit="fit"></el-image>
  116. </div>
  117. <p v-else class="chatMsg user_box" v-html="item.content.text"></p>
  118. </div>
  119. </div>
  120. <!-- 客服消息 -->
  121. <div style="padding:0 10px;margin-top:20px;" class="rightAlignment"
  122. v-if="item.type == 'service'">
  123. <div style="height:37px;font-size:12px;color:#bbb;"
  124. class="row item-center rightAlignment">{{item.time}}
  125. </div>
  126. <div class="row item-center rightAlignment">
  127. <div class="message_box" v-if="item.content.img !=''">
  128. <!-- :fit="contain" style="background:#F5F5F5; border-radius: 10px 0 10px 10px;"-->
  129. <el-image style="max-width:100%;"
  130. @click="handlePictureCardPreview(img_http+item.content.img)"
  131. :src="img_http + item.content.img" :fit="fit"></el-image>
  132. </div>
  133. <p v-else class="chatMsg message_box" v-html="item.content.text"></p>
  134. </div>
  135. </div>
  136. <!-- 点击图片放大 -->
  137. <el-dialog :visible.sync="dialogVisible">
  138. <img width="100%" :src="dialogImageUrl" alt="">
  139. </el-dialog>
  140. </div>
  141. </div>
  142. <div class="key column allAlignment">
  143. <div class="frce row item-center allAlignment">
  144. <div class="row ">
  145. <!-- <img class="hover"
  146. :src="isFrce?require('@/assets/img/frcea.png'):require('@/assets/img/frce.png')"
  147. @click="frceClick" style="margin-right:16px;"/> -->
  148. <el-popover id="pop" placement="top-start" width="400" trigger="hover">
  149. <ul>
  150. <li class="emoticon" v-for="(item,index) in frceArr" :key="item.id">
  151. <img class="pointer" :src="require(`@/assets/img/${index}.gif`)"
  152. @click="frceCenterClick(item)" alt="">
  153. </li>
  154. </ul>
  155. <el-button class="expression" slot="reference"></el-button>
  156. </el-popover>
  157. <input type="file" id="file" style="display:none;" @change="uploadIMG"/>
  158. <label for="file" class="row item-center" style="height:100%">
  159. <img class="hover" src="@/assets/img/img.png"/>
  160. </label>
  161. </div>
  162. <div>
  163. <i :class="{disable : is_eva_btn}" @click="evaluation()"
  164. class="el-icon-postcard hover evaluation"></i>
  165. </div>
  166. </div>
  167. <textarea draggable="false" class="input scroll" id="input" v-model.trim="inputValue"
  168. @keyup.enter="listenEnter($event)" @keyup.ctrl.enter="lineFeed()"></textarea>
  169. <div class="row rightAlignment" style="width: 100%;">
  170. <div @click="sendMessage()" @keyup.enter="sendMessage" class="msgInputBtn row center">发送</div>
  171. </div>
  172. </div>
  173. <!-- 发送消息音频提示 -->
  174. <!-- <audio id="send" src="@/assets/audio/send.wav"></audio> -->
  175. </div>
  176. <!-- 快捷回复模块 -->
  177. <div class="FastReply">
  178. <div class="FastReplyHader row item-center">快捷回复</div>
  179. <div class="FastReplySwitch row item-center average">
  180. <p :class="FastReplySwitch=='one'?'active':''" class="hover"
  181. @click="FastReplySwitchClick('one')">公有库</p>
  182. <span style="width:1px;height:18px;background:#ccc;display: block;"></span>
  183. <p :class="FastReplySwitch=='tow'?'active':''"
  184. class="hover"
  185. @click="FastReplySwitchClick('tow')"
  186. >私有库</p>
  187. </div>
  188. <!-- <div class="serch row center">
  189. <div class="serchBox">
  190. <input placeholder="搜索快捷回复" v-model="serch" type="text" />
  191. <img src="@/assets/img/serch.png" />
  192. </div>
  193. </div> -->
  194. <!-- <div> -->
  195. <!-- <el-collapse>
  196. <el-collapse-item>
  197. <template slot="title" name="el-icon-caret-bottom">
  198. <span>常用语</span>
  199. </template> -->
  200. <div class="FastReplyBox">
  201. <!-- <ul class="FastReplyList"> -->
  202. <!-- <li @click="getLanguage(item.content)" class="row cursor_text" v-for="item in FastReply.sysWords" :key="item.id"> -->
  203. <div @click="getLanguage(item.content)" class="row cursor_text item-center"
  204. v-for="item in FastReply.sysWords" :key="item.id" v-if="FastReplySwitch == 'one'">
  205. <el-tooltip class="title_span" effect="light" placement="bottom-start">
  206. <div slot="content">{{item.content}}</div>
  207. <span class="title_span" style=" width: 100%">#{{item.title}}</span>
  208. </el-tooltip>
  209. <!-- <div class="ellipsis" style=" width: 70%">
  210. <span class="content_span">{{item.content}}</span>
  211. </div> -->
  212. </div>
  213. <!-- </li> -->
  214. <div @click="getLanguage(item.content)" class="row cursor_text item-center"
  215. v-for="item in FastReply.userWords" :key="item.id" v-if="FastReplySwitch == 'tow'">
  216. <el-tooltip class="title_span" effect="light" placement="bottom-start">
  217. <div slot="content">{{item.content}}</div>
  218. <span class="title_span" style=" width: 100%">#{{item.title}}</span>
  219. </el-tooltip>
  220. <!-- <div class="ellipsis" style=" width: 70%">
  221. <span class="content_span">{{item.content}}</span>
  222. </div> -->
  223. </div>
  224. <!-- <li class="row cursor_text" v-for="item in FastReply.userWords" :key="item.id">
  225. <div v-if="FastReplySwitch == 'tow'" class="row item-center">
  226. <p style="margin-right:10px;color:#666;font-size:14px;font-weight: bold;"
  227. >#{{item.title}}</p>
  228. <p class="ellipsis" style="width: 60%; color:#999;font-size:14px;">{{item.content}}</p>
  229. </div>
  230. </li> -->
  231. <!-- </ul> -->
  232. </div>
  233. <!-- </el-collapse-item>
  234. </el-collapse> -->
  235. <!-- </div> -->
  236. </div>
  237. <!-- 用户信息模块 -->
  238. <div class="userinfo">
  239. <div style="color:#666;font-weight:bold;font-size:14px;">访问信息</div>
  240. <div style="margin-top:10px;color:#999;font-size:14px;" class="userData wrap">
  241. <!-- <p>来源:{{session_user_info.website}}</p> -->
  242. <p @dblclick="get_ip_Info" class="get_ip" :data-clipboard-text="terminal_IP.ip">
  243. IP地址:{{terminal_IP.ip}}</p>
  244. <p>来源终端:{{terminal_IP.system}}</p>
  245. <p>来源地区:{{terminal_IP.source}}</p>
  246. </div>
  247. <div style="color:#666;font-weight:bold;font-size:14px; margin-top:30px;">用户信息</div>
  248. <div id="user_info_box" style="margin-top:10px;color:#999;font-size:14px;" class="userData wrap">
  249. <div class="user_info_box">
  250. <p @dblclick="get_name" class="user_text" :data-clipboard-text="session_user_info.account_name" style="background: #ECF4FF;"><span>账号:</span>{{session_user_info.account_name}}</p>
  251. </div>
  252. <div class="user_info_box">
  253. <span>标签:</span>
  254. <el-select style="width:70%;" v-model="value" @focus='focusFun' @change='labelChange'
  255. placeholder="请选择">
  256. <el-option
  257. v-for="item in options"
  258. :key="item.id"
  259. :label="item.name"
  260. :value="item.id">
  261. </el-option>
  262. </el-select>
  263. </div>
  264. <div class="user_info_box">
  265. <span>昵称:</span>
  266. <el-input style="width:70%;" v-model="session_user_info.nick_name"
  267. placeholder="请输入内容"></el-input>
  268. </div>
  269. <div class="user_info_box">
  270. <span>手机:</span>
  271. <el-input @blur='validation_user_info(1)' style="width:70%;"
  272. v-model="session_user_info.account_phone"
  273. placeholder="请输入内容"></el-input>
  274. </div>
  275. <div class="user_info_box">
  276. <span>邮箱:</span>
  277. <el-input @blur='validation_user_info(2)' style="width:70%;"
  278. v-model="session_user_info.account_email"
  279. placeholder="请输入内容"></el-input>
  280. </div>
  281. <div class="user_info_box">
  282. <span>地址:</span>
  283. <el-input style="width:70%;" v-model="session_user_info.address"
  284. placeholder="请输入内容"></el-input>
  285. </div>
  286. <div class="user_info_box">
  287. <span>备注:</span>
  288. <el-input style="width:70%;" v-model="session_user_info.remark"
  289. placeholder="请输入内容"></el-input>
  290. </div>
  291. </div>
  292. <div class=" row rightAlignment">
  293. <div class="userBtn row center" @click="bt_update()">保存</div>
  294. </div>
  295. </div>
  296. </div>
  297. <!-- 截图粘贴 -->
  298. <el-dialog
  299. :close-on-click-modal="true"
  300. :close-on-press-escape="true"
  301. title="是否发送图片"
  302. :visible.sync="dialogPaste"
  303. width="35%">
  304. <!-- :before-close="handleClose" -->
  305. <!-- <span>这是一段信息</span> -->
  306. <el-image
  307. :src="pasteUrl" :fit="fit"></el-image>
  308. <span slot="footer" class="dialog-footer">
  309. <el-button @click="dialogPaste = false">取 消</el-button>
  310. <el-button type="primary" @click="handleClose()">确 定</el-button>
  311. </span>
  312. </el-dialog>
  313. </div>
  314. </div>
  315. </template>
  316. <script>
  317. import "@/css/index.css";
  318. import Clipboard from 'clipboard';
  319. import {mapState, mapGetters} from 'vuex'; //先要引入
  320. import leftNav from "@/components/leftNav";
  321. import hader from "@/components/hader";
  322. import messageCenter from "@/components/messageCenter";
  323. import historicalRecord from "@/components/historicalRecord";
  324. export default {
  325. name: "TheCurrentSession",
  326. data() {
  327. return {
  328. /***********************************/
  329. inputValue: "", //输入框内容
  330. isFrce: false, //表情包开关
  331. frceArr: [], //表情包数组
  332. FastReply: "", //快捷回复
  333. FastReplySwitch: "one", //快捷回复开关
  334. user_info: '',//用户信息
  335. token: "",
  336. time: "",
  337. transferList: [],//转接列表
  338. lineUp: [],//排队列表
  339. conversationId: '',//会话工单
  340. session_user_info: {},//当前会话用户信息
  341. img_http: 'https://manage.281570.com',//图片路径域
  342. // img_http: 'http://192.168.2.187:8090',//图片路径域
  343. fit: 'scale-down',//图片渲染样式
  344. is_eva_btn: true,//
  345. trigger_condition: 0,//评价触发条件
  346. webTime: '',//客服会话时间
  347. session_marked: '',//客服当前会话标记
  348. sensitive: [],//客服敏感词数据
  349. userSensitiveWords: [],//用户敏感词
  350. sensitiveNumber: 0,//关键词次数
  351. isTrue: true,//编辑用户信息按钮开关
  352. options: [],
  353. label_id: '',
  354. value: '请选择',
  355. dialogPaste: false,
  356. dialogVisible: false, //图片放大
  357. dialogImageUrl: '', // 放大的图片
  358. dialogUrl: false,
  359. pasteUrl: '',//截屏图片
  360. userSwitching: true,//是否切换完成
  361. terminal_IP: {},//访客设备信息
  362. showHistoryList: false,
  363. historyList: [],
  364. historyTime:'',
  365. historyLoading: false, // 历史记录加载
  366. historyProcess: '更多历史记录', // 查看历史历史记录或者加载中
  367. historyPage: 1 // 当前的历史记录页
  368. }
  369. },
  370. methods: {
  371. /****************************/
  372. validation_user_info(type) {
  373. if (type == 1 && this.session_user_info.account_phone) {
  374. if (!/^1[34578]\d{9}$/.test(this.session_user_info.account_phone)) {
  375. this.session_user_info.account_phone = '';
  376. this.$message({
  377. message: '这不是一个手机号哦!...',
  378. type: 'warning'
  379. });
  380. }
  381. } else if (type == 2 && this.session_user_info.account_email) {
  382. if (!/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(this.session_user_info.account_email)) {
  383. this.session_user_info.account_email = ''
  384. this.$message({
  385. message: '这不是一个邮箱哦!...',
  386. type: 'warning'
  387. });
  388. }
  389. }
  390. },
  391. /***************图片放大*************** */
  392. handlePictureCardPreview(url) {
  393. this.dialogImageUrl = url;
  394. this.dialogVisible = true;
  395. },
  396. /************回车提交************/
  397. listenEnter(event) {
  398. if(event.keyCode === 13) {
  399. this.inputValue = this.inputValue.replace(/\s/g, '')
  400. // this.inputValue = this.inputValue.replace(/\n /g,'')
  401. this.sendMessage(); // 发送文本
  402. }
  403. },
  404. /************ctrl+center 换行***********/
  405. lineFeed() {
  406. this.inputValue = this.inputValue + '\n'
  407. },
  408. /********************发送获取标签数据指令*******************/
  409. focusFun() {
  410. // console.log('haha');
  411. this.$websocket.send(JSON.stringify({type: 'userlabeall'}));
  412. },
  413. /**************************获取选择标签ID****************/
  414. labelChange(e) {
  415. this.label_id = e;
  416. },
  417. /******************消息数据接收********************/
  418. chatMessage(redata) {
  419. //console.log(this.historyList,'historyList');
  420. //console.log(this.data,'data');
  421. //用户离线后会话窗口切换
  422. if (redata.message_type == "userClose") {
  423. // console.log(redata)
  424. return false
  425. }
  426. // //用户会话结束窗口切换
  427. if (redata.message_type == "delUser") {
  428. redata.data;
  429. // console.log(redata.data, this.session_user_info)
  430. if (redata.data.id == this.session_user_info.id) {
  431. this.session_user_info = {};
  432. this.value = '请选择';
  433. }
  434. return false
  435. }
  436. //获取标签数据信息
  437. if (redata.message_type == "userlabeall") {
  438. if (Object.values(redata.data).length > 0) {
  439. this.options = [];
  440. this.options = Object.values(redata.data);
  441. // this.value = this.options[0].name;
  442. }
  443. return false
  444. }
  445. //接收系统操作信息状态在线客服列表
  446. if (redata.message_type == "onlinekfs") {
  447. this.transferList = [];
  448. this.transferList = this.transferList.concat(redata.data);
  449. return false
  450. }
  451. //接收会话时间
  452. if (redata.message_type == "webTime") {
  453. let data = this.data;
  454. // console.log(data, '接收会话时间');
  455. data[data.length - 1].time = redata.data.webTime
  456. this.$store.dispatch("SET_CURRENT", data);
  457. if(this.historyList.length > 0){
  458. let historyTime = this.historyTime;
  459. this.$set(this.historyList[this.historyTime], 'time', redata.data.webTime);
  460. }
  461. return false
  462. }
  463. //客服手动转接用户成功
  464. if (redata.message_type == "trunconnect") {
  465. this.sessionList.splice(this.dataIndex, 1);
  466. this.$message({
  467. message: '转接用户成功...',
  468. type: 'success'
  469. });
  470. if (this.sessionList.length > 1) {
  471. this.$store.dispatch("SET_NUM", 0);
  472. // this.data = []
  473. } else {
  474. // this.data = [];
  475. this.$store.dispatch("SET_CURRENT", []);//当前会话数据
  476. this.$store.dispatch("SET_SESSION_NAME", '');
  477. }
  478. return false
  479. }
  480. if (redata.message_type == 'chatMessage') {
  481. this.automaticRolling();
  482. }
  483. // 转接历史信息
  484. if (redata.message_type == "connect") {
  485. if (redata.data.history.length > 0) {
  486. console.log(redata, '转接历史消息');
  487. this.showHistoryList = true;
  488. redata.data.history.forEach(res => {
  489. let content = JSON.parse(res.content)
  490. // res.content = content;
  491. if (content.text) {
  492. content.text = this.$public.turnFace(content.text,this.$frce)
  493. }
  494. res.content = content
  495. this.historyList.push(res)
  496. })
  497. this.automaticRolling();
  498. }
  499. }
  500. },
  501. /*********************图片发送*********************/
  502. uploadIMG(e) {
  503. //console.log(e);
  504. let self = this;
  505. let files = e.target.files || e.dataTransfer.files;
  506. if (!files.length) return;
  507. const isJPG = files.type == 'image/jpeg' || 'image/jpg' || 'image/png' || 'image/svg';
  508. const isLt2M = file.size / 1024 / 1024 < 2;
  509. if (!isJPG) {
  510. this.$message.error('上传只能是图片格式!');
  511. return false;
  512. }
  513. if (!isLt2M) {
  514. this.$message.error('上传图片大小不能超过 2MB!');
  515. return false;
  516. }
  517. let picavalue = files[0];
  518. //console.log(picavalue);
  519. if (picavalue.size / 1000 > 20000) {
  520. this.$message({
  521. message: "图片过大不支持上传",
  522. type: "warning"
  523. });
  524. } else {
  525. this.$public.imgPreview(picavalue, function (imgSrc, formData) {
  526. self.upImg(formData)
  527. e.target.value = "";
  528. });
  529. }
  530. },
  531. /**********************图片上传***********************/
  532. upImg(formData) {
  533. let self = this;
  534. // 数据结构请求
  535. self.$http.uploadPost('/index/upload/uploadImg', formData).then(res => {
  536. //console.log(res.data.data.src)
  537. if (res.data.code == 1) {
  538. let isFirst = true;
  539. //判断客服是否发送的第一句话
  540. if (self.data.length > 0) {
  541. for (let i = 0; i < self.data.length; i++) {
  542. if (self.data[i].type == 'service') {
  543. isFirst = false;
  544. break;
  545. }
  546. }
  547. }
  548. let obj = {
  549. text: '',
  550. img: res.data.data.src,
  551. type: false,
  552. };
  553. let chatList = self.sessionList[self.dataIndex];
  554. // console.log(self.webTime);
  555. //本地存储
  556. chatList.data.push({type: 'service', content: obj, time: self.webTime});
  557. // self.data = [];
  558. // self.data = chatList.data;
  559. // self.$store.dispatch("SET_CURRENT", []);
  560. self.$store.dispatch("SET_CURRENT", chatList.data);
  561. let type = 'chatMessage';
  562. let data = {
  563. from_name: self.user_info.user_name,//发送者
  564. from_avatar: self.user_info.avatar,//发送者头像
  565. from_id: "KF" + self.user_info.id,//发送者id
  566. content: JSON.stringify(obj),
  567. to_id: self.sessionList[self.dataIndex].id,
  568. to_name: self.sessionList[self.dataIndex].name,
  569. conversationId: self.sessionList[self.dataIndex].conversationId,
  570. isFirst: isFirst,//是否是第一句话
  571. sensitiveNumber: 0,//敏感词次数
  572. }
  573. self.websocketsend(JSON.stringify({type, data}))
  574. }
  575. })
  576. },
  577. /*****************转接会话用户确认******************/
  578. transfer(e) {
  579. if (this.sessionList.length > 0) {
  580. this.$confirm('此操作将当前用户转出, 是否继续?', '温馨提示!', {
  581. confirmButtonText: '确定',
  582. cancelButtonText: '取消',
  583. type: 'warning'
  584. }).then(() => {
  585. let type = "changeOtherhKeFu";
  586. let data = {
  587. conversationId: this.sessionType == 1 ? this.sessionList[this.dataIndex].conversationId : this.offlineList[this.dataIndex].conversationId,
  588. togroup: this.transferList[e].groupid,
  589. fromgroup: this.user_info.group_id,
  590. toukfuid: this.transferList[e].kfuid,
  591. fromkfuid: "KF" + this.user_info.id,
  592. uid: this.sessionType == 1 ? this.sessionList[this.dataIndex].id : this.offlineList[this.dataIndex].id,
  593. word: '',
  594. }
  595. //console.log({type,data});
  596. this.websocketsend(JSON.stringify({type, data}))
  597. }).catch(() => {
  598. })
  599. } else {
  600. this.$message({
  601. message: '亲!您没有和用户会话怎么能转接呢。',
  602. type: 'warning'
  603. });
  604. }
  605. },
  606. /******************获取客服人员列表*****************/
  607. getServiceList() {
  608. //console.log(12313);
  609. this.websocketsend(JSON.stringify({"type": "getkfonlines"}))
  610. },
  611. getPlatformCN(name){
  612. let platforms={'android':'安卓','ios':'苹果','pc':'电脑'};
  613. return platforms[name];
  614. },
  615. /*****************切换用户会话对象******************/
  616. chooseDialogue(type,index,system) {
  617. if(!system){
  618. this.inputValue = '' // 清除会话内容
  619. }
  620. console.log(type, index);
  621. if (this.userSwitching) {
  622. let data = [];
  623. let order_id = '';
  624. this.$store.dispatch("SET_TYPE", type);
  625. this.$store.dispatch("SET_NUM", index);
  626. if (type == 1) {
  627. data = this.sessionList[index].data;
  628. order_id = this.sessionList[index].id;
  629. this.$set(this.sessionList[index], 'num', 0);
  630. this.terminal_IP = {
  631. system: this.getPlatformCN(this.sessionList[index].system) + '-' + this.sessionList[index].browse,
  632. ip: this.sessionList[index].ip,
  633. source:this.sessionList[index].ipinfo
  634. }
  635. } else if (type == 2) {
  636. data = this.offlineList[index].data;
  637. order_id = this.offlineList[index].id;
  638. this.terminal_IP = {
  639. system: this.getPlatformCN(this.offlineList[index].system) + '-' + this.offlineList[index].browse,
  640. ip: this.offlineList[index].ip,
  641. source:this.offlineList[index].ipinfo
  642. }
  643. }
  644. this.$store.dispatch("SET_CURRENT", data);//当前会话数据
  645. this.userSwitching = false;
  646. this.get_user(order_id,type,index);
  647. } else {
  648. // this.$message({
  649. // message: '警告!,操作太频繁',
  650. // type: 'warning'
  651. // });
  652. }
  653. },
  654. /***************关闭当前和用户聊天对话***************/
  655. open() {
  656. let _this = this;
  657. // console.log(this.sessionList)
  658. if (this.sessionType == 1) {
  659. if (this.sessionList.length < 1) return
  660. } else {
  661. if (this.offlineList.length < 1) return
  662. }
  663. this.$confirm('此操作将关闭和当前用户通话, 是否继续?', '温馨提示!', {
  664. confirmButtonText: '确定',
  665. cancelButtonText: '取消',
  666. type: 'warning'
  667. }).then(() => {
  668. let to_id = this.sessionType == 1 ? this.sessionList[this.dataIndex].id : this.offlineList[this.dataIndex].id;
  669. let conversationId = this.sessionType == 1 ? this.sessionList[this.dataIndex].conversationId : this.offlineList[this.dataIndex].conversationId;
  670. // console.log(conversationId,'ssss');
  671. let data = {
  672. "type": "kfCloseUser",
  673. data: {
  674. to_id: '',
  675. kf_id: "KF" + _this.user_info.id,
  676. group_id: _this.user_info.group_id,
  677. conversationId: conversationId,
  678. type: 3,
  679. }
  680. }
  681. if (this.sessionType == 1) {
  682. let sessionList = this.sessionList;
  683. sessionList.splice(this.dataIndex, 1);
  684. if (sessionList.length > 0) {
  685. this.$store.dispatch("SET_CURRENT", sessionList[0]);//当前会话数据
  686. this.$store.dispatch("SET_SESSION_NAME", sessionList[0].name);
  687. } else {
  688. this.$store.dispatch("SET_CURRENT", []);//当前会话数据
  689. this.$store.dispatch("SET_SESSION_NAME", '');
  690. }
  691. } else {
  692. let offlineList = this.offlineList;
  693. offlineList.splice(this.dataIndex, 1);
  694. this.$store.dispatch("SET_CURRENT", []);//当前会话数据
  695. this.$store.dispatch("SET_SESSION_NAME", '');
  696. }
  697. this.websocketsend(JSON.stringify(data))
  698. }).catch(() => {
  699. this.$message({
  700. type: 'info',
  701. message: '已取消删除'
  702. });
  703. });
  704. },
  705. /*****************数据发送方法调用******************/
  706. websocketsend(Data) {
  707. this.$websocket.send(Data);
  708. this.automaticRolling();
  709. },
  710. // 消息发送声音提示
  711. sendAudio() {
  712. let send = new Audio()
  713. send.src = "../../static/audio/send.wav"
  714. send.play()
  715. },
  716. //判断是否选中访客
  717. visitor_info(){
  718. if(this.sessionType == 1 && this.sessionList.length <= 0 ){
  719. return '-1';
  720. }else if(this.sessionType == 2 && this.offlineList <= 0 ){
  721. return ' -1';
  722. }
  723. //this.sessionList.length >0 && this.sessionType == 1
  724. },
  725. /*********************发送消息*********************/
  726. sendMessage() {
  727. if (!this.inputValue ) return;
  728. if (this.sessionType == 2) {
  729. this.$message({
  730. message: '只能给在线用户发送消息哦...',
  731. type: 'warning'
  732. });
  733. return false;
  734. }else if(this.sessionType == 1 && this.sessionList.length <= 0){
  735. this.$message({
  736. message: '只能给在线用户发送消息哦...',
  737. type: 'warning'
  738. });
  739. return false;
  740. }
  741. // if(this.offlineList.length <= 0 ) return
  742. let isFirst = true, sensitiveNumber = 0;
  743. this.isFrce = false;
  744. //判断客服是否发送的第一句话
  745. if (this.data.length > 0) {
  746. for (let i = 0; i < this.data.length; i++) {
  747. if (this.data[i].type == 'service') {
  748. isFirst = false;
  749. break;
  750. }
  751. }
  752. }
  753. this.historyTime = this.historyList.length - 1;
  754. //检测发送信息是否含有敏感词
  755. let sensitive_data = this.$public.shieldingKeyword(this.$public.turnFace(this.inputValue, this.$frce), this.sensitive);
  756. //组合发送数据
  757. let data = {
  758. from_name: this.user_info.user_name,//发送者
  759. from_avatar: this.user_info.avatar,//发送者头像
  760. from_id: "KF" + this.user_info.id,//发送者id
  761. content: JSON.stringify({
  762. text: this.inputValue,
  763. img: '',
  764. }),
  765. to_id: this.sessionList[this.dataIndex].id,
  766. to_name: this.sessionList[this.dataIndex].name,
  767. conversationId: this.sessionList[this.dataIndex].conversationId,
  768. isFirst: isFirst,//是否是第一句话
  769. sensitiveNumber: this.sensitiveNumber,//敏感词次数
  770. }
  771. let chatList = this.sessionList[this.dataIndex];
  772. //有敏感词提示并且禁止发送
  773. if (sensitive_data.num == 0) {
  774. // 本地储存
  775. chatList.data.push({
  776. type: 'service', content: {
  777. text: this.$public.turnFace(this.inputValue, this.$frce),
  778. img: '',
  779. },
  780. // time: this.time[1]
  781. });
  782. //this.data = [];
  783. //标记当前会话位置
  784. this.session_marked = chatList.data.length - 1;
  785. //this.data = chatList.data;
  786. this.$store.dispatch("SET_CURRENT", chatList.data);//当前会话数据
  787. this.websocketsend(JSON.stringify({type: 'chatMessage', data}))
  788. this.sendAudio();
  789. this.inputValue = '';
  790. this.sensitiveNumber = 0;
  791. } else {
  792. this.$message({
  793. message: '敏感词' + sensitive_data.text,
  794. type: 'warning'
  795. });
  796. //计算关键词次数
  797. this.sensitiveNumber = this.sensitiveNumber + sensitive_data.num;
  798. }
  799. this.historyProcess = '更多历史消息' // 发送信息成功后改变说明
  800. },
  801. /******************开启或关闭表情包******************/
  802. frceClick() {
  803. this.isFrce = !this.isFrce;
  804. },
  805. /*******************发送评价指令*******************/
  806. evaluation() {
  807. if (!this.is_eva_btn && this.sessionType == 1) {
  808. this.$message({
  809. message: '评价指令已发送',
  810. type: 'success'
  811. });
  812. let type = 'getEvaluate';
  813. let data = {
  814. conversationId: this.sessionList[this.dataIndex].conversationId,
  815. to_id: this.sessionList[this.dataIndex].id,
  816. }
  817. this.sessionList[this.dataIndex].isEva = 10;
  818. this.$store.dispatch("SET_SESSION", this.sessionList);
  819. this.websocketsend(JSON.stringify({type, data}));
  820. this.is_eva_btn = true;
  821. } else if (this.sessionType == 2) {
  822. this.$message.error('用户已离线指令无法发送');
  823. } else {
  824. this.$message.error('评价指令无法发送');
  825. }
  826. },
  827. /******************查询快捷数据信息*****************/
  828. quickReplyInfo() {
  829. let obj = {
  830. headers: {
  831. apiToken: this.$md5("userwords" + "customer-service" + "index" + "service"),
  832. userToken: this.token
  833. }
  834. };
  835. this.$http.get(this.$ports.FastReply.userWords, obj).then(res => {
  836. if (res.data.code == 1) {
  837. this.FastReply = res.data.data;
  838. }
  839. });
  840. },
  841. /******************获取快捷语文字******************/
  842. getLanguage(e) {
  843. // console.log(e, "公有库");
  844. this.inputValue = this.inputValue + e;
  845. },
  846. /*****************表情包输入框赋值******************/
  847. frceCenterClick(text) {
  848. this.inputValue = this.inputValue + "#" + text + "/";
  849. //console.log(this.inputValue);
  850. },
  851. /******************* 快捷语库开关 ******************/
  852. FastReplySwitchClick(num) {
  853. this.FastReplySwitch = num;
  854. },
  855. /*****************获取当前聊天用户信息****************/
  856. get_user(id,type,index) {
  857. // console.log(id,type,index)
  858. let obj = {
  859. account_id: id
  860. };
  861. let headers ={ headers: {
  862. "apiToken": this.$md5('accountInfo' + "customer-service" + 'service' + 'service'),
  863. 'userToken': this.token
  864. },}
  865. this.$http.post(this.$ports.userInfo.accountInfo,obj,headers).then(res => {
  866. if (res.data.code == 1) {
  867. this.session_user_info = res.data.data;
  868. this.value = res.data.data.label
  869. if(this.session_user_info.nick_name){
  870. this.$store.dispatch("SET_SESSION_NAME", this.session_user_info.nick_name);
  871. }
  872. if(type == 1){
  873. if(this.session_user_info.nick_name){
  874. if(this.sessionList[index]){
  875. this.sessionList[index].name = this.session_user_info.nick_name;
  876. }else{
  877. }
  878. }
  879. this.$store.dispatch("SET_SESSION",this.sessionList);
  880. this.$store.dispatch("SET_SESSION_NAME",this.sessionList[index].name);
  881. }else if(type == 2){
  882. if(this.session_user_info.nick_name){
  883. this.offlineList[index].name = this.session_user_info.nick_name;
  884. }
  885. this.$store.dispatch("SET_SESSION_NAME",this.offlineList[index].name);
  886. //this.$store.dispatch("SET_SESSION", this.offlineList);
  887. }
  888. }
  889. this.userSwitching = true;
  890. })
  891. },
  892. /********************获取配置信息********************/
  893. get_config_info() {
  894. let obj = {
  895. headers: {
  896. apiToken: this.$md5("minround" + "customer-service" + "evaluate" + "index"),
  897. userToken: this.token
  898. }
  899. };
  900. this.$http.get( this.$ports.minRound,obj).then(res => {
  901. if (res.data.code == 1) {
  902. this.trigger_condition = res.data.data.systemconfig_data;
  903. }
  904. });
  905. },
  906. /***********发送消息或接收消息后自动滚动高度*************/
  907. automaticRolling() {
  908. this.$nextTick(() => {
  909. let msg = document.getElementById('chat_box') // 获取对象
  910. msg.scrollTop = msg.scrollHeight // 滚动高度
  911. })
  912. },
  913. /*****************************/
  914. automaticScrollTop(){
  915. this.$nextTick(() => {
  916. let msg = document.getElementById('chat_box') // 获取对象
  917. console.log(msg.scrollHeight);
  918. msg.scrollTop = '0px'
  919. })
  920. },
  921. /**************获取敏感词*****************/
  922. getSensitive() {
  923. let obj = {
  924. headers: {
  925. "apiToken": this.$md5('sensitivewords' + "customer-service" + 'index' + 'index'),
  926. 'userToken': this.token
  927. }
  928. };
  929. this.$http.post(this.$ports.sensitiveWords, '', obj).then(res => {
  930. if (res.data.code == 1) {
  931. res.data.data.serverSensitive.forEach(res => {
  932. this.sensitive.push(res.sensitivewords_word)
  933. })
  934. res.data.data.userSensitive.forEach(res => {
  935. this.userSensitiveWords.push(res.sensitivewords_word)
  936. })
  937. }
  938. })
  939. },
  940. /********************获取vuex数据***********************/
  941. get_vuex_info() {
  942. let getters = this.$store.getters;
  943. if(typeof getters.get_user_info != 'string' ){
  944. this.user_info = getters.get_user_info;//用户消息
  945. }else{
  946. // console.log('vule',JSON.parse(getters.get_user_info));
  947. this.user_info = JSON.parse(getters.get_user_info);
  948. }
  949. this.token = this.user_info.token;//token
  950. this.time = JSON.parse(sessionStorage.getItem("time"));
  951. },
  952. /**********************保存编辑用户信息**********************/
  953. bt_update() {
  954. if (!this.isTrue) return false;
  955. this.isTrue = false;
  956. let obj = {
  957. account_id: this.session_user_info.id,
  958. nick_name: this.session_user_info.nick_name,
  959. account_email: this.session_user_info.account_email,
  960. phone: this.session_user_info.account_phone,
  961. address: this.session_user_info.address,
  962. remark: this.session_user_info.remark,
  963. label_id: this.label_id
  964. };
  965. let headers={
  966. headers: {
  967. "apiToken": this.$md5('update' + "customer-service" + 'service' + 'service'),
  968. 'userToken': this.token
  969. },
  970. }
  971. this.$http.post(this.$ports.userInfo.update, obj,headers).then(res => {
  972. if (res.data.code == 1) {
  973. this.websocketsend(JSON.stringify({"type":"updateusercache","data":{"userid":this.session_user_info.id}}))
  974. this.$message({
  975. showClose: true,
  976. message: `恭喜你,${res.data.msg}`,
  977. type: 'success'
  978. });
  979. }
  980. this.isTrue = true;
  981. })
  982. },
  983. /******************qq截图粘贴---获取剪切板数据*****************/
  984. getClipboardData(e) {
  985. // 添加到事件对象中的访问系统剪贴板的接口
  986. let clipboardData = e.clipboardData,
  987. i = 0,
  988. items, item, types;
  989. if (clipboardData) {
  990. items = clipboardData.items;
  991. if (!items) {
  992. return;
  993. }
  994. item = items[0];
  995. // 保存在剪贴板中的数据类型
  996. types = clipboardData.types || [];
  997. for (let i=0; i < types.length; i++) {
  998. if (types[i] === 'Files') {
  999. item = items[i];
  1000. break;
  1001. }
  1002. }
  1003. // 判断是否为图片数据
  1004. if (item && item.kind === 'file' && item.type.match(/^image\//i)) {
  1005. this.imgReader(item);
  1006. }
  1007. }
  1008. },
  1009. /**********qq截图粘贴---获取剪切板图片信息进行转换blob***********/
  1010. imgReader(item) {
  1011. let _this = this;
  1012. var blob = item.getAsFile(), reader = new FileReader();
  1013. // 读取文件后将其显示在网页中
  1014. reader.onload = function (e) {
  1015. var img = new Image();
  1016. img.src = e.target.result;
  1017. _this.dialogPaste = true;
  1018. _this.pasteUrl = e.target.result;
  1019. // console.log(img.src)
  1020. //document.body.appendChild( img );
  1021. };
  1022. // 读取文件
  1023. reader.readAsDataURL(blob);
  1024. },
  1025. /*******************qq截图粘贴---监听时间捆绑*****************/
  1026. paste() {
  1027. document.getElementById('input').addEventListener('paste', this.getClipboardData);
  1028. },
  1029. /**********************qq截图粘贴---发送截图*****************/
  1030. handleClose(done) {
  1031. this.dialogPaste = false;
  1032. let blob = this.$public.dataURItoBlob(this.pasteUrl)
  1033. let self = this;
  1034. var formData = new FormData();
  1035. formData.append("file", blob);
  1036. self.upImg(formData);
  1037. },
  1038. /****************双击获取ip*******************/
  1039. get_ip_Info() {
  1040. var clipboard = new Clipboard(".get_ip")
  1041. clipboard.on('success', e => {
  1042. // console.log('复制成功')
  1043. this.$message({
  1044. message: '复制成功',
  1045. type: 'success'
  1046. });
  1047. // 释放内存
  1048. clipboard.destroy()
  1049. })
  1050. clipboard.on('error', e => {
  1051. // 不支持复制
  1052. this.$message({
  1053. message: '该浏览器不支持自动复制',
  1054. type: 'warning'
  1055. });
  1056. // 释放内存
  1057. clipboard.destroy()
  1058. })
  1059. },
  1060. get_name() {
  1061. var clipboard = new Clipboard(".user_text")
  1062. clipboard.on('success', e => {
  1063. // console.log('复制成功')
  1064. this.$message({
  1065. message: '复制成功',
  1066. type: 'success'
  1067. });
  1068. // 释放内存
  1069. clipboard.destroy()
  1070. })
  1071. clipboard.on('error', e => {
  1072. // 不支持复制
  1073. this.$message({
  1074. message: '该浏览器不支持自动复制',
  1075. type: 'warning'
  1076. });
  1077. // 释放内存
  1078. clipboard.destroy()
  1079. })
  1080. },
  1081. /****************访问信息和评价状态***************/
  1082. accessTerminal(data) {
  1083. if (this.sessionType == 1) {
  1084. // console.log('dataIndex', this.dataIndex)
  1085. let List = this.sessionList[this.dataIndex];
  1086. // console.log('list', List)
  1087. if (data == 'eva') {
  1088. if (!List) return false
  1089. // console.log(List,'对话信息');
  1090. if (List.isEva == 10) {
  1091. this.is_eva_btn = true;
  1092. } else if (List.isEva != 10) {
  1093. if (this.data.length > this.trigger_condition) {
  1094. List.isEva = 100;
  1095. this.is_eva_btn = false;
  1096. } else {
  1097. this.is_eva_btn = true;
  1098. }
  1099. }
  1100. this.sessionList[this.dataIndex] = List
  1101. this.$store.dispatch("SET_SESSION", this.sessionList)
  1102. } else {
  1103. if (List) {
  1104. this.terminal_IP = {
  1105. system: this.getPlatformCN(List.system) + '-' + List.browse,
  1106. ip: List.ip,
  1107. source:List.ipinfo
  1108. }
  1109. if(this.sessionList.length == 1 && this.dataIndex ==0){
  1110. this.get_user(List.id,1,this.dataIndex);
  1111. }
  1112. } else {
  1113. this.terminal_IP = {}
  1114. }
  1115. }
  1116. } else if (this.sessionType == 2) {
  1117. let List = this.offlineList[this.dataIndex];
  1118. if (List) {
  1119. this.terminal_IP = {
  1120. system: this.getPlatformCN(List.system) + '-' + List.browse,
  1121. ip: List.ip,
  1122. source:List.ipinfo
  1123. }
  1124. } else {
  1125. this.terminal_IP = {}
  1126. }
  1127. // }
  1128. }
  1129. },
  1130. /****************** 获取历史数据 *******************/
  1131. getHistoryInfo() { //
  1132. let visitors_id = '';
  1133. let conversationId = '';
  1134. if(this.sessionType == 1){
  1135. visitors_id = this.sessionList[this.dataIndex] ? this.sessionList[this.dataIndex].id: '';
  1136. conversationId =this.sessionList[this.dataIndex] ? this.sessionList[this.dataIndex].conversationId : '';
  1137. }else if(this.sessionType == 2){
  1138. visitors_id = this.offlineList[this.dataIndex] ? this.offlineList[this.dataIndex].id :'';
  1139. conversationId = this.offlineList[this.dataIndex] ? this.offlineList[this.dataIndex].conversationId : '';
  1140. }
  1141. if(visitors_id == ''){
  1142. this.$message({
  1143. message:'没有对应的访客',
  1144. type: 'warning'
  1145. });
  1146. return false;
  1147. }
  1148. let obj = {
  1149. headers: {
  1150. apiToken: this.$md5("userhistory" + "customer-service" + "history" + "service"),
  1151. // 'apiToken': this.$md5("historylist" + "customer-service" + "history" + "service"),
  1152. userToken: this.token
  1153. },
  1154. params: {
  1155. account_user_id: visitors_id,
  1156. account_id: 'KF' + this.user_info.id,
  1157. conversationId,
  1158. currentPage: this.historyPage,
  1159. pageSize: 10
  1160. }
  1161. };
  1162. this.historyLoading = true
  1163. this.historyProcess = '加载中'
  1164. this.$http.get(this.$ports.history.userHistory,obj).then(res => {
  1165. if(res.data.code == 1) {
  1166. if(!res.data.data.total ) { // 历史记录总数
  1167. this.historyProcess = '没有更多历史记录'
  1168. this.historyLoading = false
  1169. } else {
  1170. // 遍历封装数据
  1171. if(this.historyPage > res.data.data.countPage) {
  1172. this.historyProcess = '没有更多历史记录'
  1173. this.historyLoading = false
  1174. } else {
  1175. let list = res.data.data.list
  1176. if(list) {
  1177. for(let item of list) {
  1178. let content = JSON.parse(item.content)
  1179. if (content.text) {
  1180. content.text = this.$public.turnFace(content.text,this.$frce)
  1181. }
  1182. let historyItem = {
  1183. type: item.from_id.substr(0, 2) === 'KF' ? 'service' : 'user',
  1184. time: this.$public.customFormatDateTime(item.time_line),
  1185. content: content
  1186. }
  1187. this.data.unshift(historyItem);
  1188. this.automaticScrollTop()
  1189. }
  1190. this.historyPage ++ ;
  1191. this.historyProcess = '更多历史记录'
  1192. this.historyLoading = false;
  1193. } else {
  1194. this.historyProcess = '没有更多历史记录'
  1195. this.historyLoading = false
  1196. }
  1197. }
  1198. }
  1199. }
  1200. }).catch(err => {
  1201. this.$message.error(err.message)
  1202. this.historyLoading = false;
  1203. this.historyProcess = '更多历史记录'
  1204. })
  1205. }
  1206. },
  1207. created() {
  1208. this.get_vuex_info();
  1209. },
  1210. /**
  1211. * 挂载前执行
  1212. */
  1213. mounted() {
  1214. //获取vuex里面数据
  1215. this.get_vuex_info();
  1216. let _this = this;
  1217. this.get_config_info();
  1218. //获取客服快捷语
  1219. this.quickReplyInfo();
  1220. //获取敏感词
  1221. this.getSensitive();
  1222. //获取
  1223. this.frceArr = this.$frce;
  1224. //调用截图粘贴捆绑方法
  1225. this.paste();
  1226. //
  1227. this.accessTerminal();
  1228. //
  1229. if (this.sessionList.length > 0) {
  1230. if (this.sessionList[this.dataIndex].isEva == 100 && this.sessionList[this.dataIndex]) {
  1231. this.is_eva_btn = false;
  1232. }
  1233. }
  1234. },
  1235. beforeDestroy() {
  1236. document.getElementById('input').removeEventListener('paste', this.getClipboardData)
  1237. },
  1238. /**
  1239. * 事件监听
  1240. */
  1241. watch: {
  1242. get_session_message(e) {
  1243. this.chatMessage(e)
  1244. },
  1245. // sessionList(e) {
  1246. // this.accessTerminal(e)
  1247. // },
  1248. sessionList: {
  1249. handler(val) {
  1250. // console.log(val,'事件监听sessionList');
  1251. this.accessTerminal(val)
  1252. },
  1253. deep: true
  1254. },
  1255. offlineList(e) {
  1256. // console.log(e,'事件监听offlineList')
  1257. this.accessTerminal(e)
  1258. },
  1259. /*****************评价按钮显示隐藏处理*****************/
  1260. get_is_eva_btn(data) {
  1261. this.accessTerminal('eva')
  1262. }
  1263. },
  1264. /**
  1265. * 计算属性
  1266. */
  1267. computed: {
  1268. ...mapGetters({
  1269. data: 'get_current',
  1270. sessionName: 'get_session_name',
  1271. sessionList: 'get_session',
  1272. offlineList: 'get_offline',
  1273. dataIndex: 'get_num',
  1274. sessionType: 'get_type',
  1275. get_user_info: 'get_session_user', // 会话人详细信息
  1276. }),
  1277. get_session_message() {
  1278. return this.$store.getters.get_session_message;
  1279. },
  1280. /****************判断是否可以点击评价*****************/
  1281. get_is_eva_btn() {
  1282. return this.data;
  1283. }
  1284. },
  1285. components: {
  1286. leftNav,
  1287. hader,
  1288. messageCenter,
  1289. historicalRecord
  1290. }
  1291. };
  1292. </script>
  1293. <style>
  1294. .el-icon-arrow-right:before {
  1295. content: "\E791";
  1296. color: #ccc;
  1297. }
  1298. .emoticon {
  1299. width: 30px;
  1300. height: 30px;
  1301. display: inline-block;
  1302. }
  1303. #pop .expression {
  1304. display: inline-block;
  1305. width: 20px;
  1306. height: 20px;
  1307. background: url("./../assets/img/frce.png") no-repeat;
  1308. background-size: 100% 100%;
  1309. cursor: pointer;
  1310. margin-right: 10px;
  1311. }
  1312. #pop .expression:hover {
  1313. background: url("./../assets/img/frcea.png") no-repeat;
  1314. background-size: 100% 100%;
  1315. }
  1316. .session_choose {
  1317. background: #F6F8FF;
  1318. }
  1319. .session_style:hover {
  1320. /* background:#F6F8FF; */
  1321. background: #ECF4FF;
  1322. cursor: pointer;
  1323. }
  1324. .sessionList {
  1325. width: 16vw;
  1326. background: #fff;
  1327. }
  1328. .markNumber {
  1329. display: inline-block;
  1330. width: 20px;
  1331. height: 20px;
  1332. border-radius: 50%;
  1333. background: #f60;
  1334. font-size: 12px;
  1335. color: #fff;
  1336. text-align: center;
  1337. line-height: 20px;
  1338. }
  1339. .el-collapse-item__header {
  1340. position: relative;
  1341. font-size: 14px;
  1342. font-weight: bold;
  1343. color: #666;
  1344. font-family: PingFang SC;
  1345. padding-left: 32px;
  1346. height: 49px;
  1347. justify-content: space-between;
  1348. padding-right: 10px;
  1349. }
  1350. .el-collapse-item__header.is-active {
  1351. border-bottom: 1px solid #d5e5ff;
  1352. }
  1353. .el-collapse-item__header {
  1354. border-bottom: 1px solid #d5e5ff;
  1355. }
  1356. .el-icon-arrow-right {
  1357. position: absolute;
  1358. left: 10px;
  1359. top: auto;
  1360. }
  1361. .sessionList_span {
  1362. color: #999;
  1363. }
  1364. .user {
  1365. padding: 10px;
  1366. }
  1367. .evaluation {
  1368. font-size: 24px;
  1369. color: #969696;
  1370. }
  1371. .el-collapse-item__content {
  1372. padding-bottom: 0;
  1373. }
  1374. .chat {
  1375. width: 40vw;
  1376. height: 93vh;
  1377. border: 1px solid #d5e5ff;
  1378. border-top: none;
  1379. background: #fff;
  1380. }
  1381. .user_text {
  1382. border: 1px solid #ECF4FF;
  1383. color: #999;
  1384. line-height: 30px;
  1385. width: 100%;
  1386. }
  1387. .user_text:focus {
  1388. outline: none;
  1389. }
  1390. .chatTop {
  1391. height: 50px;
  1392. border-bottom: 1px solid #d5e5ff;
  1393. }
  1394. .chat-box {
  1395. height: 56vh;
  1396. padding-bottom: 10px;
  1397. border-bottom: 1px solid #d5e5ff;
  1398. overflow-x: hidden;
  1399. overflow-y: auto;
  1400. }
  1401. .chatMsg {
  1402. display: inline-block;
  1403. padding: 10px;
  1404. font-size: 14px;
  1405. max-width: 85%;
  1406. word-wrap: break-word;
  1407. }
  1408. p {
  1409. margin-block-start: 0em;
  1410. margin-block-end: 0em;
  1411. margin-inline-start: 0px;
  1412. margin-inline-end: 0px;
  1413. }
  1414. .frce {
  1415. height: 0.38rem;
  1416. width: 100%;
  1417. padding: 16px 10px;
  1418. }
  1419. .input {
  1420. height: 100px;
  1421. background: #fff;
  1422. resize: none;
  1423. font-size: 14px;
  1424. margin: 0 10px;
  1425. border: none;
  1426. /* border: 1px solid #d5e5ff; */
  1427. }
  1428. .input:focus {
  1429. outline: none;
  1430. border: none;
  1431. }
  1432. .user_info_box {
  1433. margin: 10px 0;
  1434. display: flex;
  1435. justify-content: flex-start;
  1436. }
  1437. .title_span {
  1438. /* width: 100%; */
  1439. margin: 4px 2px;
  1440. color: #666;
  1441. font-size: 14px;
  1442. font-weight: bold;
  1443. }
  1444. .content_span {
  1445. color: #999;
  1446. font-size: 14px;
  1447. }
  1448. .key {
  1449. /* width: 27.8vw; */
  1450. /* position: absolute; */
  1451. bottom: 22px;
  1452. height: 23vh;
  1453. /* background: #409EFF; */
  1454. }
  1455. .msgInputBtn {
  1456. right: 10px;
  1457. bottom: 10px;
  1458. width: 60px;
  1459. height: 30px;
  1460. /* background:#ECF4FF; */
  1461. background: #5399f5;
  1462. margin-right: 10px;
  1463. border-radius: 5px;
  1464. font-size: 14px;
  1465. color: #fff;
  1466. cursor: pointer;
  1467. }
  1468. /* .msgInputBtn:hover{
  1469. background:#5399f5;
  1470. } */
  1471. .frceBox {
  1472. position: absolute;
  1473. /* top: 25vw; */
  1474. bottom: 25vh;
  1475. left: 31.5vw;
  1476. width: 28vw;
  1477. height: 25vh;
  1478. background: #fff;
  1479. border: 1px solid #d5e5ff;
  1480. overflow-x: hidden;
  1481. overflow-y: auto;
  1482. z-index: 999999;
  1483. }
  1484. .frceBox p {
  1485. width: 50px;
  1486. height: 50px;
  1487. }
  1488. .FastReply {
  1489. width: 18vw;
  1490. height: 92vh;
  1491. border-right: 1px solid #d5e5ff;
  1492. background: #fff;
  1493. }
  1494. .FastReplyBox {
  1495. padding: 0.4rem 0;
  1496. height: 75vh;
  1497. overflow-x: hidden;
  1498. overflow-y: auto;
  1499. }
  1500. .FastReplyHader {
  1501. height: 50px;
  1502. border-bottom: 1px solid #d5e5ff;
  1503. padding: 0 10px;
  1504. font-size: 14px;
  1505. color: #666;
  1506. font-weight: bold;
  1507. }
  1508. .FastReplySwitch {
  1509. height: 50px;
  1510. border-bottom: 1px solid #d5e5ff;
  1511. color: #666;
  1512. font-size: 14px;
  1513. padding: 0 40px;
  1514. }
  1515. .FastReplySwitch p.active {
  1516. position: relative;
  1517. color: #5399f5;
  1518. }
  1519. .FastReplySwitch p.active::after {
  1520. content: "";
  1521. display: inline-block;
  1522. position: absolute;
  1523. width: 42px;
  1524. height: 2px;
  1525. left: 1px;
  1526. bottom: -15px;
  1527. background: #5399f5;
  1528. }
  1529. ul {
  1530. margin-block-start: 0.4em;
  1531. margin-block-end: 0.4em;
  1532. }
  1533. .cursor_text {
  1534. cursor: pointer;
  1535. margin: 10px 20px;
  1536. }
  1537. .cursor_text:hover {
  1538. color: #d5e5ff;
  1539. background: #f6f8ff;
  1540. }
  1541. .serch {
  1542. padding: 20px 10px;
  1543. }
  1544. .disable {
  1545. color: #f0f0f0 !important;
  1546. }
  1547. .serchBox {
  1548. width: 200px;
  1549. height: 40px;
  1550. border: 1px solid #eee;
  1551. position: relative;
  1552. }
  1553. .serchBox img {
  1554. position: absolute;
  1555. right: 10px;
  1556. top: 12px;
  1557. }
  1558. .serchBox input {
  1559. width: 100%;
  1560. height: 100%;
  1561. background: #f5f5f5;
  1562. border: none;
  1563. color: #999;
  1564. padding: 0 10px;
  1565. }
  1566. .serchBox input:focus {
  1567. outline: none;
  1568. color: #666;
  1569. }
  1570. .FastReplyList {
  1571. width: 100%;
  1572. }
  1573. .userinfo {
  1574. width: 16vw;
  1575. padding: 20px;
  1576. background: #ECF4FF;
  1577. }
  1578. .userData p {
  1579. line-height: 30px;
  1580. display: block;
  1581. }
  1582. .message_box {
  1583. background: #DFF0FF;
  1584. border-radius: 10px 0 10px 10px;
  1585. }
  1586. .user_box {
  1587. background: #F5F5F5;
  1588. border-radius: 0 10px 10px 10px;
  1589. }
  1590. .userDataInput {
  1591. width: 80%;
  1592. padding: 10px;
  1593. height: 80px;
  1594. resize: none;
  1595. border: 1px solid #d5e5ff;
  1596. background: #fff;
  1597. }
  1598. .userDataInput:focus {
  1599. outline: none;
  1600. }
  1601. .userBtn {
  1602. width: 60px;
  1603. height: 34px;
  1604. border: 1px solid rgba(221, 221, 221, 1);
  1605. background: linear-gradient(
  1606. 180deg,
  1607. rgba(245, 245, 245, 1) 0%,
  1608. rgba(238, 238, 238, 1) 100%
  1609. );
  1610. border-radius: 5px;
  1611. color: #888;
  1612. font-size: 14px;
  1613. margin-top: 10px;
  1614. }
  1615. .userBtn:hover {
  1616. background: #5399f5;
  1617. color: #f0f0f0;
  1618. cursor: pointer;
  1619. }
  1620. .chatmin {
  1621. height: 46.5vh;
  1622. }
  1623. #pop .el-button--primary {
  1624. background: #409EFF !important;
  1625. /* color:#fff !important; */
  1626. border: 1px solid #DCDFE6;
  1627. line-height: 1;
  1628. padding: 4px 8px;
  1629. }
  1630. .cell button {
  1631. line-height: 1;
  1632. -webkit-transition: .1s;
  1633. border-radius: 4px;
  1634. border: 1px solid #DCDFE6;
  1635. padding: 4px 8px;
  1636. }
  1637. #pop .el-button {
  1638. line-height: 0;
  1639. /* width: 0; */
  1640. border: none;
  1641. padding: 0;
  1642. color: #999;
  1643. font-size: 12px;
  1644. font-weight: 400;
  1645. }
  1646. .el-tooltip__popper {
  1647. max-width: 15vw;
  1648. /* line-height: 180%; */
  1649. }
  1650. .rightAlignment .el-button {
  1651. border: none;
  1652. }
  1653. .history-info {
  1654. color: #5399f5;
  1655. text-align: center;
  1656. margin-top: 5px;
  1657. }
  1658. </style>