TheCurrentSession.vue 53 KB

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