cnhis-design-vue 2.1.78 → 2.1.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (588) hide show
  1. package/.prettierrc.js +27 -27
  2. package/CHANGELOG.md +2924 -2903
  3. package/README.md +90 -90
  4. package/commitlint.config.js +1 -1
  5. package/es/affix/index.js +8 -8
  6. package/es/age/index.js +18 -18
  7. package/es/alert/index.js +8 -8
  8. package/es/anchor/index.js +8 -8
  9. package/es/auto-complete/index.js +8 -8
  10. package/es/avatar/index.js +8 -8
  11. package/es/back-top/index.js +8 -8
  12. package/es/badge/index.js +8 -8
  13. package/es/base/index.js +8 -8
  14. package/es/big-table/index.js +311 -311
  15. package/es/breadcrumb/index.js +8 -8
  16. package/es/button/index.js +31 -31
  17. package/es/calendar/index.js +8 -8
  18. package/es/captcha/index.js +7 -7
  19. package/es/card/index.js +8 -8
  20. package/es/carousel/index.js +8 -8
  21. package/es/cascader/index.js +8 -8
  22. package/es/checkbox/index.js +17 -17
  23. package/es/col/index.js +8 -8
  24. package/es/collapse/index.js +8 -8
  25. package/es/color-picker/index.js +5 -5
  26. package/es/comment/index.js +8 -8
  27. package/es/config-provider/index.js +8 -8
  28. package/es/date-picker/index.js +30 -30
  29. package/es/descriptions/index.js +8 -8
  30. package/es/divider/index.js +8 -8
  31. package/es/drag-layout/index.js +5 -5
  32. package/es/drawer/index.js +8 -8
  33. package/es/dropdown/index.js +8 -8
  34. package/es/editor/index.js +1 -1
  35. package/es/ellipsis/index.js +1 -1
  36. package/es/empty/index.js +8 -8
  37. package/es/fabric-chart/index.js +45 -45
  38. package/es/form/index.js +8 -8
  39. package/es/form-model/index.js +8 -8
  40. package/es/form-table/index.js +144 -144
  41. package/es/grid/index.js +4 -4
  42. package/es/index/index.js +1260 -1256
  43. package/es/index/style.css +1 -1
  44. package/es/input/index.js +11 -11
  45. package/es/input-number/index.js +8 -8
  46. package/es/keep-cache/index.js +9 -9
  47. package/es/layout/index.js +8 -8
  48. package/es/list/index.js +8 -8
  49. package/es/locale-provider/index.js +8 -8
  50. package/es/map/index.js +13 -13
  51. package/es/mentions/index.js +8 -8
  52. package/es/menu/index.js +8 -8
  53. package/es/message/index.js +8 -8
  54. package/es/multi-chat/index.js +117 -117
  55. package/es/multi-chat-client/index.js +111 -111
  56. package/es/multi-chat-history/index.js +6 -6
  57. package/es/multi-chat-record/index.js +27 -27
  58. package/es/multi-chat-setting/index.js +43 -43
  59. package/es/multi-chat-sip/index.js +1 -1
  60. package/es/notification/index.js +8 -8
  61. package/es/page-header/index.js +8 -8
  62. package/es/pagination/index.js +8 -8
  63. package/es/popconfirm/index.js +8 -8
  64. package/es/popover/index.js +8 -8
  65. package/es/progress/index.js +8 -8
  66. package/es/radio/index.js +17 -17
  67. package/es/rate/index.js +8 -8
  68. package/es/result/index.js +8 -8
  69. package/es/row/index.js +8 -8
  70. package/es/scale-container/index.js +1 -1
  71. package/es/scale-view/index.js +175 -175
  72. package/es/select/index.js +44 -44
  73. package/es/select-label/index.js +50 -50
  74. package/es/select-person/index.js +45 -41
  75. package/es/select-person/style.css +1 -1
  76. package/es/shortcut-setter/index.js +10 -10
  77. package/es/skeleton/index.js +8 -8
  78. package/es/slider/index.js +8 -8
  79. package/es/space/index.js +8 -8
  80. package/es/spin/index.js +8 -8
  81. package/es/statistic/index.js +8 -8
  82. package/es/steps/index.js +8 -8
  83. package/es/switch/index.js +8 -8
  84. package/es/table-filter/index.js +214 -214
  85. package/es/tabs/index.js +8 -8
  86. package/es/tag/index.js +9 -9
  87. package/es/time-picker/index.js +8 -8
  88. package/es/timeline/index.js +8 -8
  89. package/es/tooltip/index.js +8 -8
  90. package/es/transfer/index.js +8 -8
  91. package/es/tree/index.js +8 -8
  92. package/es/tree-select/index.js +8 -8
  93. package/es/upload/index.js +8 -8
  94. package/es/utils/clickoutside.js +7 -7
  95. package/es/utils/kty.min-1.0.0.js +5 -5
  96. package/es/utils/time-domain.js +16 -16
  97. package/es/utils/utils-map.js +32 -32
  98. package/es/utils/vexutils.js +27 -27
  99. package/es/verification-code/index.js +2 -2
  100. package/lib/cui.common.js +21239 -21236
  101. package/lib/cui.umd.js +21239 -21236
  102. package/lib/cui.umd.min.js +29 -29
  103. package/package.json +110 -110
  104. package/packages/affix/index.js +12 -12
  105. package/packages/affix/src/Affix.jsx +12 -12
  106. package/packages/age/index.js +27 -27
  107. package/packages/age/src/age/index.vue +139 -139
  108. package/packages/age/src/age-com/index.vue +209 -209
  109. package/packages/alert/index.js +12 -12
  110. package/packages/alert/src/Alert.jsx +11 -11
  111. package/packages/anchor/index.js +18 -18
  112. package/packages/anchor/src/Anchor.jsx +11 -11
  113. package/packages/anchor/src/Link.jsx +11 -11
  114. package/packages/auto-complete/index.js +12 -12
  115. package/packages/auto-complete/src/AutoComplete.jsx +12 -12
  116. package/packages/avatar/index.js +12 -12
  117. package/packages/avatar/src/Avatar.jsx +11 -11
  118. package/packages/back-top/index.js +12 -12
  119. package/packages/back-top/src/BackTop.jsx +11 -11
  120. package/packages/badge/index.js +12 -12
  121. package/packages/badge/src/Badge.jsx +11 -11
  122. package/packages/base/index.js +3 -3
  123. package/packages/big-table/index.js +16 -16
  124. package/packages/big-table/src/BigTable.vue +3193 -3193
  125. package/packages/big-table/src/Fieldset.vue +2067 -2067
  126. package/packages/big-table/src/assets/iconfont/iconfont.css +21 -21
  127. package/packages/big-table/src/assets/style/table-base.less +387 -387
  128. package/packages/big-table/src/assets/style/table-global.less +175 -175
  129. package/packages/big-table/src/components/AutoLayoutButton.vue +307 -307
  130. package/packages/big-table/src/components/NoData.vue +81 -81
  131. package/packages/big-table/src/components/TextOverTooltip.vue +120 -120
  132. package/packages/big-table/src/components/edit-form/EditForm.vue +509 -509
  133. package/packages/big-table/src/components/edit-form/edit-component/config-data/index.js +68 -68
  134. package/packages/big-table/src/components/edit-form/edit-component/edit-date-picker/edit-date-picker.vue +60 -60
  135. package/packages/big-table/src/components/edit-form/edit-component/edit-digital/edit-digital.vue +54 -54
  136. package/packages/big-table/src/components/edit-form/edit-component/edit-input/edit-input.vue +39 -39
  137. package/packages/big-table/src/components/edit-form/edit-component/edit-input-password/edit-input-password.vue +79 -79
  138. package/packages/big-table/src/components/edit-form/edit-component/edit-month-picker/edit-month-picker.vue +37 -37
  139. package/packages/big-table/src/components/edit-form/edit-component/edit-search/edit-search.vue +82 -82
  140. package/packages/big-table/src/components/edit-form/edit-component/edit-search-more/edit-search-more.vue +95 -95
  141. package/packages/big-table/src/components/edit-form/edit-component/edit-select/edit-select.vue +40 -40
  142. package/packages/big-table/src/components/edit-form/edit-component/edit-select-multiple/edit-select-multiple.vue +55 -55
  143. package/packages/big-table/src/components/edit-form/edit-component/edit-switch/edit-switch.vue +43 -43
  144. package/packages/big-table/src/components/edit-form/edit-component/edit-textarea/edit-textarea.vue +41 -41
  145. package/packages/big-table/src/components/edit-form/edit-component/edit-time-picker/edit-time-picker.vue +40 -40
  146. package/packages/big-table/src/components/edit-form/edit-component/mixins/bound-date.js +3 -3
  147. package/packages/big-table/src/components/edit-form/edit-component/mixins/dateType.js +217 -217
  148. package/packages/big-table/src/components/edit-form/edit-component/mixins/item-default.js +639 -639
  149. package/packages/big-table/src/components/edit-form/edit-component/mixins/search.js +1247 -1247
  150. package/packages/big-table/src/components/edit-form/edit-component/register-com.js +26 -26
  151. package/packages/big-table/src/components/edit-form/edit-item/form-event.js +80 -80
  152. package/packages/big-table/src/components/edit-form/edit-item/global-props.js +33 -33
  153. package/packages/big-table/src/components/edit-form/edit-item/index.js +4 -4
  154. package/packages/big-table/src/components/edit-form/edit-item/render-methods.js +28 -28
  155. package/packages/big-table/src/components/edit-form/edit-item/validate-rules.js +463 -463
  156. package/packages/big-table/src/components/edit-form/edit-mixins/form-commom.js +673 -673
  157. package/packages/big-table/src/components/edit-form/edit-mixins/index.js +3 -3
  158. package/packages/big-table/src/components/edit-form/edit-utils/index.js +112 -112
  159. package/packages/big-table/src/components/password-com.vue +58 -58
  160. package/packages/big-table/src/components/player-vod/index.vue +57 -57
  161. package/packages/big-table/src/components/player-vod/player.vue +193 -193
  162. package/packages/big-table/src/components/player-vod/video-list.vue +265 -265
  163. package/packages/big-table/src/components/player-vod/video-modal.vue +126 -126
  164. package/packages/big-table/src/utils/CustomPagination.vue +86 -86
  165. package/packages/big-table/src/utils/batchEditing.js +610 -610
  166. package/packages/big-table/src/utils/bigTableProps.js +108 -108
  167. package/packages/big-table/src/utils/eventBroadcast.js +24 -24
  168. package/packages/big-table/src/utils/format.js +557 -557
  169. package/packages/big-table/src/utils/nestTable.js +109 -109
  170. package/packages/big-table/src/utils/tableParse.js +234 -234
  171. package/packages/breadcrumb/index.js +21 -21
  172. package/packages/breadcrumb/src/Breadcrumb.jsx +11 -11
  173. package/packages/breadcrumb/src/BreadcrumbItem.jsx +11 -11
  174. package/packages/breadcrumb/src/BreadcrumbSeparator.jsx +11 -11
  175. package/packages/button/index.js +21 -21
  176. package/packages/button/src/Button.jsx +11 -11
  177. package/packages/button/src/ButtonGroup.jsx +11 -11
  178. package/packages/button/src/ButtonPrint/components/IdentityVerification.vue +181 -181
  179. package/packages/button/src/ButtonPrint/index.vue +766 -766
  180. package/packages/button/src/ButtonPrint/mixin/his-print.js +95 -95
  181. package/packages/calendar/index.js +12 -12
  182. package/packages/calendar/src/Calendar.jsx +11 -11
  183. package/packages/captcha/index.js +9 -9
  184. package/packages/captcha/src/Captcha.vue +164 -164
  185. package/packages/captcha/src/Index.vue +47 -47
  186. package/packages/captcha/src/SlideVerify.vue +285 -285
  187. package/packages/card/index.js +21 -21
  188. package/packages/card/src/Card.jsx +12 -12
  189. package/packages/card/src/CardGrid.js +7 -7
  190. package/packages/card/src/CardMeta.js +7 -7
  191. package/packages/carousel/index.js +12 -12
  192. package/packages/carousel/src/Carousel.jsx +12 -12
  193. package/packages/cascader/index.js +12 -12
  194. package/packages/cascader/src/Cascader.jsx +11 -11
  195. package/packages/checkbox/index.js +30 -30
  196. package/packages/checkbox/src/Checkbox.jsx +11 -11
  197. package/packages/checkbox/src/CheckboxImg/index.vue +141 -141
  198. package/packages/checkbox/src/Group.jsx +11 -11
  199. package/packages/col/index.js +13 -13
  200. package/packages/col/src/Col.jsx +11 -11
  201. package/packages/collapse/index.js +18 -18
  202. package/packages/collapse/src/Collapse.jsx +11 -11
  203. package/packages/collapse/src/Panel.jsx +11 -11
  204. package/packages/color-picker/index.js +10 -10
  205. package/packages/color-picker/src/color-picker.vue +191 -191
  206. package/packages/color-picker/src/style.less +109 -109
  207. package/packages/comment/index.js +12 -12
  208. package/packages/comment/src/Comment.jsx +11 -11
  209. package/packages/config-provider/index.js +12 -12
  210. package/packages/config-provider/src/ConfigProvider.jsx +11 -11
  211. package/packages/date-picker/index.js +26 -26
  212. package/packages/date-picker/src/DatePicker.jsx +12 -12
  213. package/packages/date-picker/src/MonthPicker.jsx +11 -11
  214. package/packages/date-picker/src/RangePicker.jsx +11 -11
  215. package/packages/date-picker/src/WeekPicker.jsx +11 -11
  216. package/packages/date-picker/src/utils/index.js +374 -374
  217. package/packages/descriptions/index.js +18 -18
  218. package/packages/descriptions/src/Descriptions.jsx +11 -11
  219. package/packages/descriptions/src/Item.jsx +11 -11
  220. package/packages/divider/index.js +12 -12
  221. package/packages/divider/src/Divider.jsx +11 -11
  222. package/packages/drag-layout/DragFormLeftItem.vue +173 -173
  223. package/packages/drag-layout/DragFormRightItem.vue +284 -284
  224. package/packages/drag-layout/I18n-mixins.js +10 -10
  225. package/packages/drag-layout/drag-layout.vue +778 -778
  226. package/packages/drag-layout/index.js +12 -12
  227. package/packages/drawer/index.js +12 -12
  228. package/packages/drawer/src/Drawer.jsx +11 -11
  229. package/packages/dropdown/index.js +12 -12
  230. package/packages/dropdown/src/Dropdown.jsx +11 -11
  231. package/packages/editor/index.js +9 -9
  232. package/packages/ellipsis/index.js +8 -8
  233. package/packages/ellipsis/src/Ellipsis.vue +65 -65
  234. package/packages/empty/index.js +12 -12
  235. package/packages/empty/src/Empty.jsx +11 -11
  236. package/packages/fabric-chart/index.js +9 -9
  237. package/packages/fabric-chart/src/FabricGrid.vue +67 -67
  238. package/packages/fabric-chart/src/components/DropPopup.vue +90 -90
  239. package/packages/fabric-chart/src/components/MouseRightClick.vue +168 -168
  240. package/packages/fabric-chart/src/components/TimeScaleValue.vue +125 -125
  241. package/packages/fabric-chart/src/const/defaultVaule.js +60 -60
  242. package/packages/fabric-chart/src/fabric-chart/FabricLines.vue +617 -617
  243. package/packages/fabric-chart/src/fabric-chart/FabricPolylines.vue +1191 -1191
  244. package/packages/fabric-chart/src/fabric-chart/FabricScaleValue.vue +139 -139
  245. package/packages/fabric-chart/src/fabric-chart/FabricTextGroup.vue +651 -651
  246. package/packages/fabric-chart/src/mixins/fabricCommon.js +81 -81
  247. package/packages/fabric-chart/src/mixins/fabricObject.js +193 -193
  248. package/packages/fabric-chart/src/mixins/type.js +5 -5
  249. package/packages/fabric-chart/src/utils/bus.js +2 -2
  250. package/packages/form/index.js +16 -16
  251. package/packages/form/src/Form.jsx +11 -11
  252. package/packages/form/src/Item.jsx +11 -11
  253. package/packages/form-model/index.js +14 -14
  254. package/packages/form-model/src/FormModel.jsx +11 -11
  255. package/packages/form-model/src/Item.jsx +11 -11
  256. package/packages/form-table/index.js +16 -16
  257. package/packages/form-table/src/FormTable.vue +1110 -1110
  258. package/packages/form-table/src/components/table-component/config-data/index.js +80 -80
  259. package/packages/form-table/src/components/table-component/global-props.js +22 -22
  260. package/packages/form-table/src/components/table-component/index.js +8 -8
  261. package/packages/form-table/src/components/table-component/mixins/bound-date.js +455 -455
  262. package/packages/form-table/src/components/table-component/mixins/dateType.js +217 -217
  263. package/packages/form-table/src/components/table-component/mixins/item-default.js +257 -257
  264. package/packages/form-table/src/components/table-component/mixins/search.js +1242 -1242
  265. package/packages/form-table/src/components/table-component/register-com.js +30 -30
  266. package/packages/form-table/src/components/table-component/table-age/table-age.vue +175 -175
  267. package/packages/form-table/src/components/table-component/table-date-picker/table-date-picker.vue +87 -87
  268. package/packages/form-table/src/components/table-component/table-digital/table-digital.vue +93 -93
  269. package/packages/form-table/src/components/table-component/table-input/table-input.vue +81 -81
  270. package/packages/form-table/src/components/table-component/table-input-password/table-input-password.vue +126 -126
  271. package/packages/form-table/src/components/table-component/table-month-picker/table-month-picker.vue +55 -55
  272. package/packages/form-table/src/components/table-component/table-search/table-search.vue +174 -174
  273. package/packages/form-table/src/components/table-component/table-search-more/table-search-more.vue +191 -191
  274. package/packages/form-table/src/components/table-component/table-select/table-select.vue +64 -64
  275. package/packages/form-table/src/components/table-component/table-select-multiple/table-select-multiple.vue +81 -81
  276. package/packages/form-table/src/components/table-component/table-textarea/table-textarea.vue +76 -76
  277. package/packages/form-table/src/components/table-component/table-time-picker/table-time-picker.vue +55 -55
  278. package/packages/form-table/src/components/table-component/table-tree-select/table-tree-select.vue +135 -135
  279. package/packages/form-table/src/components/table-component/text-over-tooltip/TextOverTooltip.vue +97 -97
  280. package/packages/form-table/src/components/table-item/form-event.js +81 -81
  281. package/packages/form-table/src/components/table-item/global-props.js +27 -27
  282. package/packages/form-table/src/components/table-item/index.js +4 -4
  283. package/packages/form-table/src/components/table-item/render-methods.js +28 -28
  284. package/packages/form-table/src/components/table-item/validate-rules.js +520 -520
  285. package/packages/form-table/src/components/table-mixins/form-commom.js +98 -98
  286. package/packages/form-table/src/components/table-mixins/index.js +3 -3
  287. package/packages/form-table/src/components/table-utils/index.js +112 -112
  288. package/packages/form-table/src/disabledDetail.less +46 -46
  289. package/packages/grid/index.js +10 -10
  290. package/packages/grid/src/grid.js +28 -28
  291. package/packages/icon/index.js +10 -10
  292. package/packages/icon/src/icon.js +13 -13
  293. package/packages/index.js +313 -313
  294. package/packages/input/index.js +30 -30
  295. package/packages/input/src/Group.jsx +11 -11
  296. package/packages/input/src/Input.jsx +11 -11
  297. package/packages/input/src/Password.jsx +11 -11
  298. package/packages/input/src/Search.jsx +11 -11
  299. package/packages/input/src/TextArea.jsx +11 -11
  300. package/packages/input/src/input-quick/components/quick-item.vue +284 -284
  301. package/packages/input/src/input-quick/components/quick-popover.vue +596 -596
  302. package/packages/input/src/input-quick/index.vue +137 -137
  303. package/packages/input-number/index.js +12 -12
  304. package/packages/input-number/src/InputNumber.jsx +11 -11
  305. package/packages/keep-cache/KeepCache.js +236 -236
  306. package/packages/keep-cache/index.css +2 -2
  307. package/packages/keep-cache/index.js +8 -8
  308. package/packages/layout/index.js +27 -27
  309. package/packages/layout/src/Content.jsx +11 -11
  310. package/packages/layout/src/Footer.jsx +11 -11
  311. package/packages/layout/src/Header.jsx +11 -11
  312. package/packages/layout/src/Layout.jsx +11 -11
  313. package/packages/layout/src/Sider.jsx +11 -11
  314. package/packages/list/index.js +21 -21
  315. package/packages/list/src/Item.jsx +11 -11
  316. package/packages/list/src/ItemMeta.jsx +11 -11
  317. package/packages/list/src/List.jsx +11 -11
  318. package/packages/locale-provider/index.js +12 -12
  319. package/packages/locale-provider/src/LocaleProvider.jsx +11 -11
  320. package/packages/map/index.js +9 -9
  321. package/packages/map/src/Map.vue +484 -484
  322. package/packages/map/src/popup-map.vue +53 -53
  323. package/packages/mentions/index.js +18 -18
  324. package/packages/mentions/src/Mentions.jsx +11 -11
  325. package/packages/mentions/src/Option.jsx +11 -11
  326. package/packages/menu/index.js +27 -27
  327. package/packages/menu/src/Divider.jsx +11 -11
  328. package/packages/menu/src/Item.jsx +11 -11
  329. package/packages/menu/src/ItemGroup.jsx +11 -11
  330. package/packages/menu/src/Menu.jsx +11 -11
  331. package/packages/menu/src/SubMenu.jsx +11 -11
  332. package/packages/message/index.js +8 -8
  333. package/packages/modal/index.js +10 -10
  334. package/packages/modal/src/Modal.js +7 -7
  335. package/packages/multi-chat/chat/addConference.vue +200 -200
  336. package/packages/multi-chat/chat/addMembers.vue +411 -411
  337. package/packages/multi-chat/chat/advancedFilter.vue +372 -372
  338. package/packages/multi-chat/chat/calling.vue +246 -246
  339. package/packages/multi-chat/chat/chatFooter.vue +1647 -1647
  340. package/packages/multi-chat/chat/chatHistory.vue +605 -605
  341. package/packages/multi-chat/chat/chatMain.vue +1490 -1490
  342. package/packages/multi-chat/chat/client/index.vue +149 -149
  343. package/packages/multi-chat/chat/delay.vue +177 -177
  344. package/packages/multi-chat/chat/evaluate.vue +343 -343
  345. package/packages/multi-chat/chat/messageRecord.vue +324 -324
  346. package/packages/multi-chat/chat/mixins/NoData.js +20 -20
  347. package/packages/multi-chat/chat/mixins/base.js +97 -97
  348. package/packages/multi-chat/chat/mixins/uniRTCAPI.js +80 -80
  349. package/packages/multi-chat/chat/mixins/viewerOptions.js +67 -67
  350. package/packages/multi-chat/chat/quickReply.vue +439 -439
  351. package/packages/multi-chat/chat/robot/index.vue +312 -312
  352. package/packages/multi-chat/chat/scrollList.vue +1259 -1259
  353. package/packages/multi-chat/chat/videoVoiceList.vue +348 -348
  354. package/packages/multi-chat/chat/voice.vue +431 -431
  355. package/packages/multi-chat/components/avatar.vue +113 -113
  356. package/packages/multi-chat/components/chat-tabs-header.vue +251 -251
  357. package/packages/multi-chat/components/classify-tabs.vue +185 -185
  358. package/packages/multi-chat/components/empty.vue +24 -24
  359. package/packages/multi-chat/components/modal-refuse-reason.vue +112 -112
  360. package/packages/multi-chat/components/modal-sip.vue +160 -160
  361. package/packages/multi-chat/components/modal-user-transfer.vue +98 -98
  362. package/packages/multi-chat/components/msg-describe.vue +138 -138
  363. package/packages/multi-chat/components/msg-picture.vue +68 -68
  364. package/packages/multi-chat/components/msg-prescription.vue +205 -205
  365. package/packages/multi-chat/components/read-record.vue +133 -133
  366. package/packages/multi-chat/components/read-status.vue +34 -34
  367. package/packages/multi-chat/components/user-status.vue +198 -198
  368. package/packages/multi-chat/components/vuecmf-dialog.vue +322 -322
  369. package/packages/multi-chat/index.js +7 -7
  370. package/packages/multi-chat/setting/authority/index.vue +156 -156
  371. package/packages/multi-chat/setting/authority/roleSetting.vue +204 -204
  372. package/packages/multi-chat/setting/baseInfo/index.vue +1343 -1343
  373. package/packages/multi-chat/setting/customerService/batchSelect.vue +403 -403
  374. package/packages/multi-chat/setting/customerService/index.vue +273 -273
  375. package/packages/multi-chat/setting/event/edit/condition.vue +128 -128
  376. package/packages/multi-chat/setting/event/edit/index.vue +437 -437
  377. package/packages/multi-chat/setting/event/edit/notice.vue +129 -129
  378. package/packages/multi-chat/setting/event/edit/strategy.vue +98 -98
  379. package/packages/multi-chat/setting/event/index.vue +249 -249
  380. package/packages/multi-chat/setting/index.vue +269 -269
  381. package/packages/multi-chat/setting/page.vue +14 -14
  382. package/packages/multi-chat/setting/sessionList/index.vue +412 -412
  383. package/packages/multi-chat/setting/sessionList/messageRecord.vue +372 -372
  384. package/packages/multi-chat/setting/userConfig/index.vue +124 -124
  385. package/packages/multi-chat/setting/worktime/index.vue +274 -274
  386. package/packages/multi-chat/store/actions.js +452 -452
  387. package/packages/multi-chat/store/getters.js +380 -380
  388. package/packages/multi-chat/store/helper.js +66 -66
  389. package/packages/multi-chat/store/index.js +50 -50
  390. package/packages/multi-chat/store/mutation.js +305 -305
  391. package/packages/multi-chat/store/state.js +120 -120
  392. package/packages/multi-chat/style/emoji.css +315 -315
  393. package/packages/multi-chat/style/message.mixin.less +38 -38
  394. package/packages/multi-chat/utils/chatSock.js +93 -93
  395. package/packages/multi-chat/utils/compressImage.js +115 -115
  396. package/packages/multi-chat/utils/emoji.json +68 -68
  397. package/packages/multi-chat/utils/index.js +259 -259
  398. package/packages/multi-chat/utils/observer-scroll.js +49 -49
  399. package/packages/multi-chat/utils/panelsetting.js +48 -48
  400. package/packages/multi-chat-client/index.js +7 -7
  401. package/packages/multi-chat-history/index.js +7 -7
  402. package/packages/multi-chat-record/index.js +7 -7
  403. package/packages/multi-chat-setting/index.js +7 -7
  404. package/packages/multi-chat-sip/index.js +6 -6
  405. package/packages/notification/index.js +8 -8
  406. package/packages/page-header/index.js +12 -12
  407. package/packages/page-header/src/PageHeader.jsx +11 -11
  408. package/packages/pagination/index.js +12 -12
  409. package/packages/pagination/src/Pagination.jsx +11 -11
  410. package/packages/popconfirm/index.js +12 -12
  411. package/packages/popconfirm/src/Popconfirm.jsx +11 -11
  412. package/packages/popover/index.js +12 -12
  413. package/packages/popover/src/Popover.jsx +11 -11
  414. package/packages/progress/index.js +12 -12
  415. package/packages/progress/src/Progress.jsx +11 -11
  416. package/packages/radio/index.js +33 -33
  417. package/packages/radio/src/Group.jsx +11 -11
  418. package/packages/radio/src/Radio.jsx +11 -11
  419. package/packages/radio/src/RadioButton.jsx +11 -11
  420. package/packages/radio/src/RadioImg/index.vue +124 -124
  421. package/packages/rate/index.js +12 -12
  422. package/packages/rate/src/Rate.jsx +11 -11
  423. package/packages/result/index.js +12 -12
  424. package/packages/result/src/Result.jsx +11 -11
  425. package/packages/row/index.js +12 -12
  426. package/packages/row/src/Row.jsx +11 -11
  427. package/packages/scale-container/index.js +8 -8
  428. package/packages/scale-container/src/ScaleContainer.vue +197 -197
  429. package/packages/scale-view/NoData.vue +81 -81
  430. package/packages/scale-view/answerParse.vue +133 -133
  431. package/packages/scale-view/customList.vue +801 -801
  432. package/packages/scale-view/data.js +80 -80
  433. package/packages/scale-view/evaluateCountdown.vue +155 -155
  434. package/packages/scale-view/evaluatePage.vue +202 -202
  435. package/packages/scale-view/formitem/data.js +3991 -3991
  436. package/packages/scale-view/formitem/index.js +7 -7
  437. package/packages/scale-view/formitem/r-address.vue +245 -245
  438. package/packages/scale-view/formitem/r-choice.vue +746 -746
  439. package/packages/scale-view/formitem/r-input.vue +93 -93
  440. package/packages/scale-view/formitem/r-prompt.vue +52 -52
  441. package/packages/scale-view/formitem/r-sign.vue +218 -218
  442. package/packages/scale-view/formitem/r-time.vue +285 -285
  443. package/packages/scale-view/formitem/r-upload-custom-list.vue +242 -242
  444. package/packages/scale-view/formitem/r-upload.vue +287 -287
  445. package/packages/scale-view/formitem/sign-com.vue +316 -316
  446. package/packages/scale-view/formitem/text-over-tooltip/TextOverTooltip.vue +98 -98
  447. package/packages/scale-view/index.js +17 -17
  448. package/packages/scale-view/mixin/NoData.js +38 -38
  449. package/packages/scale-view/mixin/addressVal.js +156 -156
  450. package/packages/scale-view/mixin/evaluate.js +146 -146
  451. package/packages/scale-view/mixin/index.js +337 -337
  452. package/packages/scale-view/mixin/judgeTypes.js +267 -267
  453. package/packages/scale-view/scaleView.vue +2017 -2017
  454. package/packages/select/index.js +27 -27
  455. package/packages/select/src/CustomSelect/index.vue +130 -130
  456. package/packages/select/src/OptGroup.jsx +11 -11
  457. package/packages/select/src/Option.jsx +11 -11
  458. package/packages/select/src/Select/Select.vue +231 -231
  459. package/packages/select/src/Select/index.js +12 -12
  460. package/packages/select/src/TableSelect/index.vue +514 -514
  461. package/packages/select-label/index.js +14 -14
  462. package/packages/select-label/label-classify.vue +129 -129
  463. package/packages/select-label/labelFormContent.vue +787 -787
  464. package/packages/select-label/select-label.vue +581 -581
  465. package/packages/select-person/index.js +10 -10
  466. package/packages/select-person/search-tree.vue +373 -373
  467. package/packages/select-person/select-person.vue +1703 -1696
  468. package/packages/shortcut-setter/index.js +12 -12
  469. package/packages/shortcut-setter/src/ShortcutSetter.vue +55 -55
  470. package/packages/shortcut-setter/src/ShortcutSetterItem.vue +85 -85
  471. package/packages/shortcut-setter/src/utils/index.js +63 -63
  472. package/packages/skeleton/index.js +12 -12
  473. package/packages/skeleton/src/Skeleton.jsx +11 -11
  474. package/packages/slider/index.js +12 -12
  475. package/packages/slider/src/Slider.jsx +11 -11
  476. package/packages/space/index.js +12 -12
  477. package/packages/space/src/Space.jsx +11 -11
  478. package/packages/spin/index.js +12 -12
  479. package/packages/spin/src/Spin.jsx +11 -11
  480. package/packages/statistic/index.js +18 -18
  481. package/packages/statistic/src/Countdown.jsx +11 -11
  482. package/packages/statistic/src/Statistic.jsx +11 -11
  483. package/packages/steps/index.js +18 -18
  484. package/packages/steps/src/Step.jsx +11 -11
  485. package/packages/steps/src/Steps.jsx +11 -11
  486. package/packages/switch/index.js +12 -12
  487. package/packages/switch/src/Switch.jsx +11 -11
  488. package/packages/table-filter/index.js +27 -27
  489. package/packages/table-filter/src/base-search-com/BaseSearch.vue +2630 -2630
  490. package/packages/table-filter/src/classification/Classification-com.vue +1760 -1760
  491. package/packages/table-filter/src/classification/search-class-name.vue +266 -266
  492. package/packages/table-filter/src/classification/search-professional-model.vue +680 -680
  493. package/packages/table-filter/src/components/TextOverTooltip.vue +107 -107
  494. package/packages/table-filter/src/components/age-com/index.vue +205 -205
  495. package/packages/table-filter/src/components/button-group/ButtonGroup.vue +162 -162
  496. package/packages/table-filter/src/components/button-icon/button-icon.js +33 -33
  497. package/packages/table-filter/src/components/button-icon/getBtnIcon.js +34 -34
  498. package/packages/table-filter/src/components/c-tree-select/tree-select.vue +336 -336
  499. package/packages/table-filter/src/components/drop-button/drop-button.vue +224 -224
  500. package/packages/table-filter/src/components/drop-button/head-btn-icon.js +33 -33
  501. package/packages/table-filter/src/components/drop-view/drop-view.vue +89 -89
  502. package/packages/table-filter/src/components/multi-select/multi-select.vue +236 -236
  503. package/packages/table-filter/src/components/out-quick-search/out-quick-search.vue +346 -346
  504. package/packages/table-filter/src/components/range-age/index.vue +172 -172
  505. package/packages/table-filter/src/components/render-widget/components/CheckboxGroup.vue +51 -51
  506. package/packages/table-filter/src/components/render-widget/components/Select.vue +50 -50
  507. package/packages/table-filter/src/components/render-widget/components/index.js +7 -7
  508. package/packages/table-filter/src/components/render-widget/enums.js +28 -28
  509. package/packages/table-filter/src/components/render-widget/index.vue +91 -91
  510. package/packages/table-filter/src/components/render-widget/widgetCfgMaps.js +139 -139
  511. package/packages/table-filter/src/components/search-condition/SearchCondition.vue +1907 -1907
  512. package/packages/table-filter/src/components/search-condition/fieldTypeList.js +169 -169
  513. package/packages/table-filter/src/components/search-filter/SearchFilter.vue +278 -278
  514. package/packages/table-filter/src/components/search-modal/set-classification.vue +336 -336
  515. package/packages/table-filter/src/components/table-modal/TableModal.vue +477 -477
  516. package/packages/table-filter/src/const/dataOptions.js +43 -43
  517. package/packages/table-filter/src/const/index.js +1 -1
  518. package/packages/table-filter/src/index.vue +584 -584
  519. package/packages/table-filter/src/mixins/mixins.js +714 -714
  520. package/packages/table-filter/src/mixins/renderWidget.js +88 -88
  521. package/packages/table-filter/src/mixins/tableSearchCon.js +128 -128
  522. package/packages/table-filter/src/mixins/wordBookutils.js +113 -113
  523. package/packages/table-filter/src/quick-search/QuickSearch.vue +2167 -2167
  524. package/packages/tabs/index.js +18 -18
  525. package/packages/tabs/src/TabPane.jsx +11 -11
  526. package/packages/tabs/src/Tabs.jsx +11 -11
  527. package/packages/tag/index.js +21 -21
  528. package/packages/tag/src/CheckableTag.jsx +11 -11
  529. package/packages/tag/src/Tag.jsx +11 -11
  530. package/packages/tag/src/TagGroup.vue +621 -621
  531. package/packages/time-picker/index.js +12 -12
  532. package/packages/time-picker/src/TimePicker.jsx +11 -11
  533. package/packages/timeline/index.js +14 -14
  534. package/packages/timeline/src/Item.jsx +11 -11
  535. package/packages/timeline/src/Timeline.jsx +11 -11
  536. package/packages/tooltip/index.js +12 -12
  537. package/packages/tooltip/src/Tooltip.jsx +11 -11
  538. package/packages/transfer/index.js +12 -12
  539. package/packages/transfer/src/Transfer.jsx +11 -11
  540. package/packages/tree/index.js +18 -18
  541. package/packages/tree/src/Tree.jsx +11 -11
  542. package/packages/tree/src/TreeNode.jsx +11 -11
  543. package/packages/tree-select/index.js +18 -18
  544. package/packages/tree-select/src/TreeNode.jsx +11 -11
  545. package/packages/tree-select/src/TreeSelect.jsx +11 -11
  546. package/packages/upload/chunk-upload/chunk-upload-new.vue +1001 -1001
  547. package/packages/upload/chunk-upload/vod-chunk-upload.vue +749 -749
  548. package/packages/upload/chunk-upload/vod-upload-modal.vue +100 -100
  549. package/packages/upload/index.js +12 -12
  550. package/packages/upload/src/Upload.jsx +11 -11
  551. package/packages/verification-code/SlideVerify.vue +306 -306
  552. package/packages/verification-code/index.js +17 -17
  553. package/packages/verification-code/verification-code.vue +147 -147
  554. package/src/component/player-vod/index.vue +57 -57
  555. package/src/component/player-vod/player.vue +192 -192
  556. package/src/component/player-vod/video-list.vue +262 -262
  557. package/src/component/player-vod/video-modal.vue +128 -128
  558. package/src/component/select-options/index.vue +430 -430
  559. package/src/component/select-pages/index.vue +95 -95
  560. package/src/component/svg/index.vue +59 -59
  561. package/src/core/create.js +6 -6
  562. package/src/core/event.js +23 -23
  563. package/src/core/table-methods.js +444 -444
  564. package/src/directive/flexibleResize.js +151 -151
  565. package/src/directive/preventReClick.js +12 -12
  566. package/src/directive/scroll.js +230 -230
  567. package/src/global/variable.js +2 -2
  568. package/src/style/normalize.css +424 -424
  569. package/src/style/style.less +49 -49
  570. package/src/utils/UniRTCv2.js +626 -626
  571. package/src/utils/chatFetch.js +61 -61
  572. package/src/utils/clickoutside.js +75 -75
  573. package/src/utils/crypto.js +25 -25
  574. package/src/utils/index.js +81 -81
  575. package/src/utils/kty-sdk.js +582 -582
  576. package/src/utils/kty.min-1.0.0.js +14378 -14378
  577. package/src/utils/sip-device.js +79 -79
  578. package/src/utils/time-domain.js +249 -249
  579. package/src/utils/trtc.js +1 -1
  580. package/src/utils/utils-map.js +485 -485
  581. package/src/utils/vexutils.js +836 -836
  582. package/.idea/cnhis-design-vue.iml +0 -12
  583. package/.idea/codeStyles/Project.xml +0 -57
  584. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  585. package/.idea/git_toolbox_prj.xml +0 -15
  586. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  587. package/.idea/modules.xml +0 -8
  588. package/.idea/vcs.xml +0 -6
@@ -1,1647 +1,1647 @@
1
- <template>
2
- <a-layout-footer style="position: relative;cursor:pointer" v-show="!queueItem || !hideQueueBtns">
3
- <div class="message-operate">
4
- <a-upload
5
- v-if="isShow('PICTURE')"
6
- class="operate-icon"
7
- v-decorator="[
8
- 'upload',
9
- {
10
- valuePropName: 'fileList'
11
- }
12
- ]"
13
- :beforeUpload="beforeUpload"
14
- >
15
- <a-tooltip placement="top">
16
- <template slot="title">{{ i18nText('1.9.181') }}</template>
17
- <svg-icon icon-class="liaotiantupian1" class="toolbar"></svg-icon>
18
- </a-tooltip>
19
- </a-upload>
20
- <a-popover :title="i18nText('1.9.354')" trigger="click" v-model="visible">
21
- <a slot="content">
22
- <div class="emoji-wrapper">
23
- <p v-for="(item, index) in emojiList" :key="index" @click="() => handleEmojiClick(item)" :class="['twa', 'emoji', item]"></p>
24
- </div>
25
- </a>
26
-
27
- <a-tooltip placement="top">
28
- <template slot="title">{{ i18nText('1.9.354') }}</template>
29
- <svg-icon icon-class="liaotianbiaoqing1" @click="showEmoji" class="toolbar" v-if="isShow('SMILINEFACE')"></svg-icon>
30
- </a-tooltip>
31
- </a-popover>
32
- <template v-for="(item, index) in toolbar">
33
- <a-tooltip placement="top" :key="index">
34
- <template slot="title">{{ item.name }}</template>
35
- <svg-icon :icon-class="item.icon" class="toolbar" :class="{ 'closed-toolbar': closedSession }" @click="handleToolBarClick(item)"></svg-icon>
36
- </a-tooltip>
37
- </template>
38
- <!-- 快捷回复 -->
39
- <a-tooltip placement="top" :title="'快捷回复'">
40
- <a-popover trigger="click" overlayClassName="quick-reply" placement="topLeft" v-model="quickShow">
41
- <template slot="content">
42
- <quick-reply :quickShow.sync="quickShow" :quickData="quickData"></quick-reply>
43
- </template>
44
- <svg-icon icon-class="liaotiankuaijiehuifu1" class="toolbar" @click="openQuickData" v-if="isShow('FASTREPLY') && isServer"></svg-icon>
45
- </a-popover>
46
- </a-tooltip>
47
- <a-tooltip :title="'语音通话'">
48
- <svg-icon icon-class="liaotianyuyindianhua" @click="handleVideoClick('voice')" class="toolbar" v-if="isShow('VOICE_CALL')"></svg-icon>
49
- <!-- <img
50
- width="20"
51
- src="../img/multi-voice.png"
52
- @click="handleVideoClick('voice')"
53
- v-if="isShow('VOICE_CALL') && isServer"
54
- /> -->
55
- </a-tooltip>
56
- <a-tooltip :title="'发送语音'">
57
- <svg-icon icon-class="liaotianyuyin1" @click="handleVoice(true)" class="toolbar" :class="{ 'click-voice': showVoice }" v-if="isShow('VOICE')"></svg-icon>
58
- <!-- <img
59
- width="20"
60
- src="../img/multi-video.png"
61
- @click="handleVideoClick('video')"
62
- v-if="isShow('VIDEO') && isServer"
63
- /> -->
64
- </a-tooltip>
65
- <a-tooltip :title="'视频通话'">
66
- <svg-icon icon-class="liaotianshipin1" @click="handleVideoClick('video')" class="toolbar" v-if="isShow('VIDEO')"></svg-icon>
67
- <!-- <img
68
- width="20"
69
- src="../img/multi-video.png"
70
- @click="handleVideoClick('video')"
71
- v-if="isShow('VIDEO') && isServer"
72
- /> -->
73
- </a-tooltip>
74
- </div>
75
- <div class="message" style="text-align: left">
76
- <div class="content-edit">
77
- <div
78
- ref="contentEdit"
79
- @click="saveRange"
80
- @keyup.exact="saveRange"
81
- @change="changeData"
82
- @input="handleInput"
83
- @compositionstart="() => (this.ping = true)"
84
- @compositionend="() => (this.ping = false)"
85
- @keydown="handleKeyDown"
86
- @paste="handlePaste"
87
- contenteditable="true"
88
- ></div>
89
- </div>
90
- <span class="prompt">Enter {{ i18nText('1.2.1.11.6') }}, Ctrl + Enter {{ i18nText('1.9.356') }}</span>
91
- <a-button :disabled="sendDisabled" class="message-send" @click="handleMsgSend">{{ i18nText('1.2.1.11.6') }}</a-button>
92
- </div>
93
- <div id="canvas-wrapper" style="display: none">
94
- <canvas id="canvas"></canvas>
95
- </div>
96
- <template v-if="showOverlay">
97
- <div class="overlay" v-if="(!onChating || sessionEnd) && !queueItem"></div>
98
- </template>
99
- <div class="queue-page" v-if="queueItem">
100
- <div v-if="accessDesc" class="queue-tips">{{ accessDesc }}</div>
101
- <div class="queue-btns">
102
- <div v-if="enableTransfer" class="toSession" @click="handleOpenTransfer">
103
- {{ i18nText('1.10.201') }}
104
- </div>
105
- <div class="toSession primary" @click="handleAccess">
106
- {{ accessText || i18nText('1.9.352') }}
107
- </div>
108
- <div v-if="enableRefuse" class="toSession danger" @click="openRefuseReason">
109
- {{ i18nText('1.9.353') }}
110
- </div>
111
- </div>
112
- </div>
113
- <!-- 操作栏弹窗 -->
114
- <VuecmfDialog
115
- ref="vuecmfDialog"
116
- v-if="cmfModalShow"
117
- :class="isFullScreen ? 'chat-footer-modal-big' : 'chat-footer-modal-small'"
118
- :title="cmfModalData.name"
119
- :top="isFullScreen ? '0' : '10vh'"
120
- :width="isFullScreen ? '100%' : '80%'"
121
- :isFullScreen="isFullScreen"
122
- :okText="i18nText('1.2.1.11.6')"
123
- @close="handleClose"
124
- @ok="handleOk"
125
- >
126
- <iframe id="toolbarIframe" v-if="cmfModalData.targetType === 'LINK_ADDRESS'" width="100%" height="100%" frameborder="0" :src="modalData.address" allow="camera;midi"></iframe>
127
- </VuecmfDialog>
128
- <!-- <a-modal
129
- :wrapClassName="isFullScreen ? 'chat-footer-modal-big' : 'chat-footer-modal-small'"
130
- :title="modalData.name"
131
- :visible="modalShow"
132
- :maskClosable="false"
133
- :mask="true"
134
- :width="isFullScreen ? '100%' : '80%'"
135
- destroyOnClose
136
- :okText="i18nText('1.2.1.11.6')"
137
- :footer="null"
138
- @cancel="handleClose"
139
- @ok="handleOk"
140
- >
141
- <iframe id="toolbarIframe" v-if="modalData.targetType === 'LINK_ADDRESS'" width="100%" height="100%" frameborder="0" :src="modalData.address" allow="camera;midi"></iframe>
142
- </a-modal> -->
143
- <!-- 接入拦截 -->
144
- <a-modal
145
- :title="accessInterceptTitle"
146
- :visible="accessIntercept"
147
- :maskClosable="false"
148
- :mask="true"
149
- :footer="null"
150
- destroyOnClose
151
- :width="600"
152
- :bodyStyle="{ height: '280px' }"
153
- @cancel="
154
- () => {
155
- this.accessIntercept = false;
156
- }
157
- "
158
- >
159
- <iframe width="100%" height="100%" frameborder="0" :src="accessInterceptUrl"></iframe>
160
- </a-modal>
161
- <!-- 语音消息 -->
162
- <voice v-if="showVoice" :showVoice="showVoice" @closeVoice="handleVoice"></voice>
163
- <ModalUserTransfer v-if="enableTransfer" :title="i18nText('1.10.201')" :visible.sync="transferVisible" :assemblyId="assemblyId" @ok="handleTransfer" />
164
- <ModalRefuseReason v-if="refuseVisible" :visible.sync="refuseVisible" :reasonList="refuseReasonList" @ok="handleRefuse" />
165
- </a-layout-footer>
166
- </template>
167
-
168
- <script>
169
- import { Layout, Tooltip, Upload, Modal, Popover, Button } from 'ant-design-vue';
170
- import SvgIcon from '@/component/svg/index.vue';
171
- import ImageCompress from '../utils/compressImage';
172
- import { parseParams } from '../utils/panelsetting';
173
-
174
- import { mapState, mapGetters, mapMutations, mapActions } from '../store/helper';
175
- import fetch, { qs } from '@/utils/chatFetch';
176
- import QuickReply from './quickReply';
177
- import voice from './voice';
178
- import ModalUserTransfer from '../components/modal-user-transfer';
179
- import ModalRefuseReason from '../components/modal-refuse-reason';
180
- import VuecmfDialog from '../components/vuecmf-dialog.vue';
181
- import vexutils from '@/utils/vexutils';
182
- export default {
183
- inject: ['store', 'i18nText', 'dispatchEvent', 'registerEvent', 'unregisterEvent'],
184
- components: {
185
- AModal: Modal,
186
- [Layout.Footer.name]: Layout.Footer,
187
- [Tooltip.name]: Tooltip,
188
- [Upload.name]: Upload,
189
- [Button.name]: Button,
190
- [Popover.name]: Popover,
191
- SvgIcon,
192
- ModalRefuseReason,
193
- ModalUserTransfer,
194
- QuickReply,
195
- voice,
196
- VuecmfDialog
197
- },
198
- props: {
199
- // 隐藏排队状态底部信息
200
- hideQueueBtns: {
201
- type: Boolean,
202
- default: false
203
- },
204
- validTalkingEnv: {
205
- type: Function
206
- },
207
- curChatType: {
208
- type: String
209
- },
210
- clientFinish: {
211
- type: Boolean,
212
- default: true
213
- },
214
- addvisible: {
215
- type: Boolean,
216
- default: false
217
- },
218
- isShowVoice: {
219
- type: Boolean,
220
- default: false
221
- }
222
- },
223
- data() {
224
- return {
225
- // message: "",
226
- visible: false,
227
- modalShow: false,
228
- modalData: {},
229
- ping: false,
230
- templateId: null, // 卡片模板
231
- isFullScreen: false,
232
- emojiList: require('../utils/emoji.json'),
233
- quickData: [],
234
- quickShow: false,
235
- screenshot: false,
236
- screenshotFile: null,
237
- timer: null,
238
- accessIntercept: false,
239
- curToolbarItem: {},
240
- showVoice: false,
241
- transferVisible: false,
242
- refuseVisible: false,
243
-
244
- apiResult: {}, // 前置条件的返回值
245
- };
246
- },
247
- computed: {
248
- ...mapGetters([
249
- 'userInfo',
250
- 'assemblyId',
251
- 'sessionId',
252
- 'serviceId',
253
- 'onChating',
254
- 'roomId',
255
- 'isServer',
256
- 'assemblySetting',
257
- 'chatType',
258
- 'sessionEnd',
259
- 'closedSession',
260
- 'clientParams',
261
- 'footerMessage',
262
- 'queueItem',
263
- 'sessionType',
264
- 'groupMembers',
265
- 'curScrollItem',
266
- 'modalType',
267
- 'cmfModalShow',
268
- 'cmfModalData'
269
- ]),
270
- ...mapState({
271
- classify: state => state.lastClassify || state.classify
272
- }),
273
- message() {
274
- return this.footerMessage;
275
- },
276
- sendDisabled() {
277
- return this.message.length === 0;
278
- },
279
- orgId() {
280
- return this.userInfo?.sysParams?.orgId;
281
- },
282
- userId() {
283
- return this.userInfo?.sysParams?.userId;
284
- },
285
- toolbar() {
286
- if (!this.isServer) return [];
287
- let toolbar = this.assemblySetting.toolbar || [];
288
- toolbar = toolbar.filter(item => {
289
- const { source, isChecked, isCloseChecked, isClosedAble } = item;
290
- if (source === 'PC' && (
291
- (!this.closedSession && isChecked === 'Y') ||
292
- (this.closedSession && isCloseChecked === 'Y' && isChecked === 'Y' && isClosedAble === 'Y')
293
- )
294
- ){
295
- const showCondition = item.showCondition || [];
296
- const i = showCondition.findIndex(({ p_name, p_value }) => {
297
- const params = this.clientParams;
298
- const value = params[p_name];
299
- if (p_value.startsWith('form.')) {
300
- return value !== p_name[p_value.slice(5)];
301
- }
302
- return value !== p_value;
303
- });
304
- return i < 0;
305
- }
306
- return false;
307
- });
308
- return toolbar;
309
- },
310
- isListClassify() {
311
- return this.assemblySetting.isListClassify === 'Y';
312
- },
313
- showOverlay() {
314
- return this.curChatType != 'robot' || this.clientFinish;
315
- },
316
- accessText() {
317
- let obj = this.assemblySetting.serverSetting.serverInfo.filter(item => item.key === 'ongoingButton')[0];
318
- return obj?.value;
319
- },
320
- accessDesc() {
321
- let obj = this.assemblySetting.serverSetting.serverInfo.filter(item => item.key === 'ongoingDescription')[0];
322
- return obj?.value;
323
- },
324
- accessInterceptObj() {
325
- let obj = this.assemblySetting.accessInterceptSetting?.filter(item => item.source === 'PC');
326
- if (obj && obj[0]) {
327
- return obj[0];
328
- }
329
- return undefined;
330
- },
331
- // 拦截url
332
- accessInterceptUrl() {
333
- const { accessInterceptObj: obj, apiResult } = this;
334
- if (obj) {
335
- return this.getLinkAddress(obj,{result:apiResult});
336
- }
337
- return '';
338
- },
339
- // 拦截title
340
- accessInterceptTitle() {
341
- const { accessInterceptObj: obj } = this;
342
- if (obj) {
343
- let res = obj.titleI18n ? this.i18nText(obj.titleI18n) : obj.title;
344
- return res || '接入拦截';
345
- }
346
- return '接入拦截';
347
- },
348
- // 是否开启 排队转接
349
- enableTransfer() {
350
- if (this.assemblySetting.type === 'single') {
351
- let setting = null;
352
- if (this.isListClassify) {
353
- const classify = this.classify;
354
- const { listClassify = [] } = this.assemblySetting;
355
- const target = listClassify.find(item => item.classify === classify);
356
- setting = target ? target.serverFunctionSetting : null;
357
- } else {
358
- setting = this.assemblySetting?.serverSetting?.functionSetting;
359
- }
360
- if (setting) {
361
- const v = setting.find(item => item.function === 'TRANSFER_BEFORE');
362
- return v ? v.isChecked == 'Y' : false;
363
- }
364
- }
365
- return false;
366
- },
367
- enableRefuse() {
368
- let setting = null;
369
- if (this.isListClassify) {
370
- const classify = this.classify;
371
- const { listClassify = [] } = this.assemblySetting;
372
- const target = listClassify.find(item => item.classify === classify);
373
- setting = target ? target.serverFunctionSetting : null;
374
- } else {
375
- setting = this.assemblySetting?.serverSetting?.functionSetting;
376
- }
377
- if (setting) {
378
- const v = setting.find(item => item.function === 'ACCESS_REFUSE');
379
- return v ? v.isChecked == 'Y' : false;
380
- }
381
- return false;
382
- },
383
- refuseReasonList() {
384
- const list = this.assemblySetting?.refuseReasonSetting?.list || [];
385
- return list.filter(v => !!v.text);
386
- }
387
- },
388
-
389
- mounted() {
390
- this.bindEvents();
391
- },
392
- methods: {
393
- ...mapMutations([
394
- 'setLastClassify',
395
- 'setSessionTimer',
396
- 'setScrollQueueId',
397
- 'setCurScrollItem',
398
- 'setIsAppendMsg',
399
- 'setMessage',
400
- 'setShowVideo',
401
- 'setCaller',
402
- 'setMedicalOrPrescription',
403
- 'setModalVisible',
404
- 'setFooterMessage',
405
- 'setQueueItem',
406
- 'setSessionId',
407
- 'setCurrentTab',
408
- 'setClientId',
409
- 'setOnChating',
410
- 'setClientParams',
411
- 'setSessionHistoryList',
412
- 'setSessionEnd',
413
- 'setQuestionId',
414
- 'setDictionaryKey',
415
- 'setMultiVideoShow',
416
- 'setVideoStatus',
417
- 'setVideoMode',
418
- 'setAddMemberType',
419
- 'setShowAudio',
420
- 'setVideoMembers',
421
- 'setLastCurrentTab',
422
- 'setIsRecorderVoice',
423
- 'setVideoData',
424
- 'setSessionType',
425
- 'setCallerStatus',
426
- 'setModalType',
427
- 'setCmfModalShow',
428
- 'setCmfModalData'
429
- ]),
430
- ...mapMutations({
431
- clearMsgList: 'setMsgList'
432
- }),
433
- ...mapActions(['sendMessage', 'sendRobotMessage', 'handleBotChat', 'setMsgList', 'setChatTimer']),
434
- deleteStyle(value) {
435
- // 去掉样式
436
- value = value.replace(/style\s*?=\s*?(['"])[\s\S]*?\1/g, '');
437
- value = value.replace(/data\s*?=\s*?(['"])[\s\S]*?\1/g, '');
438
- value = value.replace(/class\s*?=\s*?(['"])[\s\S]*?\1/g, match => {
439
- if (match.includes('twa')) {
440
- return match;
441
- } else {
442
- return '';
443
- }
444
- });
445
- value = value.replace(/face\s*?=\s*?(['"])[\s\S]*?\1/g, '');
446
- value = value.replace(/<a/g, '<span');
447
- value = value.replace(/a>/g, 'span>');
448
- value = value.replace(/<i/g, '<span');
449
- value = value.replace(/i>/g, 'span>');
450
- value = value.replace(/<u/g, '<span');
451
- value = value.replace(/u>/g, 'span>');
452
- value = value.replace(/<strong/g, '<span');
453
- value = value.replace(/strong>/g, 'span>');
454
- value = value.replace(/<h\d/g, '<span');
455
- value = value.replace(/h\d>/g, 'span>');
456
- value = value.replace(/<b>/g, '<span>');
457
- value = value.replace(/b>/g, 'span>');
458
- value = value.replace(/<font/g, '<span');
459
- value = value.replace(/font>/g, 'span>');
460
- return value;
461
- },
462
- // 更新 message值 (未用v-html,修改后需要手动设置聊天框html内容)
463
- updateMessage(value) {
464
- this._editValue = value;
465
- this.setFooterMessage(`${value}`);
466
- const editRef = this.$refs.contentEdit;
467
- if (!editRef) return;
468
- editRef.innerHTML = value;
469
- },
470
- // 根据 聊天框 html节点内容 设置 message值 (未用v-html,html内容更改需主动设置message值)
471
- setMessageByHTML() {
472
- const editRef = this.$refs.contentEdit;
473
- if (!editRef) return;
474
- const message = editRef.innerHTML;
475
- this._editValue = message;
476
- this.setFooterMessage(`${message}`);
477
- },
478
-
479
- showEmoji() {
480
- // this.visible = true;
481
- },
482
-
483
- isShow(type) {
484
- if (type === 'SMILINEFACE' && this.curChatType === 'robot') return true;
485
- if (this.isListClassify) {
486
- let label;
487
- if (this.isServer) {
488
- label = 'serverFunctionSetting';
489
- } else {
490
- label = 'clientFunctionSetting';
491
- }
492
- let classifyItem = this.assemblySetting.listClassify.filter(item => item.classify === this.classify);
493
- if (!classifyItem || !classifyItem.length) return;
494
- let funs = classifyItem[0][label] || [];
495
- return funs.find(item => item.function === type)?.isChecked === 'Y';
496
- }
497
- let label;
498
- if (this.isServer) {
499
- label = 'serverSetting';
500
- } else {
501
- label = 'clientSetting';
502
- }
503
- let funs = this.assemblySetting[label]?.functionSetting || [];
504
- return funs.find(item => item.function === type)?.isChecked === 'Y';
505
- },
506
-
507
- handleEmojiClick(item) {
508
- let emojiHtml = `<p contenteditable="false" class="twa emoji ${item}"></p>&nbsp`;
509
- this.insertToEdit(emojiHtml);
510
- },
511
- /* edit-content光标定位 */
512
- resetSelection() {
513
- let edit = this.$refs.contentEdit;
514
- let sel, range;
515
- if (window.getSelection && document.createRange) {
516
- range = document.createRange();
517
- range.selectNodeContents(edit);
518
- range.collapse(true);
519
- range.setEnd(edit, edit.childNodes.length);
520
- range.setStart(edit, edit.childNodes.length);
521
- sel = window.getSelection();
522
- sel.removeAllRanges();
523
- sel.addRange(range);
524
- }
525
- },
526
-
527
- insertToEdit(value, isEditing) {
528
- const { _editSel, _editRange } = this;
529
- let sel, range;
530
- if (window.getSelection) {
531
- if (!isEditing) {
532
- if (_editRange) {
533
- sel = _editSel;
534
- range = _editRange;
535
- } else {
536
- // 初始状态没有focus聊天框,需要手动focus 获取光标位置
537
- const editRef = this.$refs.contentEdit;
538
- if (!editRef) return;
539
- editRef.focus();
540
- this.saveRange();
541
- sel = this._editSel;
542
- range = this._editRange;
543
- }
544
- } else {
545
- sel = window.getSelection();
546
- range = sel.getRangeAt(0);
547
- }
548
- range.deleteContents();
549
- let frag;
550
- if (range.createContextualFragment) {
551
- frag = range.createContextualFragment(value);
552
- } else {
553
- const el = document.createElement('div');
554
- el.innerHTML = value;
555
- frag = document.createDocumentFragment();
556
- let node, lastNode;
557
- while ((node = el.firstChild)) {
558
- lastNode = frag.appendChild(node); // 之所以能终止循环,是因为el的child一旦添加到dom后,作为fragment里的的child就没了。那么el.firstChild就会返回null
559
- }
560
- }
561
- const lastNode = frag.lastChild;
562
- range.insertNode(frag);
563
- // 把光标挪到插入的元素后面
564
- range.setStartAfter(lastNode);
565
- sel.removeAllRanges();
566
- sel.addRange(range);
567
- } else {
568
- range = isEditing || !_editRange ? document.selection.createRange() : _editRange;
569
- range.pasteHTML(value);
570
- range.select();
571
- }
572
- this.setMessageByHTML();
573
- },
574
- saveRange() {
575
- if (window.getSelection) {
576
- this._editSel = window.getSelection();
577
- this._editRange = this._editSel.getRangeAt(0);
578
- } else {
579
- this._editRange = document.selection.createRange();
580
- }
581
- },
582
- handleInput(e) {
583
- if (e.inputType === 'deleteContentBackward') {
584
- this.screenshot = false;
585
- this.screenshotFile = null;
586
- }
587
- setTimeout(() => {
588
- if (this.ping || this.pasteTimer) return;
589
- this.setMessageByHTML();
590
- }, 0);
591
- },
592
- changeData(e) {
593
- let message = e.srcElement.innerHTML;
594
- if (e.inputType === 'deleteContentBackward') {
595
- let div = document.createElement('div');
596
- div.innerHTML = e.srcElement.innerHTML;
597
- if (div.lastChild?.className?.startsWith('twa emoji')) {
598
- div.removeChild(div.lastChild);
599
- message = div.innerHTML;
600
- }
601
- this.screenshot = false;
602
- this.screenshotFile = null;
603
- }
604
-
605
- setTimeout(() => {
606
- if (this.ping) return;
607
- this.setFooterMessage(`${message}`);
608
- this.$nextTick().then(() => {
609
- this.resetSelection();
610
- this.ping = false;
611
- });
612
- }, 0);
613
- },
614
-
615
- beforeUpload(data) {
616
- let { type } = data;
617
- if (!type.startsWith('image/')) {
618
- this.$message.warning(`${this.i18nText('1.9.357')}!`);
619
- return;
620
- }
621
- let that = this;
622
- this.$confirm({
623
- title: this.i18nText('1.9.331'),
624
- content: `${this.i18nText('1.9.358')}?`,
625
- okText: '确定',
626
- cancelText: '取消',
627
- onOk() {
628
- return that.uploadImg(data);
629
- },
630
- onCancel() {
631
- return false;
632
- }
633
- });
634
- },
635
-
636
- /* 压缩上传 */
637
- uploadImg(file) {
638
- const hide = this.$message.loading(`${this.i18nText('1.9.199')}...`, 0);
639
- new ImageCompress(file, 'canvas', fetch, {
640
- url: '/hospitalUpload/picture'
641
- })
642
- .execute()
643
- .then(({ data }) => {
644
- if (data.result === 'SUCCESS') {
645
- this.doMsgSend(1, data.map.url);
646
- hide();
647
- } else {
648
- hide();
649
- this.$message.info(data.msg || `${this.i18nText('1.9.174')}!`);
650
- }
651
- })
652
- .catch(() => {
653
- hide();
654
- this.$message.info(`${this.i18nText('1.9.174')}!`);
655
- })
656
- .finally(() => {
657
- this.screenshotFile = null;
658
- this.screenshot = false;
659
- this.updateMessage('');
660
- });
661
- },
662
-
663
- /* 发送消息 */
664
- doMsgSend(type, content) {
665
- let body = {
666
- content: type === 0 ? `<div>${content}</div>` : content,
667
- type: type
668
- };
669
- if (this.curChatType === 'robot') {
670
- // this.setQuestionId("");
671
- // this.setDictionaryKey("");
672
- this.sendRobotMessage(content);
673
- } else {
674
- this.sendMessage(body);
675
- }
676
- },
677
- handleMsgSend() {
678
- // 截图上传
679
- if (this.screenshot) {
680
- this.uploadImg(this.screenshotFile);
681
- return;
682
- }
683
- if (this.chatType === 'bot') {
684
- this.handleBotChat(this.message).then(isHuman => {
685
- if (isHuman) {
686
- this.$parent.$parent.$parent.initWebSocket();
687
- }
688
- this.updateMessage('');
689
- });
690
- return;
691
- }
692
-
693
- const editRef = this.$refs.contentEdit;
694
- if (editRef) {
695
- const message = editRef.innerText;
696
- if (message.length > 2000) {
697
- this.$message.warning('请控制在2000字以内!');
698
- return;
699
- }
700
- }
701
- // let reg = /(.*?)(<div><br><\/div>)*?$/;
702
- let reg = /(.*?)(<div>(<span>)?<br>(<\/span>)?<\/div>)*?$/;
703
- let message = this.message.match(reg);
704
- if (message[2]) {
705
- this.updateMessage(message[1]);
706
- }
707
- this.updateMessage(this.message.replace(/style/g, 'data'));
708
- if (this.message.trim()) {
709
- this.doMsgSend(0, this.message);
710
- } else {
711
- return this.$message.warning(this.i18nText('1.9.359'));
712
- }
713
- this.updateMessage('');
714
- },
715
- handleKeyDown(e) {
716
- // 判断enter 发送还是换行
717
- if (e.keyCode === 13) {
718
- e.preventDefault();
719
- if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
720
- this.handleWrap();
721
- } else {
722
- this.handleMsgSend();
723
- }
724
- }
725
- },
726
- handleWrap() {
727
- let ctn = `<br>`;
728
- // 非ie环境 元素后面没有node的时候换行需要两个<br>
729
- if (!/msie/.test(navigator.userAgent) && window.getSelection) {
730
- const focusNode = window.getSelection().focusNode;
731
- let nextSibling = focusNode.nextSibling;
732
- if (focusNode === this.$refs.contentEdit) {
733
- nextSibling = focusNode.childNodes[0];
734
- }
735
- do {
736
- if (!nextSibling || nextSibling.nodeValue || nextSibling.tagName == 'BR') break;
737
- } while ((nextSibling = nextSibling.nextSibling));
738
- if (!nextSibling) {
739
- ctn += ctn;
740
- }
741
- }
742
- this.insertToEdit(ctn);
743
- this.$nextTick().then(() => {
744
- this.ping = false;
745
- });
746
- },
747
- handleVideoClick(type) {
748
- this.setCallerStatus('')
749
- // this.curScrollItem.type 2多人 1单人
750
- if (this.sessionType === 2) {
751
- this.$emit('update:addvisible', true);
752
- this.setAddMemberType(2);
753
- this.setVideoMode(type === 'voice' ? 1 : 2);
754
- } else {
755
- const openTalking = sip => {
756
- this.setShowAudio(true);
757
- this.setVideoMode(type === 'voice' ? 1 : 2);
758
- this.$nextTick(() => {
759
- this.setVideoMembers([]);
760
- });
761
- this.setVideoData({
762
- callerSipKey: sip?.username,
763
- callerSipName: sip?.name
764
- });
765
- };
766
- if (this.validTalkingEnv) {
767
- this.validTalkingEnv().then(res => {
768
- if (res.status) {
769
- openTalking(res.sip);
770
- }
771
- });
772
- } else {
773
- openTalking();
774
- }
775
- }
776
- // this.groupMembers.length > 2
777
- return;
778
- },
779
- handleVoice(val) {
780
- val && this.setIsRecorderVoice(true);
781
- this.showVoice = val;
782
- },
783
- showPrescription() {
784
- this.setModalVisible(true);
785
- this.setMedicalOrPrescription('prescription');
786
- },
787
- showMedicalRecord() {
788
- this.setModalVisible(true);
789
- this.setMedicalOrPrescription('medical');
790
- },
791
- beofreToolBarClick(item) {
792
- // 操作栏前置条件
793
- return new Promise((resolve, reject) => {
794
- const { precondition } = item;
795
- if (precondition) {
796
- this.requestPreCondition(precondition)
797
- .then(res => {
798
- const result = res.data.result === 'SUCCESS';
799
- !result && this.$message.error(res.data.resultMsg || this.i18nText('1.9.22'));
800
- resolve(result);
801
- })
802
- .catch(error => {
803
- this.$message.error(error.resultMsg || this.i18nText('1.9.22'));
804
- resolve(false);
805
- });
806
- } else {
807
- resolve(true);
808
- }
809
- });
810
- },
811
- async handleToolBarClick(item) {
812
- console.log('item', item.key);
813
- console.log('toolbarItem', this.curScrollItem);
814
- console.log(this.curScrollItem.consultText);
815
- if (this.curScrollItem.consultText === '初诊' && ['prescription', 'prescription_new_his', 'prescription_his', 'medical_record', 'medical_record_new'].includes(item.key)) {
816
- this.$message.info('初诊病人仅支持咨询')
817
- return
818
- }
819
- if (item.key === this.modalType) {
820
- this.$refs.vuecmfDialog.toggleScreen()
821
- return
822
- }
823
- if (this.modalType && ['prescription', 'prescription_new_his', 'prescription_his', 'medical_record', 'medical_record_new', 'gauge'].includes(item.key)) {
824
- this.$message.info('请先关闭最小化弹窗后再进行操作')
825
- return
826
- }
827
- const validate = await this.beofreToolBarClick(item);
828
- if (!validate) return;
829
- let { openMode, name, templateId, isFullScreen } = item;
830
- this.dispatchEvent('click_toolbar', { ...item });
831
- if (!item.address) return;
832
- this.curToolbarItem = item;
833
- this.templateId = templateId;
834
- this.isFullScreen = isFullScreen === 'Y';
835
- let address = this.getLinkAddress(item);
836
- if (openMode === 'WINDOW') {
837
- window.open(address, name);
838
- return;
839
- }
840
- if (openMode === 'EJECT') {
841
- if (!this.modalType) {
842
- this.setModalType(item.key)
843
- this.setCmfModalShow(true);
844
- this.setCmfModalData(Object.assign({}, item, { address }))
845
- }
846
- this.modalData = Object.assign({}, item, { address });
847
- console.log('this.modalData', this.modalData);
848
- this.$nextTick().then(() => {
849
- window.addEventListener('message', this.iframeEvent);
850
- // window.onmessage = this.iframeEvent
851
- });
852
- return;
853
- }
854
- },
855
- iframeEvent(event) {
856
- const method = event?.data?.method;
857
- this[method]?.(event);
858
- },
859
- // 发送
860
- handleParentMessageSend({ data, source, origin }) {
861
- let params = {
862
- assemblyId: this.assemblyId,
863
- sessionId: this.sessionId,
864
- orgId: this.orgId
865
- };
866
- params = Object.assign(params, data.data);
867
- let { actionType } = this.curToolbarItem;
868
- actionType && Object.assign(params, { actionType });
869
- return fetch.post('/chat/access/sendToolBarData', qs.stringify(params)).then(({ data }) => {
870
- if (data.result === 'SUCCESS') {
871
- source.postMessage({ status: 0, resultMsg: data.resultMsg }, origin);
872
- } else {
873
- source.postMessage({ status: 1, resultMsg: data.resultMsg }, origin);
874
- }
875
- });
876
- },
877
- // 关闭
878
- handleClose() {
879
- this.setCmfModalShow(false);
880
- this.setModalType(null)
881
- this.setCmfModalData({})
882
- this.modalShow = false;
883
- window.removeEventListener('message', this.iframeEvent);
884
- // window.onmessage = null;
885
- },
886
- getLinkAddress(item,paramsData= {}) {
887
- let t = {talbe:{},form:{},sys:{}};
888
- Object.assign(t,paramsData ||{})
889
- let { address = '', params = [] } = item;
890
- let urlParams = [];
891
- params.forEach(({ p_name, p_value }) => {
892
- let value;
893
- if (p_value.startsWith('form.')) {
894
- value = this.clientParams[p_value.slice(5)];
895
- } else if( /\${result.(.*?)\}/g.test(p_value)) {
896
- value = vexutils.handleSysParams(p_value,t)
897
- } else {
898
- value = p_value;
899
- }
900
- urlParams.push(`${p_name}=${value}`);
901
- });
902
- if(/\${result.(.*?)\}/g.test(address)){
903
- address = vexutils.handleSysParams(address,t)
904
- }
905
- let { actionType } = this.curToolbarItem;
906
- actionType && urlParams.push(`actionType=${actionType}`);
907
- if (address.includes('?')) {
908
- address += `&${urlParams.join('&')}`;
909
- } else {
910
- address += `?${urlParams.join('&')}`;
911
- }
912
- return address;
913
- },
914
- handleOk() {
915
- window.handleParentMessageSend();
916
- },
917
- // 剪切板粘贴
918
- handlePaste(e) {
919
- const cbd = e.clipboardData;
920
- const ua = window.navigator.userAgent;
921
- // 如果是 Safari 直接 return
922
- if (!(e.clipboardData && e.clipboardData.items)) {
923
- this.handlePasteText(e);
924
- return;
925
- }
926
- if (
927
- cbd.items &&
928
- cbd.items.length === 2 &&
929
- cbd.items[0].kind === 'string' &&
930
- cbd.items[1].kind === 'file' &&
931
- cbd.types &&
932
- cbd.types.length === 2 &&
933
- cbd.types[0] === 'text/plain' &&
934
- cbd.types[1] === 'Files' &&
935
- ua.match(/Macintosh/i) &&
936
- Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49
937
- ) {
938
- this.handlePasteText(e);
939
- return;
940
- }
941
- const hasFile = this.handleImgPaste(cbd.items);
942
- if (hasFile) {
943
- e.stopPropagation();
944
- e.preventDefault();
945
- return;
946
- }
947
- this.handlePasteText(e);
948
- },
949
- handleImgPaste(files) {
950
- let hasFile = false;
951
- for (let i = 0; i < files.length; i++) {
952
- let item = files[i];
953
- if (item.kind == 'file') {
954
- hasFile = true;
955
- // blob 就是从剪切板获得的文件,可以进行上传或其他操作
956
- const blob = item.getAsFile();
957
- if (blob.size === 0) {
958
- return;
959
- }
960
- const reader = new FileReader();
961
- const imgs = new Image();
962
- imgs.file = blob;
963
- reader.onload = e => {
964
- imgs.src = e.target.result;
965
- imgs.width = '150';
966
- this.updateMessage(this.htmlToString(imgs));
967
- this.$nextTick().then(() => {
968
- this.resetSelection();
969
- this.screenshot = true;
970
- this.screenshotFile = blob;
971
- });
972
- };
973
- reader.readAsDataURL(blob);
974
- }
975
- }
976
- return hasFile;
977
- },
978
- // 处理文本粘贴
979
- handlePasteText() {
980
- if (this.pasteTimer) clearTimeout(this.pasteTimer);
981
- const ele = this.$refs.contentEdit;
982
- if (!ele) return;
983
- let before = ele.innerHTML;
984
- this.pasteTimer = setTimeout(() => {
985
- function getPasteHtml(before, after) {
986
- // 计算粘贴后html不同的位置起点和终点(插入"abc",则得出sPos为0,ePos为2)
987
- var sPos = -1,
988
- ePos = -1;
989
- for (var i = 0, len = after.length; i < len; ++i) {
990
- if (sPos == -1 && before.substr(i, 1) != after.substr(i, 1)) sPos = i;
991
- if (ePos == -1 && before.substr(before.length - i - 1, 1) != after.substr(after.length - i - 1, 1)) ePos = i;
992
-
993
- if ((sPos != -1 && ePos != -1) || len - 1 - ePos <= sPos) break;
994
- }
995
- if (sPos == -1 || ePos == -1) return;
996
- ePos = len - 1 - ePos;
997
-
998
- if (ePos <= sPos) {
999
- // 遇到像ab,粘贴ab后变成abab这种了,这是需要从sPos开始往后找,找到和before一样的为止
1000
- i = sPos;
1001
- var beforeSPosNext = before.substr(i + 1, 10); // 取后10个来对比,如果没有10个,则取最多
1002
- while (++i < len) {
1003
- if (beforeSPosNext == after.substr(i, beforeSPosNext.length)) {
1004
- ePos = i;
1005
- break;
1006
- }
1007
- }
1008
- i == len && (ePos = len - 1);
1009
- }
1010
- // 如果有<和>,则需要计算在内
1011
- if (after.substr(sPos - 1, 1) == '<') --sPos;
1012
- if (after.substr(ePos + 1, 1) == '>') ++ePos;
1013
-
1014
- // 分段获得文本,前半段 插入段 后半段
1015
- var pastedText = after.substring(sPos, ePos + 1),
1016
- formerText = after.substr(0, sPos),
1017
- latterText = after.substr(sPos + pastedText.length);
1018
-
1019
- // 判断formerText和pastedText是否闭合了
1020
- var lastLT = formerText.lastIndexOf('<'),
1021
- lastGT = formerText.lastIndexOf('>');
1022
- if (lastGT < lastLT) {
1023
- // 标签断了xxxxx<
1024
- pastedText = formerText.slice(lastLT) + pastedText;
1025
- formerText = formerText.slice(0, lastLT);
1026
- }
1027
-
1028
- lastLT = pastedText.lastIndexOf('<');
1029
- lastGT = pastedText.lastIndexOf('>');
1030
- if (lastGT < lastLT) {
1031
- // 标签断了<xxxxxx
1032
- var _insertGT = latterText.indexOf('>') + 1;
1033
- pastedText += latterText.slice(0, _insertGT);
1034
- latterText = latterText.slice(_insertGT);
1035
- }
1036
- return [formerText, pastedText, latterText];
1037
- }
1038
- var after = ele.innerHTML;
1039
- const data = getPasteHtml(before, after);
1040
- if (data) {
1041
- let [formerText, insertText, latterText] = data;
1042
- insertText = this.deleteStyle(insertText);
1043
- ele.innerHTML = formerText + insertText + "<span class='pasteCaretPosHelper'></span>" + latterText; // 插入pasteCaretPosHelper以帮助定位光标位置
1044
- var pasteCaretPosHelper = ele.querySelector('.pasteCaretPosHelper'),
1045
- range,
1046
- selection;
1047
- if (pasteCaretPosHelper) {
1048
- if (document.createRange) {
1049
- // Chrome, IE 9+
1050
- range = document.createRange();
1051
- range.setStartAfter(pasteCaretPosHelper);
1052
- range.collapse(false);
1053
- selection = window.getSelection();
1054
- selection.removeAllRanges();
1055
- selection.addRange(range);
1056
- } else if (document.selection) {
1057
- // IE 8 and lower
1058
- range = document.body.createTextRange();
1059
- range.moveToElementText(pasteCaretPosHelper);
1060
- range.collapse(false);
1061
- range.select();
1062
- }
1063
- pasteCaretPosHelper.parentNode.removeChild(pasteCaretPosHelper);
1064
- }
1065
- }
1066
- this.setMessageByHTML();
1067
- this.saveRange();
1068
- this.pasteTimer = null;
1069
- }, 50);
1070
- },
1071
- // 拖拽上传图片
1072
- handleFiles(files) {
1073
- this.handleImgPaste(files);
1074
- },
1075
- htmlToString(dom) {
1076
- let div = document.createElement('div');
1077
- div.appendChild(dom);
1078
- return div.innerHTML;
1079
- },
1080
- /**
1081
- * 接入拦截
1082
- */
1083
- handleAccessIntercept(result) {
1084
- let { data } = result;
1085
- let { status, data: param } = data;
1086
- if (status === 1) {
1087
- this.accessChat(param).finally(() => {
1088
- this.accessIntercept = false;
1089
- });
1090
- } else {
1091
- this.accessIntercept = false;
1092
- }
1093
- },
1094
- /* 客服点击接入按钮进入会话 */
1095
- async handleAccess() {
1096
- this.apiResult = {};
1097
- let accessInterceptValidate = this.handleAccessInterceptValue();
1098
- let data = null; // 接口参数
1099
- if (accessInterceptValidate && this.accessInterceptUrl) {
1100
- const r = await this.beforeAccessIntercept();
1101
- if (!r) return;
1102
- if (r.value == 'Y') {
1103
- this.accessIntercept = true;
1104
- this.$nextTick().then(() => {
1105
- window.addEventListener('message', this.handleAccessIntercept);
1106
- });
1107
- return;
1108
- } else {
1109
- data = r.data; // 获取接入拦截返回参数
1110
- }
1111
- }
1112
- clearTimeout(this.timer);
1113
- this.timer = setTimeout(() => {
1114
- this.accessChat(data);
1115
- }, 300);
1116
- },
1117
- // 条件转换请求
1118
- requestPreCondition(precondition) {
1119
- const { targetType, targetName, targetId, params } = precondition;
1120
- const data = parseParams(params, this.clientParams);
1121
- let url = '';
1122
- if (targetType === 'API') {
1123
- data.url = targetName;
1124
- url = `/api/executeApi`;
1125
- } else {
1126
- data.sqlEnterId = targetId;
1127
- url = `/form/saveSqlEnter`;
1128
- }
1129
- return fetch.post(url, qs.stringify(data));
1130
- },
1131
- async beforeAccessIntercept() {
1132
- function parseResult(r) {
1133
- let value = 'Y';
1134
- const data = r.split('&').reduce((obj, str) => {
1135
- const [k, v] = str.split('=');
1136
- if (k) {
1137
- if (k == 'value') {
1138
- value = v || value;
1139
- } else {
1140
- obj = obj || {};
1141
- obj[k] = v || '';
1142
- }
1143
- }
1144
- return obj;
1145
- }, null);
1146
- return {
1147
- value,
1148
- data
1149
- };
1150
- }
1151
- this.apiResult = {};
1152
- const accessInterceptSetting = this.assemblySetting.accessInterceptSetting || [];
1153
- const setting = accessInterceptSetting.find(item => item.source == 'PC' && item.isChecked == 'Y' && item.precondition);
1154
- if (setting) {
1155
- const precondition = setting.precondition;
1156
- try {
1157
- let res = await this.requestPreCondition(precondition);
1158
- this.apiResult = res?.data?.map || {};
1159
- if (res.data.result === 'SUCCESS') {
1160
- let value = res.data.map?.result;
1161
- value = value ? JSON.parse(value) : {};
1162
- return value.value ? parseResult(value.value) : false;
1163
- } else {
1164
- this.$message.error(res.data.resultMsg || this.i18nText('1.9.22'));
1165
- return false;
1166
- }
1167
- } catch (error) {
1168
- this.$message.error(error.resultMsg || this.i18nText('1.9.22'));
1169
- return false;
1170
- }
1171
- }
1172
- return {
1173
- value: 'Y',
1174
- data: null
1175
- };
1176
- },
1177
- handleAccessInterceptValue() {
1178
- let { listClassify = [], isListClassify, serverSetting = {} } = this.assemblySetting;
1179
- let list = [];
1180
- if (isListClassify != 'Y') {
1181
- let { functionSetting = [] } = serverSetting;
1182
- list = functionSetting;
1183
- } else {
1184
- let curList = listClassify.find(item => item.classify == this.classify);
1185
- if (!curList) return false;
1186
- list = curList.serverFunctionSetting || [];
1187
- }
1188
- if (!list.length) return true;
1189
- let curItem = list.find(item => item.function == 'ACCESS_INTERCEPT');
1190
- if (!curItem) return true;
1191
- return curItem.isChecked == 'Y';
1192
- },
1193
- accessChat(data) {
1194
- let { bid: userId, username, userType } = this.queueItem;
1195
- let params = {
1196
- assemblyId: this.assemblyId,
1197
- userId,
1198
- userType,
1199
- lastSessionId: this.sessionId,
1200
- relateId: this.clientParams.relateId
1201
- };
1202
- if (data) {
1203
- params.addParams = JSON.stringify(data);
1204
- }
1205
- return fetch.post('/chat/service/accessChat', qs.stringify(params)).then(({ data }) => {
1206
- if (data.result === 'SUCCESS') {
1207
- let { countdown, clientParams, sessionType, countdownDesc } = data.map;
1208
- this.setSessionId(data.map.sessionId);
1209
- this.clearMsgList();
1210
- this.setMsgList();
1211
- this.setCurrentTab('session');
1212
- this.setLastCurrentTab('session');
1213
- this.setClientId(username);
1214
- this.setOnChating(true);
1215
- this.setSessionEnd(false);
1216
- this.setQueueItem(null);
1217
- // 设置问诊类型
1218
- this.setCurScrollItem({ ...this.curScrollItem, consultText: clientParams.text})
1219
- sessionType && this.setSessionType(sessionType);
1220
- if (countdown >= 0) {
1221
- this.setChatTimer({ countdown, countdownDesc });
1222
- }
1223
- this.setClientParams(clientParams);
1224
- this.getSessionHistoryList();
1225
- this.dispatchEvent('user_accessSuccess', {
1226
- map: data.map,
1227
- user: { ...this.curScrollItem }
1228
- });
1229
- } else {
1230
- this.$message.warning(data.resultMsg);
1231
- }
1232
- });
1233
- },
1234
- handleOpenTransfer() {
1235
- if (this.enableTransfer) {
1236
- this.transferVisible = true;
1237
- }
1238
- },
1239
- handleTransfer(data) {
1240
- const receiveId = data.converUserId;
1241
- if (receiveId) {
1242
- if (this.userId == receiveId) {
1243
- this.$message.warning(this.i18nText('1.2.7.14.1'));
1244
- return;
1245
- }
1246
- this.transferVisible = false;
1247
- fetch({
1248
- url: '/chat/service/transferQueue',
1249
- method: 'POST',
1250
- data: qs.stringify({
1251
- relateId: this.clientParams.relateId,
1252
- orgId: this.orgId,
1253
- assemblyId: this.assemblyId,
1254
- userId: this.curScrollItem?.bid,
1255
- userType: this.curScrollItem?.userType || '',
1256
- receiveId: receiveId,
1257
- deptId: data.deptId,
1258
- remark: data.converMark
1259
- })
1260
- })
1261
- .then(({ data }) => {
1262
- if (data.result === 'SUCCESS') {
1263
- this.dispatchEvent('user_transferQueueSuccess', {
1264
- user: { ...this.curScrollItem }
1265
- });
1266
- this.$message.success(this.i18nText('1.9.336'));
1267
- this.clearCurrentSession(true);
1268
- } else {
1269
- this.$message.warning(data.resultMsg || this.i18nText('1.10.201') + this.i18nText('1.9.22'));
1270
- }
1271
- })
1272
- .catch(err => {
1273
- this.$message.warning(err.resultMsg || this.i18nText('1.10.201') + this.i18nText('1.9.22'));
1274
- });
1275
- } else {
1276
- this.$message.warning(this.i18nText('1.9.335'));
1277
- }
1278
- },
1279
- getSessionHistoryList() {
1280
- this.setSessionHistoryList([]);
1281
- if (this.assemblySetting.recordScopeSetting === 'CURRENT') return;
1282
- fetch
1283
- .get('/chat/service/getPastSessionList', {
1284
- params: { sessionId: this.sessionId }
1285
- })
1286
- .then(({ data }) => {
1287
- if (data.result === 'SUCCESS') {
1288
- let list = data.list.map(item => {
1289
- if (item.id === this.sessionId || this.type === 'session') {
1290
- item.onChating = true;
1291
- }
1292
- return item;
1293
- });
1294
- this.setSessionHistoryList(list);
1295
- }
1296
- });
1297
- },
1298
- openQuickData() {
1299
- // this.quickShow = true;
1300
- if (this.quickData.length < 1) {
1301
- fetch
1302
- .get('/fastReply/getChatList', {
1303
- params: {
1304
- category: this.assemblySetting.chatPublicCategory
1305
- }
1306
- })
1307
- .then(({ data }) => {
1308
- if (data.result === 'SUCCESS') {
1309
- this.quickData = data.list;
1310
- }
1311
- });
1312
- }
1313
- },
1314
- // 清除当前会话
1315
- clearCurrentSession(update = false) {
1316
- this.clearMsgList([]);
1317
- this.setSessionHistoryList([]);
1318
- this.setSessionTimer('');
1319
- this.setClientId('');
1320
- this.setSessionId('');
1321
- this.setScrollQueueId('');
1322
- this.setLastClassify('');
1323
- this.setCurScrollItem(null);
1324
- this.setQueueItem(null);
1325
- this.setClientParams(null);
1326
- if (update) {
1327
- // 重新设置 currentTab 触发 scrollList 组件 更新排队列表
1328
- const currentTab = this.store.state?.currentTab;
1329
- if (currentTab === 'queue') {
1330
- this.setCurrentTab('');
1331
- this.$nextTick(() => {
1332
- this.setCurrentTab(this.store.state?.currentTab || currentTab);
1333
- });
1334
- }
1335
- }
1336
- },
1337
- openRefuseReason() {
1338
- if (this.enableRefuse) {
1339
- this.refuseVisible = true;
1340
- }
1341
- },
1342
- handleRefuse(remark) {
1343
- if (!this.enableRefuse) return;
1344
- fetch({
1345
- url: '/chat/service/accessRefuse',
1346
- method: 'POST',
1347
- data: qs.stringify({
1348
- relateId: this.clientParams.relateId,
1349
- orgId: this.orgId,
1350
- assemblyId: this.assemblyId,
1351
- userId: this.curScrollItem?.bid,
1352
- userType: this.curScrollItem?.userType || '',
1353
- remark: remark || '其他'
1354
- })
1355
- })
1356
- .then(({ data }) => {
1357
- if (data.result === 'SUCCESS') {
1358
- this.dispatchEvent('user_refuseSuccess', {
1359
- user: { ...this.curScrollItem }
1360
- });
1361
- this.$message.success(this.i18nText('1.10.184'));
1362
- this.clearCurrentSession(true);
1363
- } else {
1364
- this.$message.warning(data.resultMsg || this.i18nText('1.9.353') + this.i18nText('1.9.22'));
1365
- }
1366
- })
1367
- .catch(err => {
1368
- this.$message.warning(err.resultMsg || this.i18nText('1.9.353') + this.i18nText('1.9.22'));
1369
- });
1370
- this.refuseVisible = false;
1371
- },
1372
- bindEvents() {
1373
- const handleDrop = e => {
1374
- e.stopPropagation();
1375
- e.preventDefault();
1376
- this.handleFiles(e.dataTransfer.items);
1377
- };
1378
- document.addEventListener('drop', handleDrop, false);
1379
- this.registerEvent('accessCurrentSession', this.handleAccess);
1380
- this.registerEvent('refuseCurrentSession', this.openRefuseReason);
1381
- this.registerEvent('transferCurrentQueueSession', this.handleOpenTransfer);
1382
- this.registerEvent('transferUserQueueSessionOuting', this.handleTransfer);
1383
- this.$on('hook:beforeDestroy', () => {
1384
- document.removeEventListener('drop', handleDrop, false);
1385
- window.removeEventListener('message', this.iframeEvent);
1386
- window.removeEventListener('message', this.handleAccessIntercept);
1387
- this.unregisterEvent('accessCurrentSession', this.handleAccess);
1388
- this.unregisterEvent('refuseCurrentSession', this.openRefuseReason);
1389
- this.unregisterEvent('transferCurrentQueueSession', this.handleOpenTransfer);
1390
- this.unregisterEvent('transferUserQueueSessionOuting', this.handleTransfer);
1391
- });
1392
- }
1393
- },
1394
- watch: {
1395
- accessIntercept: {
1396
- handler(val) {
1397
- if (!val) {
1398
- window.removeEventListener('message', this.handleAccessIntercept);
1399
- }
1400
- }
1401
- },
1402
- message: {
1403
- handler(v) {
1404
- // 使用 _editValue 判断是否组件外修改 message,并更新聊天框
1405
- if (this._editValue !== v) {
1406
- this.updateMessage(v);
1407
- }
1408
- }
1409
- }
1410
- }
1411
- };
1412
- </script>
1413
-
1414
- <style lang="less">
1415
- .chat-footer-modal-big {
1416
- padding: 10px;
1417
- &.ant-modal-wrap {
1418
- overflow: none;
1419
- }
1420
- .ant-modal {
1421
- width: 100%;
1422
- height: 100%;
1423
- top: 0;
1424
- padding-bottom: 0;
1425
- }
1426
- .ant-modal-content {
1427
- height: 100%;
1428
- }
1429
- .ant-modal-body {
1430
- height: calc(100% - 55px);
1431
- }
1432
- }
1433
- .chat-footer-modal-small {
1434
- &.ant-modal-wrap {
1435
- overflow: none;
1436
- }
1437
- .ant-modal {
1438
- width: 80%;
1439
- height: 80%;
1440
- padding-bottom: 0;
1441
- top: 60px;
1442
- }
1443
- .ant-modal-content {
1444
- height: 100%;
1445
- }
1446
- .ant-modal-body {
1447
- height: 100%;
1448
- padding: 0;
1449
- }
1450
- }
1451
-
1452
- </style>
1453
- <style lang="less" scoped>
1454
- .message-operate {
1455
- display: flex;
1456
- align-items: center;
1457
- height: 40px;
1458
- line-height: 18px;
1459
- background: #fff;
1460
- overflow-x: auto;
1461
- overflow-y: hidden;
1462
- border-top: 1px solid #e6e6e6;
1463
- &::-webkit-scrollbar {
1464
- height: 5px;
1465
- }
1466
- > img {
1467
- // > .operate-icon {
1468
- margin-left: 10px;
1469
- }
1470
- /deep/ .ant-tabs .ant-tabs-top-content > .ant-tabs-tabpane {
1471
- height: 300px !important;
1472
- overflow: auto !important;
1473
- }
1474
- /deep/ .ant-upload-list {
1475
- display: none;
1476
- }
1477
- /deep/ .ant-upload {
1478
- height: 32px;
1479
- vertical-align: middle;
1480
- display: inline-block;
1481
- }
1482
- .no-click {
1483
- pointer-events: none;
1484
- opacity: 0.4;
1485
- }
1486
- .svg-icon {
1487
- color: rgba(0, 0, 0, 0.6);
1488
- }
1489
- }
1490
- .emoji-wrapper {
1491
- width: 500px;
1492
- height: 300px;
1493
- overflow: auto;
1494
- display: grid;
1495
- grid-template-columns: repeat(10, 1fr);
1496
- .emoji {
1497
- display: inline-block;
1498
- font-size: 20px;
1499
- margin: 10px;
1500
- text-align: center;
1501
- }
1502
- &::-webkit-scrollbar {
1503
- width: 5px;
1504
- }
1505
- }
1506
- .message {
1507
- position: relative;
1508
- height: 150px;
1509
- .message-send {
1510
- position: absolute;
1511
- bottom: 8px;
1512
- right: 14px;
1513
- height: 40px;
1514
- border-radius: 20px;
1515
- width: 86px;
1516
- font-weight: 600;
1517
- font-size: 18px;
1518
- color: #fff;
1519
- background-color: @primary-color;
1520
- border-color: @primary-color;
1521
- &:hover {
1522
- background-color: rgba(@primary-color, 0.7);
1523
- border-color: rgba(@primary-color, 0.7);
1524
- }
1525
- &[disabled]:hover,
1526
- &[disabled] {
1527
- background-color: #f5f5f5;
1528
- border-color: #d9d9d9;
1529
- color: #bebebe;
1530
- }
1531
- }
1532
- .prompt {
1533
- position: absolute;
1534
- bottom: 16px;
1535
- right: 120px;
1536
- color: #a6a6a6;
1537
- }
1538
- }
1539
- .infinite-container {
1540
- overflow-y: auto;
1541
- }
1542
- .message-wrapper {
1543
- position: relative;
1544
- .loading-icon {
1545
- position: absolute;
1546
- top: 0;
1547
- left: 50%;
1548
- }
1549
- }
1550
- .content-edit {
1551
- width: 100%;
1552
- height: 100%;
1553
- padding: 0 16px 56px;
1554
- word-break: break-word;
1555
- &::-webkit-scrollbar {
1556
- width: 5px;
1557
- }
1558
- cursor: text;
1559
- > div {
1560
- height: 100%;
1561
- outline: none;
1562
- overflow-y: auto;
1563
- overflow-x: hidden;
1564
- }
1565
- }
1566
- .overlay {
1567
- position: absolute;
1568
- width: 100%;
1569
- height: 100%;
1570
- top: 0;
1571
- cursor: not-allowed;
1572
- }
1573
- .queue-page {
1574
- display: flex;
1575
- flex-direction: column;
1576
- align-items: center;
1577
- justify-content: center;
1578
- position: absolute;
1579
- width: 100%;
1580
- height: 100%;
1581
- top: 0;
1582
- background: #fff;
1583
- z-index: 500;
1584
- border-top: 1px solid #e6e6e6;
1585
- .queue-tips {
1586
- font-size: 16px;
1587
- color: #272727;
1588
- line-height: 22px;
1589
- margin-bottom: 16px;
1590
- }
1591
- .queue-btns {
1592
- display: flex;
1593
- justify-content: center;
1594
- }
1595
- .toSession {
1596
- width: 80px;
1597
- height: 80px;
1598
- line-height: 80px;
1599
- text-align: center;
1600
- background: linear-gradient(180deg, #ffffff 0%, #f5f5f5 100%);
1601
- box-shadow: 0px 4px 9px 0px rgba(186, 186, 186, 0.79);
1602
- border-radius: 50%;
1603
- color: #4b4b4b;
1604
- font-size: 20px;
1605
- font-weight: 500;
1606
- font-family: PingFangSC-Medium, PingFang SC;
1607
- transition: transform 0.3s ease;
1608
- &.primary {
1609
- background: linear-gradient(180deg, #2d7aff 0%, #2c5df4 100%);
1610
- box-shadow: 0px 5px 8px 0px rgba(44, 101, 247, 0.39);
1611
- color: #fff;
1612
- }
1613
- &.danger {
1614
- background: linear-gradient(180deg, #ff4b4b 0%, #c80606 100%);
1615
- box-shadow: 0px 5px 8px 0px rgba(217, 26, 26, 0.35);
1616
- color: #fff;
1617
- }
1618
- &:hover {
1619
- transform: scale(1.2);
1620
- }
1621
- & + .toSession {
1622
- margin-left: 36px;
1623
- }
1624
- }
1625
- }
1626
- .toolbar {
1627
- // margin-left: 10px;
1628
- margin: 0 5px;
1629
- font-size: 20px;
1630
- outline: none;
1631
- padding: 6px;
1632
- box-sizing: content-box;
1633
- &:hover {
1634
- background-color: #ebebeb;
1635
- border-radius: 6px;
1636
- }
1637
- }
1638
- .closed-toolbar {
1639
- z-index: 100;
1640
- }
1641
- /deep/ p {
1642
- margin-bottom: 0;
1643
- }
1644
- .click-voice {
1645
- color: #2d7aff;
1646
- }
1647
- </style>
1
+ <template>
2
+ <a-layout-footer style="position: relative;cursor:pointer" v-show="!queueItem || !hideQueueBtns">
3
+ <div class="message-operate">
4
+ <a-upload
5
+ v-if="isShow('PICTURE')"
6
+ class="operate-icon"
7
+ v-decorator="[
8
+ 'upload',
9
+ {
10
+ valuePropName: 'fileList'
11
+ }
12
+ ]"
13
+ :beforeUpload="beforeUpload"
14
+ >
15
+ <a-tooltip placement="top">
16
+ <template slot="title">{{ i18nText('1.9.181') }}</template>
17
+ <svg-icon icon-class="liaotiantupian1" class="toolbar"></svg-icon>
18
+ </a-tooltip>
19
+ </a-upload>
20
+ <a-popover :title="i18nText('1.9.354')" trigger="click" v-model="visible">
21
+ <a slot="content">
22
+ <div class="emoji-wrapper">
23
+ <p v-for="(item, index) in emojiList" :key="index" @click="() => handleEmojiClick(item)" :class="['twa', 'emoji', item]"></p>
24
+ </div>
25
+ </a>
26
+
27
+ <a-tooltip placement="top">
28
+ <template slot="title">{{ i18nText('1.9.354') }}</template>
29
+ <svg-icon icon-class="liaotianbiaoqing1" @click="showEmoji" class="toolbar" v-if="isShow('SMILINEFACE')"></svg-icon>
30
+ </a-tooltip>
31
+ </a-popover>
32
+ <template v-for="(item, index) in toolbar">
33
+ <a-tooltip placement="top" :key="index">
34
+ <template slot="title">{{ item.name }}</template>
35
+ <svg-icon :icon-class="item.icon" class="toolbar" :class="{ 'closed-toolbar': closedSession }" @click="handleToolBarClick(item)"></svg-icon>
36
+ </a-tooltip>
37
+ </template>
38
+ <!-- 快捷回复 -->
39
+ <a-tooltip placement="top" :title="'快捷回复'">
40
+ <a-popover trigger="click" overlayClassName="quick-reply" placement="topLeft" v-model="quickShow">
41
+ <template slot="content">
42
+ <quick-reply :quickShow.sync="quickShow" :quickData="quickData"></quick-reply>
43
+ </template>
44
+ <svg-icon icon-class="liaotiankuaijiehuifu1" class="toolbar" @click="openQuickData" v-if="isShow('FASTREPLY') && isServer"></svg-icon>
45
+ </a-popover>
46
+ </a-tooltip>
47
+ <a-tooltip :title="'语音通话'">
48
+ <svg-icon icon-class="liaotianyuyindianhua" @click="handleVideoClick('voice')" class="toolbar" v-if="isShow('VOICE_CALL')"></svg-icon>
49
+ <!-- <img
50
+ width="20"
51
+ src="../img/multi-voice.png"
52
+ @click="handleVideoClick('voice')"
53
+ v-if="isShow('VOICE_CALL') && isServer"
54
+ /> -->
55
+ </a-tooltip>
56
+ <a-tooltip :title="'发送语音'">
57
+ <svg-icon icon-class="liaotianyuyin1" @click="handleVoice(true)" class="toolbar" :class="{ 'click-voice': showVoice }" v-if="isShow('VOICE')"></svg-icon>
58
+ <!-- <img
59
+ width="20"
60
+ src="../img/multi-video.png"
61
+ @click="handleVideoClick('video')"
62
+ v-if="isShow('VIDEO') && isServer"
63
+ /> -->
64
+ </a-tooltip>
65
+ <a-tooltip :title="'视频通话'">
66
+ <svg-icon icon-class="liaotianshipin1" @click="handleVideoClick('video')" class="toolbar" v-if="isShow('VIDEO')"></svg-icon>
67
+ <!-- <img
68
+ width="20"
69
+ src="../img/multi-video.png"
70
+ @click="handleVideoClick('video')"
71
+ v-if="isShow('VIDEO') && isServer"
72
+ /> -->
73
+ </a-tooltip>
74
+ </div>
75
+ <div class="message" style="text-align: left">
76
+ <div class="content-edit">
77
+ <div
78
+ ref="contentEdit"
79
+ @click="saveRange"
80
+ @keyup.exact="saveRange"
81
+ @change="changeData"
82
+ @input="handleInput"
83
+ @compositionstart="() => (this.ping = true)"
84
+ @compositionend="() => (this.ping = false)"
85
+ @keydown="handleKeyDown"
86
+ @paste="handlePaste"
87
+ contenteditable="true"
88
+ ></div>
89
+ </div>
90
+ <span class="prompt">Enter {{ i18nText('1.2.1.11.6') }}, Ctrl + Enter {{ i18nText('1.9.356') }}</span>
91
+ <a-button :disabled="sendDisabled" class="message-send" @click="handleMsgSend">{{ i18nText('1.2.1.11.6') }}</a-button>
92
+ </div>
93
+ <div id="canvas-wrapper" style="display: none">
94
+ <canvas id="canvas"></canvas>
95
+ </div>
96
+ <template v-if="showOverlay">
97
+ <div class="overlay" v-if="(!onChating || sessionEnd) && !queueItem"></div>
98
+ </template>
99
+ <div class="queue-page" v-if="queueItem">
100
+ <div v-if="accessDesc" class="queue-tips">{{ accessDesc }}</div>
101
+ <div class="queue-btns">
102
+ <div v-if="enableTransfer" class="toSession" @click="handleOpenTransfer">
103
+ {{ i18nText('1.10.201') }}
104
+ </div>
105
+ <div class="toSession primary" @click="handleAccess">
106
+ {{ accessText || i18nText('1.9.352') }}
107
+ </div>
108
+ <div v-if="enableRefuse" class="toSession danger" @click="openRefuseReason">
109
+ {{ i18nText('1.9.353') }}
110
+ </div>
111
+ </div>
112
+ </div>
113
+ <!-- 操作栏弹窗 -->
114
+ <VuecmfDialog
115
+ ref="vuecmfDialog"
116
+ v-if="cmfModalShow"
117
+ :class="isFullScreen ? 'chat-footer-modal-big' : 'chat-footer-modal-small'"
118
+ :title="cmfModalData.name"
119
+ :top="isFullScreen ? '0' : '10vh'"
120
+ :width="isFullScreen ? '100%' : '80%'"
121
+ :isFullScreen="isFullScreen"
122
+ :okText="i18nText('1.2.1.11.6')"
123
+ @close="handleClose"
124
+ @ok="handleOk"
125
+ >
126
+ <iframe id="toolbarIframe" v-if="cmfModalData.targetType === 'LINK_ADDRESS'" width="100%" height="100%" frameborder="0" :src="modalData.address" allow="camera;midi"></iframe>
127
+ </VuecmfDialog>
128
+ <!-- <a-modal
129
+ :wrapClassName="isFullScreen ? 'chat-footer-modal-big' : 'chat-footer-modal-small'"
130
+ :title="modalData.name"
131
+ :visible="modalShow"
132
+ :maskClosable="false"
133
+ :mask="true"
134
+ :width="isFullScreen ? '100%' : '80%'"
135
+ destroyOnClose
136
+ :okText="i18nText('1.2.1.11.6')"
137
+ :footer="null"
138
+ @cancel="handleClose"
139
+ @ok="handleOk"
140
+ >
141
+ <iframe id="toolbarIframe" v-if="modalData.targetType === 'LINK_ADDRESS'" width="100%" height="100%" frameborder="0" :src="modalData.address" allow="camera;midi"></iframe>
142
+ </a-modal> -->
143
+ <!-- 接入拦截 -->
144
+ <a-modal
145
+ :title="accessInterceptTitle"
146
+ :visible="accessIntercept"
147
+ :maskClosable="false"
148
+ :mask="true"
149
+ :footer="null"
150
+ destroyOnClose
151
+ :width="600"
152
+ :bodyStyle="{ height: '280px' }"
153
+ @cancel="
154
+ () => {
155
+ this.accessIntercept = false;
156
+ }
157
+ "
158
+ >
159
+ <iframe width="100%" height="100%" frameborder="0" :src="accessInterceptUrl"></iframe>
160
+ </a-modal>
161
+ <!-- 语音消息 -->
162
+ <voice v-if="showVoice" :showVoice="showVoice" @closeVoice="handleVoice"></voice>
163
+ <ModalUserTransfer v-if="enableTransfer" :title="i18nText('1.10.201')" :visible.sync="transferVisible" :assemblyId="assemblyId" @ok="handleTransfer" />
164
+ <ModalRefuseReason v-if="refuseVisible" :visible.sync="refuseVisible" :reasonList="refuseReasonList" @ok="handleRefuse" />
165
+ </a-layout-footer>
166
+ </template>
167
+
168
+ <script>
169
+ import { Layout, Tooltip, Upload, Modal, Popover, Button } from 'ant-design-vue';
170
+ import SvgIcon from '@/component/svg/index.vue';
171
+ import ImageCompress from '../utils/compressImage';
172
+ import { parseParams } from '../utils/panelsetting';
173
+
174
+ import { mapState, mapGetters, mapMutations, mapActions } from '../store/helper';
175
+ import fetch, { qs } from '@/utils/chatFetch';
176
+ import QuickReply from './quickReply';
177
+ import voice from './voice';
178
+ import ModalUserTransfer from '../components/modal-user-transfer';
179
+ import ModalRefuseReason from '../components/modal-refuse-reason';
180
+ import VuecmfDialog from '../components/vuecmf-dialog.vue';
181
+ import vexutils from '@/utils/vexutils';
182
+ export default {
183
+ inject: ['store', 'i18nText', 'dispatchEvent', 'registerEvent', 'unregisterEvent'],
184
+ components: {
185
+ AModal: Modal,
186
+ [Layout.Footer.name]: Layout.Footer,
187
+ [Tooltip.name]: Tooltip,
188
+ [Upload.name]: Upload,
189
+ [Button.name]: Button,
190
+ [Popover.name]: Popover,
191
+ SvgIcon,
192
+ ModalRefuseReason,
193
+ ModalUserTransfer,
194
+ QuickReply,
195
+ voice,
196
+ VuecmfDialog
197
+ },
198
+ props: {
199
+ // 隐藏排队状态底部信息
200
+ hideQueueBtns: {
201
+ type: Boolean,
202
+ default: false
203
+ },
204
+ validTalkingEnv: {
205
+ type: Function
206
+ },
207
+ curChatType: {
208
+ type: String
209
+ },
210
+ clientFinish: {
211
+ type: Boolean,
212
+ default: true
213
+ },
214
+ addvisible: {
215
+ type: Boolean,
216
+ default: false
217
+ },
218
+ isShowVoice: {
219
+ type: Boolean,
220
+ default: false
221
+ }
222
+ },
223
+ data() {
224
+ return {
225
+ // message: "",
226
+ visible: false,
227
+ modalShow: false,
228
+ modalData: {},
229
+ ping: false,
230
+ templateId: null, // 卡片模板
231
+ isFullScreen: false,
232
+ emojiList: require('../utils/emoji.json'),
233
+ quickData: [],
234
+ quickShow: false,
235
+ screenshot: false,
236
+ screenshotFile: null,
237
+ timer: null,
238
+ accessIntercept: false,
239
+ curToolbarItem: {},
240
+ showVoice: false,
241
+ transferVisible: false,
242
+ refuseVisible: false,
243
+
244
+ apiResult: {}, // 前置条件的返回值
245
+ };
246
+ },
247
+ computed: {
248
+ ...mapGetters([
249
+ 'userInfo',
250
+ 'assemblyId',
251
+ 'sessionId',
252
+ 'serviceId',
253
+ 'onChating',
254
+ 'roomId',
255
+ 'isServer',
256
+ 'assemblySetting',
257
+ 'chatType',
258
+ 'sessionEnd',
259
+ 'closedSession',
260
+ 'clientParams',
261
+ 'footerMessage',
262
+ 'queueItem',
263
+ 'sessionType',
264
+ 'groupMembers',
265
+ 'curScrollItem',
266
+ 'modalType',
267
+ 'cmfModalShow',
268
+ 'cmfModalData'
269
+ ]),
270
+ ...mapState({
271
+ classify: state => state.lastClassify || state.classify
272
+ }),
273
+ message() {
274
+ return this.footerMessage;
275
+ },
276
+ sendDisabled() {
277
+ return this.message.length === 0;
278
+ },
279
+ orgId() {
280
+ return this.userInfo?.sysParams?.orgId;
281
+ },
282
+ userId() {
283
+ return this.userInfo?.sysParams?.userId;
284
+ },
285
+ toolbar() {
286
+ if (!this.isServer) return [];
287
+ let toolbar = this.assemblySetting.toolbar || [];
288
+ toolbar = toolbar.filter(item => {
289
+ const { source, isChecked, isCloseChecked, isClosedAble } = item;
290
+ if (source === 'PC' && (
291
+ (!this.closedSession && isChecked === 'Y') ||
292
+ (this.closedSession && isCloseChecked === 'Y' && isChecked === 'Y' && isClosedAble === 'Y')
293
+ )
294
+ ){
295
+ const showCondition = item.showCondition || [];
296
+ const i = showCondition.findIndex(({ p_name, p_value }) => {
297
+ const params = this.clientParams;
298
+ const value = params[p_name];
299
+ if (p_value.startsWith('form.')) {
300
+ return value !== p_name[p_value.slice(5)];
301
+ }
302
+ return value !== p_value;
303
+ });
304
+ return i < 0;
305
+ }
306
+ return false;
307
+ });
308
+ return toolbar;
309
+ },
310
+ isListClassify() {
311
+ return this.assemblySetting.isListClassify === 'Y';
312
+ },
313
+ showOverlay() {
314
+ return this.curChatType != 'robot' || this.clientFinish;
315
+ },
316
+ accessText() {
317
+ let obj = this.assemblySetting.serverSetting.serverInfo.filter(item => item.key === 'ongoingButton')[0];
318
+ return obj?.value;
319
+ },
320
+ accessDesc() {
321
+ let obj = this.assemblySetting.serverSetting.serverInfo.filter(item => item.key === 'ongoingDescription')[0];
322
+ return obj?.value;
323
+ },
324
+ accessInterceptObj() {
325
+ let obj = this.assemblySetting.accessInterceptSetting?.filter(item => item.source === 'PC');
326
+ if (obj && obj[0]) {
327
+ return obj[0];
328
+ }
329
+ return undefined;
330
+ },
331
+ // 拦截url
332
+ accessInterceptUrl() {
333
+ const { accessInterceptObj: obj, apiResult } = this;
334
+ if (obj) {
335
+ return this.getLinkAddress(obj,{result:apiResult});
336
+ }
337
+ return '';
338
+ },
339
+ // 拦截title
340
+ accessInterceptTitle() {
341
+ const { accessInterceptObj: obj } = this;
342
+ if (obj) {
343
+ let res = obj.titleI18n ? this.i18nText(obj.titleI18n) : obj.title;
344
+ return res || '接入拦截';
345
+ }
346
+ return '接入拦截';
347
+ },
348
+ // 是否开启 排队转接
349
+ enableTransfer() {
350
+ if (this.assemblySetting.type === 'single') {
351
+ let setting = null;
352
+ if (this.isListClassify) {
353
+ const classify = this.classify;
354
+ const { listClassify = [] } = this.assemblySetting;
355
+ const target = listClassify.find(item => item.classify === classify);
356
+ setting = target ? target.serverFunctionSetting : null;
357
+ } else {
358
+ setting = this.assemblySetting?.serverSetting?.functionSetting;
359
+ }
360
+ if (setting) {
361
+ const v = setting.find(item => item.function === 'TRANSFER_BEFORE');
362
+ return v ? v.isChecked == 'Y' : false;
363
+ }
364
+ }
365
+ return false;
366
+ },
367
+ enableRefuse() {
368
+ let setting = null;
369
+ if (this.isListClassify) {
370
+ const classify = this.classify;
371
+ const { listClassify = [] } = this.assemblySetting;
372
+ const target = listClassify.find(item => item.classify === classify);
373
+ setting = target ? target.serverFunctionSetting : null;
374
+ } else {
375
+ setting = this.assemblySetting?.serverSetting?.functionSetting;
376
+ }
377
+ if (setting) {
378
+ const v = setting.find(item => item.function === 'ACCESS_REFUSE');
379
+ return v ? v.isChecked == 'Y' : false;
380
+ }
381
+ return false;
382
+ },
383
+ refuseReasonList() {
384
+ const list = this.assemblySetting?.refuseReasonSetting?.list || [];
385
+ return list.filter(v => !!v.text);
386
+ }
387
+ },
388
+
389
+ mounted() {
390
+ this.bindEvents();
391
+ },
392
+ methods: {
393
+ ...mapMutations([
394
+ 'setLastClassify',
395
+ 'setSessionTimer',
396
+ 'setScrollQueueId',
397
+ 'setCurScrollItem',
398
+ 'setIsAppendMsg',
399
+ 'setMessage',
400
+ 'setShowVideo',
401
+ 'setCaller',
402
+ 'setMedicalOrPrescription',
403
+ 'setModalVisible',
404
+ 'setFooterMessage',
405
+ 'setQueueItem',
406
+ 'setSessionId',
407
+ 'setCurrentTab',
408
+ 'setClientId',
409
+ 'setOnChating',
410
+ 'setClientParams',
411
+ 'setSessionHistoryList',
412
+ 'setSessionEnd',
413
+ 'setQuestionId',
414
+ 'setDictionaryKey',
415
+ 'setMultiVideoShow',
416
+ 'setVideoStatus',
417
+ 'setVideoMode',
418
+ 'setAddMemberType',
419
+ 'setShowAudio',
420
+ 'setVideoMembers',
421
+ 'setLastCurrentTab',
422
+ 'setIsRecorderVoice',
423
+ 'setVideoData',
424
+ 'setSessionType',
425
+ 'setCallerStatus',
426
+ 'setModalType',
427
+ 'setCmfModalShow',
428
+ 'setCmfModalData'
429
+ ]),
430
+ ...mapMutations({
431
+ clearMsgList: 'setMsgList'
432
+ }),
433
+ ...mapActions(['sendMessage', 'sendRobotMessage', 'handleBotChat', 'setMsgList', 'setChatTimer']),
434
+ deleteStyle(value) {
435
+ // 去掉样式
436
+ value = value.replace(/style\s*?=\s*?(['"])[\s\S]*?\1/g, '');
437
+ value = value.replace(/data\s*?=\s*?(['"])[\s\S]*?\1/g, '');
438
+ value = value.replace(/class\s*?=\s*?(['"])[\s\S]*?\1/g, match => {
439
+ if (match.includes('twa')) {
440
+ return match;
441
+ } else {
442
+ return '';
443
+ }
444
+ });
445
+ value = value.replace(/face\s*?=\s*?(['"])[\s\S]*?\1/g, '');
446
+ value = value.replace(/<a/g, '<span');
447
+ value = value.replace(/a>/g, 'span>');
448
+ value = value.replace(/<i/g, '<span');
449
+ value = value.replace(/i>/g, 'span>');
450
+ value = value.replace(/<u/g, '<span');
451
+ value = value.replace(/u>/g, 'span>');
452
+ value = value.replace(/<strong/g, '<span');
453
+ value = value.replace(/strong>/g, 'span>');
454
+ value = value.replace(/<h\d/g, '<span');
455
+ value = value.replace(/h\d>/g, 'span>');
456
+ value = value.replace(/<b>/g, '<span>');
457
+ value = value.replace(/b>/g, 'span>');
458
+ value = value.replace(/<font/g, '<span');
459
+ value = value.replace(/font>/g, 'span>');
460
+ return value;
461
+ },
462
+ // 更新 message值 (未用v-html,修改后需要手动设置聊天框html内容)
463
+ updateMessage(value) {
464
+ this._editValue = value;
465
+ this.setFooterMessage(`${value}`);
466
+ const editRef = this.$refs.contentEdit;
467
+ if (!editRef) return;
468
+ editRef.innerHTML = value;
469
+ },
470
+ // 根据 聊天框 html节点内容 设置 message值 (未用v-html,html内容更改需主动设置message值)
471
+ setMessageByHTML() {
472
+ const editRef = this.$refs.contentEdit;
473
+ if (!editRef) return;
474
+ const message = editRef.innerHTML;
475
+ this._editValue = message;
476
+ this.setFooterMessage(`${message}`);
477
+ },
478
+
479
+ showEmoji() {
480
+ // this.visible = true;
481
+ },
482
+
483
+ isShow(type) {
484
+ if (type === 'SMILINEFACE' && this.curChatType === 'robot') return true;
485
+ if (this.isListClassify) {
486
+ let label;
487
+ if (this.isServer) {
488
+ label = 'serverFunctionSetting';
489
+ } else {
490
+ label = 'clientFunctionSetting';
491
+ }
492
+ let classifyItem = this.assemblySetting.listClassify.filter(item => item.classify === this.classify);
493
+ if (!classifyItem || !classifyItem.length) return;
494
+ let funs = classifyItem[0][label] || [];
495
+ return funs.find(item => item.function === type)?.isChecked === 'Y';
496
+ }
497
+ let label;
498
+ if (this.isServer) {
499
+ label = 'serverSetting';
500
+ } else {
501
+ label = 'clientSetting';
502
+ }
503
+ let funs = this.assemblySetting[label]?.functionSetting || [];
504
+ return funs.find(item => item.function === type)?.isChecked === 'Y';
505
+ },
506
+
507
+ handleEmojiClick(item) {
508
+ let emojiHtml = `<p contenteditable="false" class="twa emoji ${item}"></p>&nbsp`;
509
+ this.insertToEdit(emojiHtml);
510
+ },
511
+ /* edit-content光标定位 */
512
+ resetSelection() {
513
+ let edit = this.$refs.contentEdit;
514
+ let sel, range;
515
+ if (window.getSelection && document.createRange) {
516
+ range = document.createRange();
517
+ range.selectNodeContents(edit);
518
+ range.collapse(true);
519
+ range.setEnd(edit, edit.childNodes.length);
520
+ range.setStart(edit, edit.childNodes.length);
521
+ sel = window.getSelection();
522
+ sel.removeAllRanges();
523
+ sel.addRange(range);
524
+ }
525
+ },
526
+
527
+ insertToEdit(value, isEditing) {
528
+ const { _editSel, _editRange } = this;
529
+ let sel, range;
530
+ if (window.getSelection) {
531
+ if (!isEditing) {
532
+ if (_editRange) {
533
+ sel = _editSel;
534
+ range = _editRange;
535
+ } else {
536
+ // 初始状态没有focus聊天框,需要手动focus 获取光标位置
537
+ const editRef = this.$refs.contentEdit;
538
+ if (!editRef) return;
539
+ editRef.focus();
540
+ this.saveRange();
541
+ sel = this._editSel;
542
+ range = this._editRange;
543
+ }
544
+ } else {
545
+ sel = window.getSelection();
546
+ range = sel.getRangeAt(0);
547
+ }
548
+ range.deleteContents();
549
+ let frag;
550
+ if (range.createContextualFragment) {
551
+ frag = range.createContextualFragment(value);
552
+ } else {
553
+ const el = document.createElement('div');
554
+ el.innerHTML = value;
555
+ frag = document.createDocumentFragment();
556
+ let node, lastNode;
557
+ while ((node = el.firstChild)) {
558
+ lastNode = frag.appendChild(node); // 之所以能终止循环,是因为el的child一旦添加到dom后,作为fragment里的的child就没了。那么el.firstChild就会返回null
559
+ }
560
+ }
561
+ const lastNode = frag.lastChild;
562
+ range.insertNode(frag);
563
+ // 把光标挪到插入的元素后面
564
+ range.setStartAfter(lastNode);
565
+ sel.removeAllRanges();
566
+ sel.addRange(range);
567
+ } else {
568
+ range = isEditing || !_editRange ? document.selection.createRange() : _editRange;
569
+ range.pasteHTML(value);
570
+ range.select();
571
+ }
572
+ this.setMessageByHTML();
573
+ },
574
+ saveRange() {
575
+ if (window.getSelection) {
576
+ this._editSel = window.getSelection();
577
+ this._editRange = this._editSel.getRangeAt(0);
578
+ } else {
579
+ this._editRange = document.selection.createRange();
580
+ }
581
+ },
582
+ handleInput(e) {
583
+ if (e.inputType === 'deleteContentBackward') {
584
+ this.screenshot = false;
585
+ this.screenshotFile = null;
586
+ }
587
+ setTimeout(() => {
588
+ if (this.ping || this.pasteTimer) return;
589
+ this.setMessageByHTML();
590
+ }, 0);
591
+ },
592
+ changeData(e) {
593
+ let message = e.srcElement.innerHTML;
594
+ if (e.inputType === 'deleteContentBackward') {
595
+ let div = document.createElement('div');
596
+ div.innerHTML = e.srcElement.innerHTML;
597
+ if (div.lastChild?.className?.startsWith('twa emoji')) {
598
+ div.removeChild(div.lastChild);
599
+ message = div.innerHTML;
600
+ }
601
+ this.screenshot = false;
602
+ this.screenshotFile = null;
603
+ }
604
+
605
+ setTimeout(() => {
606
+ if (this.ping) return;
607
+ this.setFooterMessage(`${message}`);
608
+ this.$nextTick().then(() => {
609
+ this.resetSelection();
610
+ this.ping = false;
611
+ });
612
+ }, 0);
613
+ },
614
+
615
+ beforeUpload(data) {
616
+ let { type } = data;
617
+ if (!type.startsWith('image/')) {
618
+ this.$message.warning(`${this.i18nText('1.9.357')}!`);
619
+ return;
620
+ }
621
+ let that = this;
622
+ this.$confirm({
623
+ title: this.i18nText('1.9.331'),
624
+ content: `${this.i18nText('1.9.358')}?`,
625
+ okText: '确定',
626
+ cancelText: '取消',
627
+ onOk() {
628
+ return that.uploadImg(data);
629
+ },
630
+ onCancel() {
631
+ return false;
632
+ }
633
+ });
634
+ },
635
+
636
+ /* 压缩上传 */
637
+ uploadImg(file) {
638
+ const hide = this.$message.loading(`${this.i18nText('1.9.199')}...`, 0);
639
+ new ImageCompress(file, 'canvas', fetch, {
640
+ url: '/hospitalUpload/picture'
641
+ })
642
+ .execute()
643
+ .then(({ data }) => {
644
+ if (data.result === 'SUCCESS') {
645
+ this.doMsgSend(1, data.map.url);
646
+ hide();
647
+ } else {
648
+ hide();
649
+ this.$message.info(data.msg || `${this.i18nText('1.9.174')}!`);
650
+ }
651
+ })
652
+ .catch(() => {
653
+ hide();
654
+ this.$message.info(`${this.i18nText('1.9.174')}!`);
655
+ })
656
+ .finally(() => {
657
+ this.screenshotFile = null;
658
+ this.screenshot = false;
659
+ this.updateMessage('');
660
+ });
661
+ },
662
+
663
+ /* 发送消息 */
664
+ doMsgSend(type, content) {
665
+ let body = {
666
+ content: type === 0 ? `<div>${content}</div>` : content,
667
+ type: type
668
+ };
669
+ if (this.curChatType === 'robot') {
670
+ // this.setQuestionId("");
671
+ // this.setDictionaryKey("");
672
+ this.sendRobotMessage(content);
673
+ } else {
674
+ this.sendMessage(body);
675
+ }
676
+ },
677
+ handleMsgSend() {
678
+ // 截图上传
679
+ if (this.screenshot) {
680
+ this.uploadImg(this.screenshotFile);
681
+ return;
682
+ }
683
+ if (this.chatType === 'bot') {
684
+ this.handleBotChat(this.message).then(isHuman => {
685
+ if (isHuman) {
686
+ this.$parent.$parent.$parent.initWebSocket();
687
+ }
688
+ this.updateMessage('');
689
+ });
690
+ return;
691
+ }
692
+
693
+ const editRef = this.$refs.contentEdit;
694
+ if (editRef) {
695
+ const message = editRef.innerText;
696
+ if (message.length > 2000) {
697
+ this.$message.warning('请控制在2000字以内!');
698
+ return;
699
+ }
700
+ }
701
+ // let reg = /(.*?)(<div><br><\/div>)*?$/;
702
+ let reg = /(.*?)(<div>(<span>)?<br>(<\/span>)?<\/div>)*?$/;
703
+ let message = this.message.match(reg);
704
+ if (message[2]) {
705
+ this.updateMessage(message[1]);
706
+ }
707
+ this.updateMessage(this.message.replace(/style/g, 'data'));
708
+ if (this.message.trim()) {
709
+ this.doMsgSend(0, this.message);
710
+ } else {
711
+ return this.$message.warning(this.i18nText('1.9.359'));
712
+ }
713
+ this.updateMessage('');
714
+ },
715
+ handleKeyDown(e) {
716
+ // 判断enter 发送还是换行
717
+ if (e.keyCode === 13) {
718
+ e.preventDefault();
719
+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
720
+ this.handleWrap();
721
+ } else {
722
+ this.handleMsgSend();
723
+ }
724
+ }
725
+ },
726
+ handleWrap() {
727
+ let ctn = `<br>`;
728
+ // 非ie环境 元素后面没有node的时候换行需要两个<br>
729
+ if (!/msie/.test(navigator.userAgent) && window.getSelection) {
730
+ const focusNode = window.getSelection().focusNode;
731
+ let nextSibling = focusNode.nextSibling;
732
+ if (focusNode === this.$refs.contentEdit) {
733
+ nextSibling = focusNode.childNodes[0];
734
+ }
735
+ do {
736
+ if (!nextSibling || nextSibling.nodeValue || nextSibling.tagName == 'BR') break;
737
+ } while ((nextSibling = nextSibling.nextSibling));
738
+ if (!nextSibling) {
739
+ ctn += ctn;
740
+ }
741
+ }
742
+ this.insertToEdit(ctn);
743
+ this.$nextTick().then(() => {
744
+ this.ping = false;
745
+ });
746
+ },
747
+ handleVideoClick(type) {
748
+ this.setCallerStatus('')
749
+ // this.curScrollItem.type 2多人 1单人
750
+ if (this.sessionType === 2) {
751
+ this.$emit('update:addvisible', true);
752
+ this.setAddMemberType(2);
753
+ this.setVideoMode(type === 'voice' ? 1 : 2);
754
+ } else {
755
+ const openTalking = sip => {
756
+ this.setShowAudio(true);
757
+ this.setVideoMode(type === 'voice' ? 1 : 2);
758
+ this.$nextTick(() => {
759
+ this.setVideoMembers([]);
760
+ });
761
+ this.setVideoData({
762
+ callerSipKey: sip?.username,
763
+ callerSipName: sip?.name
764
+ });
765
+ };
766
+ if (this.validTalkingEnv) {
767
+ this.validTalkingEnv().then(res => {
768
+ if (res.status) {
769
+ openTalking(res.sip);
770
+ }
771
+ });
772
+ } else {
773
+ openTalking();
774
+ }
775
+ }
776
+ // this.groupMembers.length > 2
777
+ return;
778
+ },
779
+ handleVoice(val) {
780
+ val && this.setIsRecorderVoice(true);
781
+ this.showVoice = val;
782
+ },
783
+ showPrescription() {
784
+ this.setModalVisible(true);
785
+ this.setMedicalOrPrescription('prescription');
786
+ },
787
+ showMedicalRecord() {
788
+ this.setModalVisible(true);
789
+ this.setMedicalOrPrescription('medical');
790
+ },
791
+ beofreToolBarClick(item) {
792
+ // 操作栏前置条件
793
+ return new Promise((resolve, reject) => {
794
+ const { precondition } = item;
795
+ if (precondition) {
796
+ this.requestPreCondition(precondition)
797
+ .then(res => {
798
+ const result = res.data.result === 'SUCCESS';
799
+ !result && this.$message.error(res.data.resultMsg || this.i18nText('1.9.22'));
800
+ resolve(result);
801
+ })
802
+ .catch(error => {
803
+ this.$message.error(error.resultMsg || this.i18nText('1.9.22'));
804
+ resolve(false);
805
+ });
806
+ } else {
807
+ resolve(true);
808
+ }
809
+ });
810
+ },
811
+ async handleToolBarClick(item) {
812
+ console.log('item', item.key);
813
+ console.log('toolbarItem', this.curScrollItem);
814
+ console.log(this.curScrollItem.consultText);
815
+ if (this.curScrollItem.consultText === '初诊' && ['prescription', 'prescription_new_his', 'prescription_his', 'medical_record', 'medical_record_new'].includes(item.key)) {
816
+ this.$message.info('初诊病人仅支持咨询')
817
+ return
818
+ }
819
+ if (item.key === this.modalType) {
820
+ this.$refs.vuecmfDialog.toggleScreen()
821
+ return
822
+ }
823
+ if (this.modalType && ['prescription', 'prescription_new_his', 'prescription_his', 'medical_record', 'medical_record_new', 'gauge'].includes(item.key)) {
824
+ this.$message.info('请先关闭最小化弹窗后再进行操作')
825
+ return
826
+ }
827
+ const validate = await this.beofreToolBarClick(item);
828
+ if (!validate) return;
829
+ let { openMode, name, templateId, isFullScreen } = item;
830
+ this.dispatchEvent('click_toolbar', { ...item });
831
+ if (!item.address) return;
832
+ this.curToolbarItem = item;
833
+ this.templateId = templateId;
834
+ this.isFullScreen = isFullScreen === 'Y';
835
+ let address = this.getLinkAddress(item);
836
+ if (openMode === 'WINDOW') {
837
+ window.open(address, name);
838
+ return;
839
+ }
840
+ if (openMode === 'EJECT') {
841
+ if (!this.modalType) {
842
+ this.setModalType(item.key)
843
+ this.setCmfModalShow(true);
844
+ this.setCmfModalData(Object.assign({}, item, { address }))
845
+ }
846
+ this.modalData = Object.assign({}, item, { address });
847
+ console.log('this.modalData', this.modalData);
848
+ this.$nextTick().then(() => {
849
+ window.addEventListener('message', this.iframeEvent);
850
+ // window.onmessage = this.iframeEvent
851
+ });
852
+ return;
853
+ }
854
+ },
855
+ iframeEvent(event) {
856
+ const method = event?.data?.method;
857
+ this[method]?.(event);
858
+ },
859
+ // 发送
860
+ handleParentMessageSend({ data, source, origin }) {
861
+ let params = {
862
+ assemblyId: this.assemblyId,
863
+ sessionId: this.sessionId,
864
+ orgId: this.orgId
865
+ };
866
+ params = Object.assign(params, data.data);
867
+ let { actionType } = this.curToolbarItem;
868
+ actionType && Object.assign(params, { actionType });
869
+ return fetch.post('/chat/access/sendToolBarData', qs.stringify(params)).then(({ data }) => {
870
+ if (data.result === 'SUCCESS') {
871
+ source.postMessage({ status: 0, resultMsg: data.resultMsg }, origin);
872
+ } else {
873
+ source.postMessage({ status: 1, resultMsg: data.resultMsg }, origin);
874
+ }
875
+ });
876
+ },
877
+ // 关闭
878
+ handleClose() {
879
+ this.setCmfModalShow(false);
880
+ this.setModalType(null)
881
+ this.setCmfModalData({})
882
+ this.modalShow = false;
883
+ window.removeEventListener('message', this.iframeEvent);
884
+ // window.onmessage = null;
885
+ },
886
+ getLinkAddress(item,paramsData= {}) {
887
+ let t = {talbe:{},form:{},sys:{}};
888
+ Object.assign(t,paramsData ||{})
889
+ let { address = '', params = [] } = item;
890
+ let urlParams = [];
891
+ params.forEach(({ p_name, p_value }) => {
892
+ let value;
893
+ if (p_value.startsWith('form.')) {
894
+ value = this.clientParams[p_value.slice(5)];
895
+ } else if( /\${result.(.*?)\}/g.test(p_value)) {
896
+ value = vexutils.handleSysParams(p_value,t)
897
+ } else {
898
+ value = p_value;
899
+ }
900
+ urlParams.push(`${p_name}=${value}`);
901
+ });
902
+ if(/\${result.(.*?)\}/g.test(address)){
903
+ address = vexutils.handleSysParams(address,t)
904
+ }
905
+ let { actionType } = this.curToolbarItem;
906
+ actionType && urlParams.push(`actionType=${actionType}`);
907
+ if (address.includes('?')) {
908
+ address += `&${urlParams.join('&')}`;
909
+ } else {
910
+ address += `?${urlParams.join('&')}`;
911
+ }
912
+ return address;
913
+ },
914
+ handleOk() {
915
+ window.handleParentMessageSend();
916
+ },
917
+ // 剪切板粘贴
918
+ handlePaste(e) {
919
+ const cbd = e.clipboardData;
920
+ const ua = window.navigator.userAgent;
921
+ // 如果是 Safari 直接 return
922
+ if (!(e.clipboardData && e.clipboardData.items)) {
923
+ this.handlePasteText(e);
924
+ return;
925
+ }
926
+ if (
927
+ cbd.items &&
928
+ cbd.items.length === 2 &&
929
+ cbd.items[0].kind === 'string' &&
930
+ cbd.items[1].kind === 'file' &&
931
+ cbd.types &&
932
+ cbd.types.length === 2 &&
933
+ cbd.types[0] === 'text/plain' &&
934
+ cbd.types[1] === 'Files' &&
935
+ ua.match(/Macintosh/i) &&
936
+ Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49
937
+ ) {
938
+ this.handlePasteText(e);
939
+ return;
940
+ }
941
+ const hasFile = this.handleImgPaste(cbd.items);
942
+ if (hasFile) {
943
+ e.stopPropagation();
944
+ e.preventDefault();
945
+ return;
946
+ }
947
+ this.handlePasteText(e);
948
+ },
949
+ handleImgPaste(files) {
950
+ let hasFile = false;
951
+ for (let i = 0; i < files.length; i++) {
952
+ let item = files[i];
953
+ if (item.kind == 'file') {
954
+ hasFile = true;
955
+ // blob 就是从剪切板获得的文件,可以进行上传或其他操作
956
+ const blob = item.getAsFile();
957
+ if (blob.size === 0) {
958
+ return;
959
+ }
960
+ const reader = new FileReader();
961
+ const imgs = new Image();
962
+ imgs.file = blob;
963
+ reader.onload = e => {
964
+ imgs.src = e.target.result;
965
+ imgs.width = '150';
966
+ this.updateMessage(this.htmlToString(imgs));
967
+ this.$nextTick().then(() => {
968
+ this.resetSelection();
969
+ this.screenshot = true;
970
+ this.screenshotFile = blob;
971
+ });
972
+ };
973
+ reader.readAsDataURL(blob);
974
+ }
975
+ }
976
+ return hasFile;
977
+ },
978
+ // 处理文本粘贴
979
+ handlePasteText() {
980
+ if (this.pasteTimer) clearTimeout(this.pasteTimer);
981
+ const ele = this.$refs.contentEdit;
982
+ if (!ele) return;
983
+ let before = ele.innerHTML;
984
+ this.pasteTimer = setTimeout(() => {
985
+ function getPasteHtml(before, after) {
986
+ // 计算粘贴后html不同的位置起点和终点(插入"abc",则得出sPos为0,ePos为2)
987
+ var sPos = -1,
988
+ ePos = -1;
989
+ for (var i = 0, len = after.length; i < len; ++i) {
990
+ if (sPos == -1 && before.substr(i, 1) != after.substr(i, 1)) sPos = i;
991
+ if (ePos == -1 && before.substr(before.length - i - 1, 1) != after.substr(after.length - i - 1, 1)) ePos = i;
992
+
993
+ if ((sPos != -1 && ePos != -1) || len - 1 - ePos <= sPos) break;
994
+ }
995
+ if (sPos == -1 || ePos == -1) return;
996
+ ePos = len - 1 - ePos;
997
+
998
+ if (ePos <= sPos) {
999
+ // 遇到像ab,粘贴ab后变成abab这种了,这是需要从sPos开始往后找,找到和before一样的为止
1000
+ i = sPos;
1001
+ var beforeSPosNext = before.substr(i + 1, 10); // 取后10个来对比,如果没有10个,则取最多
1002
+ while (++i < len) {
1003
+ if (beforeSPosNext == after.substr(i, beforeSPosNext.length)) {
1004
+ ePos = i;
1005
+ break;
1006
+ }
1007
+ }
1008
+ i == len && (ePos = len - 1);
1009
+ }
1010
+ // 如果有<和>,则需要计算在内
1011
+ if (after.substr(sPos - 1, 1) == '<') --sPos;
1012
+ if (after.substr(ePos + 1, 1) == '>') ++ePos;
1013
+
1014
+ // 分段获得文本,前半段 插入段 后半段
1015
+ var pastedText = after.substring(sPos, ePos + 1),
1016
+ formerText = after.substr(0, sPos),
1017
+ latterText = after.substr(sPos + pastedText.length);
1018
+
1019
+ // 判断formerText和pastedText是否闭合了
1020
+ var lastLT = formerText.lastIndexOf('<'),
1021
+ lastGT = formerText.lastIndexOf('>');
1022
+ if (lastGT < lastLT) {
1023
+ // 标签断了xxxxx<
1024
+ pastedText = formerText.slice(lastLT) + pastedText;
1025
+ formerText = formerText.slice(0, lastLT);
1026
+ }
1027
+
1028
+ lastLT = pastedText.lastIndexOf('<');
1029
+ lastGT = pastedText.lastIndexOf('>');
1030
+ if (lastGT < lastLT) {
1031
+ // 标签断了<xxxxxx
1032
+ var _insertGT = latterText.indexOf('>') + 1;
1033
+ pastedText += latterText.slice(0, _insertGT);
1034
+ latterText = latterText.slice(_insertGT);
1035
+ }
1036
+ return [formerText, pastedText, latterText];
1037
+ }
1038
+ var after = ele.innerHTML;
1039
+ const data = getPasteHtml(before, after);
1040
+ if (data) {
1041
+ let [formerText, insertText, latterText] = data;
1042
+ insertText = this.deleteStyle(insertText);
1043
+ ele.innerHTML = formerText + insertText + "<span class='pasteCaretPosHelper'></span>" + latterText; // 插入pasteCaretPosHelper以帮助定位光标位置
1044
+ var pasteCaretPosHelper = ele.querySelector('.pasteCaretPosHelper'),
1045
+ range,
1046
+ selection;
1047
+ if (pasteCaretPosHelper) {
1048
+ if (document.createRange) {
1049
+ // Chrome, IE 9+
1050
+ range = document.createRange();
1051
+ range.setStartAfter(pasteCaretPosHelper);
1052
+ range.collapse(false);
1053
+ selection = window.getSelection();
1054
+ selection.removeAllRanges();
1055
+ selection.addRange(range);
1056
+ } else if (document.selection) {
1057
+ // IE 8 and lower
1058
+ range = document.body.createTextRange();
1059
+ range.moveToElementText(pasteCaretPosHelper);
1060
+ range.collapse(false);
1061
+ range.select();
1062
+ }
1063
+ pasteCaretPosHelper.parentNode.removeChild(pasteCaretPosHelper);
1064
+ }
1065
+ }
1066
+ this.setMessageByHTML();
1067
+ this.saveRange();
1068
+ this.pasteTimer = null;
1069
+ }, 50);
1070
+ },
1071
+ // 拖拽上传图片
1072
+ handleFiles(files) {
1073
+ this.handleImgPaste(files);
1074
+ },
1075
+ htmlToString(dom) {
1076
+ let div = document.createElement('div');
1077
+ div.appendChild(dom);
1078
+ return div.innerHTML;
1079
+ },
1080
+ /**
1081
+ * 接入拦截
1082
+ */
1083
+ handleAccessIntercept(result) {
1084
+ let { data } = result;
1085
+ let { status, data: param } = data;
1086
+ if (status === 1) {
1087
+ this.accessChat(param).finally(() => {
1088
+ this.accessIntercept = false;
1089
+ });
1090
+ } else {
1091
+ this.accessIntercept = false;
1092
+ }
1093
+ },
1094
+ /* 客服点击接入按钮进入会话 */
1095
+ async handleAccess() {
1096
+ this.apiResult = {};
1097
+ let accessInterceptValidate = this.handleAccessInterceptValue();
1098
+ let data = null; // 接口参数
1099
+ if (accessInterceptValidate && this.accessInterceptUrl) {
1100
+ const r = await this.beforeAccessIntercept();
1101
+ if (!r) return;
1102
+ if (r.value == 'Y') {
1103
+ this.accessIntercept = true;
1104
+ this.$nextTick().then(() => {
1105
+ window.addEventListener('message', this.handleAccessIntercept);
1106
+ });
1107
+ return;
1108
+ } else {
1109
+ data = r.data; // 获取接入拦截返回参数
1110
+ }
1111
+ }
1112
+ clearTimeout(this.timer);
1113
+ this.timer = setTimeout(() => {
1114
+ this.accessChat(data);
1115
+ }, 300);
1116
+ },
1117
+ // 条件转换请求
1118
+ requestPreCondition(precondition) {
1119
+ const { targetType, targetName, targetId, params } = precondition;
1120
+ const data = parseParams(params, this.clientParams);
1121
+ let url = '';
1122
+ if (targetType === 'API') {
1123
+ data.url = targetName;
1124
+ url = `/api/executeApi`;
1125
+ } else {
1126
+ data.sqlEnterId = targetId;
1127
+ url = `/form/saveSqlEnter`;
1128
+ }
1129
+ return fetch.post(url, qs.stringify(data));
1130
+ },
1131
+ async beforeAccessIntercept() {
1132
+ function parseResult(r) {
1133
+ let value = 'Y';
1134
+ const data = r.split('&').reduce((obj, str) => {
1135
+ const [k, v] = str.split('=');
1136
+ if (k) {
1137
+ if (k == 'value') {
1138
+ value = v || value;
1139
+ } else {
1140
+ obj = obj || {};
1141
+ obj[k] = v || '';
1142
+ }
1143
+ }
1144
+ return obj;
1145
+ }, null);
1146
+ return {
1147
+ value,
1148
+ data
1149
+ };
1150
+ }
1151
+ this.apiResult = {};
1152
+ const accessInterceptSetting = this.assemblySetting.accessInterceptSetting || [];
1153
+ const setting = accessInterceptSetting.find(item => item.source == 'PC' && item.isChecked == 'Y' && item.precondition);
1154
+ if (setting) {
1155
+ const precondition = setting.precondition;
1156
+ try {
1157
+ let res = await this.requestPreCondition(precondition);
1158
+ this.apiResult = res?.data?.map || {};
1159
+ if (res.data.result === 'SUCCESS') {
1160
+ let value = res.data.map?.result;
1161
+ value = value ? JSON.parse(value) : {};
1162
+ return value.value ? parseResult(value.value) : false;
1163
+ } else {
1164
+ this.$message.error(res.data.resultMsg || this.i18nText('1.9.22'));
1165
+ return false;
1166
+ }
1167
+ } catch (error) {
1168
+ this.$message.error(error.resultMsg || this.i18nText('1.9.22'));
1169
+ return false;
1170
+ }
1171
+ }
1172
+ return {
1173
+ value: 'Y',
1174
+ data: null
1175
+ };
1176
+ },
1177
+ handleAccessInterceptValue() {
1178
+ let { listClassify = [], isListClassify, serverSetting = {} } = this.assemblySetting;
1179
+ let list = [];
1180
+ if (isListClassify != 'Y') {
1181
+ let { functionSetting = [] } = serverSetting;
1182
+ list = functionSetting;
1183
+ } else {
1184
+ let curList = listClassify.find(item => item.classify == this.classify);
1185
+ if (!curList) return false;
1186
+ list = curList.serverFunctionSetting || [];
1187
+ }
1188
+ if (!list.length) return true;
1189
+ let curItem = list.find(item => item.function == 'ACCESS_INTERCEPT');
1190
+ if (!curItem) return true;
1191
+ return curItem.isChecked == 'Y';
1192
+ },
1193
+ accessChat(data) {
1194
+ let { bid: userId, username, userType } = this.queueItem;
1195
+ let params = {
1196
+ assemblyId: this.assemblyId,
1197
+ userId,
1198
+ userType,
1199
+ lastSessionId: this.sessionId,
1200
+ relateId: this.clientParams.relateId
1201
+ };
1202
+ if (data) {
1203
+ params.addParams = JSON.stringify(data);
1204
+ }
1205
+ return fetch.post('/chat/service/accessChat', qs.stringify(params)).then(({ data }) => {
1206
+ if (data.result === 'SUCCESS') {
1207
+ let { countdown, clientParams, sessionType, countdownDesc } = data.map;
1208
+ this.setSessionId(data.map.sessionId);
1209
+ this.clearMsgList();
1210
+ this.setMsgList();
1211
+ this.setCurrentTab('session');
1212
+ this.setLastCurrentTab('session');
1213
+ this.setClientId(username);
1214
+ this.setOnChating(true);
1215
+ this.setSessionEnd(false);
1216
+ this.setQueueItem(null);
1217
+ // 设置问诊类型
1218
+ this.setCurScrollItem({ ...this.curScrollItem, consultText: clientParams.text})
1219
+ sessionType && this.setSessionType(sessionType);
1220
+ if (countdown >= 0) {
1221
+ this.setChatTimer({ countdown, countdownDesc });
1222
+ }
1223
+ this.setClientParams(clientParams);
1224
+ this.getSessionHistoryList();
1225
+ this.dispatchEvent('user_accessSuccess', {
1226
+ map: data.map,
1227
+ user: { ...this.curScrollItem }
1228
+ });
1229
+ } else {
1230
+ this.$message.warning(data.resultMsg);
1231
+ }
1232
+ });
1233
+ },
1234
+ handleOpenTransfer() {
1235
+ if (this.enableTransfer) {
1236
+ this.transferVisible = true;
1237
+ }
1238
+ },
1239
+ handleTransfer(data) {
1240
+ const receiveId = data.converUserId;
1241
+ if (receiveId) {
1242
+ if (this.userId == receiveId) {
1243
+ this.$message.warning(this.i18nText('1.2.7.14.1'));
1244
+ return;
1245
+ }
1246
+ this.transferVisible = false;
1247
+ fetch({
1248
+ url: '/chat/service/transferQueue',
1249
+ method: 'POST',
1250
+ data: qs.stringify({
1251
+ relateId: this.clientParams.relateId,
1252
+ orgId: this.orgId,
1253
+ assemblyId: this.assemblyId,
1254
+ userId: this.curScrollItem?.bid,
1255
+ userType: this.curScrollItem?.userType || '',
1256
+ receiveId: receiveId,
1257
+ deptId: data.deptId,
1258
+ remark: data.converMark
1259
+ })
1260
+ })
1261
+ .then(({ data }) => {
1262
+ if (data.result === 'SUCCESS') {
1263
+ this.dispatchEvent('user_transferQueueSuccess', {
1264
+ user: { ...this.curScrollItem }
1265
+ });
1266
+ this.$message.success(this.i18nText('1.9.336'));
1267
+ this.clearCurrentSession(true);
1268
+ } else {
1269
+ this.$message.warning(data.resultMsg || this.i18nText('1.10.201') + this.i18nText('1.9.22'));
1270
+ }
1271
+ })
1272
+ .catch(err => {
1273
+ this.$message.warning(err.resultMsg || this.i18nText('1.10.201') + this.i18nText('1.9.22'));
1274
+ });
1275
+ } else {
1276
+ this.$message.warning(this.i18nText('1.9.335'));
1277
+ }
1278
+ },
1279
+ getSessionHistoryList() {
1280
+ this.setSessionHistoryList([]);
1281
+ if (this.assemblySetting.recordScopeSetting === 'CURRENT') return;
1282
+ fetch
1283
+ .get('/chat/service/getPastSessionList', {
1284
+ params: { sessionId: this.sessionId }
1285
+ })
1286
+ .then(({ data }) => {
1287
+ if (data.result === 'SUCCESS') {
1288
+ let list = data.list.map(item => {
1289
+ if (item.id === this.sessionId || this.type === 'session') {
1290
+ item.onChating = true;
1291
+ }
1292
+ return item;
1293
+ });
1294
+ this.setSessionHistoryList(list);
1295
+ }
1296
+ });
1297
+ },
1298
+ openQuickData() {
1299
+ // this.quickShow = true;
1300
+ if (this.quickData.length < 1) {
1301
+ fetch
1302
+ .get('/fastReply/getChatList', {
1303
+ params: {
1304
+ category: this.assemblySetting.chatPublicCategory
1305
+ }
1306
+ })
1307
+ .then(({ data }) => {
1308
+ if (data.result === 'SUCCESS') {
1309
+ this.quickData = data.list;
1310
+ }
1311
+ });
1312
+ }
1313
+ },
1314
+ // 清除当前会话
1315
+ clearCurrentSession(update = false) {
1316
+ this.clearMsgList([]);
1317
+ this.setSessionHistoryList([]);
1318
+ this.setSessionTimer('');
1319
+ this.setClientId('');
1320
+ this.setSessionId('');
1321
+ this.setScrollQueueId('');
1322
+ this.setLastClassify('');
1323
+ this.setCurScrollItem(null);
1324
+ this.setQueueItem(null);
1325
+ this.setClientParams(null);
1326
+ if (update) {
1327
+ // 重新设置 currentTab 触发 scrollList 组件 更新排队列表
1328
+ const currentTab = this.store.state?.currentTab;
1329
+ if (currentTab === 'queue') {
1330
+ this.setCurrentTab('');
1331
+ this.$nextTick(() => {
1332
+ this.setCurrentTab(this.store.state?.currentTab || currentTab);
1333
+ });
1334
+ }
1335
+ }
1336
+ },
1337
+ openRefuseReason() {
1338
+ if (this.enableRefuse) {
1339
+ this.refuseVisible = true;
1340
+ }
1341
+ },
1342
+ handleRefuse(remark) {
1343
+ if (!this.enableRefuse) return;
1344
+ fetch({
1345
+ url: '/chat/service/accessRefuse',
1346
+ method: 'POST',
1347
+ data: qs.stringify({
1348
+ relateId: this.clientParams.relateId,
1349
+ orgId: this.orgId,
1350
+ assemblyId: this.assemblyId,
1351
+ userId: this.curScrollItem?.bid,
1352
+ userType: this.curScrollItem?.userType || '',
1353
+ remark: remark || '其他'
1354
+ })
1355
+ })
1356
+ .then(({ data }) => {
1357
+ if (data.result === 'SUCCESS') {
1358
+ this.dispatchEvent('user_refuseSuccess', {
1359
+ user: { ...this.curScrollItem }
1360
+ });
1361
+ this.$message.success(this.i18nText('1.10.184'));
1362
+ this.clearCurrentSession(true);
1363
+ } else {
1364
+ this.$message.warning(data.resultMsg || this.i18nText('1.9.353') + this.i18nText('1.9.22'));
1365
+ }
1366
+ })
1367
+ .catch(err => {
1368
+ this.$message.warning(err.resultMsg || this.i18nText('1.9.353') + this.i18nText('1.9.22'));
1369
+ });
1370
+ this.refuseVisible = false;
1371
+ },
1372
+ bindEvents() {
1373
+ const handleDrop = e => {
1374
+ e.stopPropagation();
1375
+ e.preventDefault();
1376
+ this.handleFiles(e.dataTransfer.items);
1377
+ };
1378
+ document.addEventListener('drop', handleDrop, false);
1379
+ this.registerEvent('accessCurrentSession', this.handleAccess);
1380
+ this.registerEvent('refuseCurrentSession', this.openRefuseReason);
1381
+ this.registerEvent('transferCurrentQueueSession', this.handleOpenTransfer);
1382
+ this.registerEvent('transferUserQueueSessionOuting', this.handleTransfer);
1383
+ this.$on('hook:beforeDestroy', () => {
1384
+ document.removeEventListener('drop', handleDrop, false);
1385
+ window.removeEventListener('message', this.iframeEvent);
1386
+ window.removeEventListener('message', this.handleAccessIntercept);
1387
+ this.unregisterEvent('accessCurrentSession', this.handleAccess);
1388
+ this.unregisterEvent('refuseCurrentSession', this.openRefuseReason);
1389
+ this.unregisterEvent('transferCurrentQueueSession', this.handleOpenTransfer);
1390
+ this.unregisterEvent('transferUserQueueSessionOuting', this.handleTransfer);
1391
+ });
1392
+ }
1393
+ },
1394
+ watch: {
1395
+ accessIntercept: {
1396
+ handler(val) {
1397
+ if (!val) {
1398
+ window.removeEventListener('message', this.handleAccessIntercept);
1399
+ }
1400
+ }
1401
+ },
1402
+ message: {
1403
+ handler(v) {
1404
+ // 使用 _editValue 判断是否组件外修改 message,并更新聊天框
1405
+ if (this._editValue !== v) {
1406
+ this.updateMessage(v);
1407
+ }
1408
+ }
1409
+ }
1410
+ }
1411
+ };
1412
+ </script>
1413
+
1414
+ <style lang="less">
1415
+ .chat-footer-modal-big {
1416
+ padding: 10px;
1417
+ &.ant-modal-wrap {
1418
+ overflow: none;
1419
+ }
1420
+ .ant-modal {
1421
+ width: 100%;
1422
+ height: 100%;
1423
+ top: 0;
1424
+ padding-bottom: 0;
1425
+ }
1426
+ .ant-modal-content {
1427
+ height: 100%;
1428
+ }
1429
+ .ant-modal-body {
1430
+ height: calc(100% - 55px);
1431
+ }
1432
+ }
1433
+ .chat-footer-modal-small {
1434
+ &.ant-modal-wrap {
1435
+ overflow: none;
1436
+ }
1437
+ .ant-modal {
1438
+ width: 80%;
1439
+ height: 80%;
1440
+ padding-bottom: 0;
1441
+ top: 60px;
1442
+ }
1443
+ .ant-modal-content {
1444
+ height: 100%;
1445
+ }
1446
+ .ant-modal-body {
1447
+ height: 100%;
1448
+ padding: 0;
1449
+ }
1450
+ }
1451
+
1452
+ </style>
1453
+ <style lang="less" scoped>
1454
+ .message-operate {
1455
+ display: flex;
1456
+ align-items: center;
1457
+ height: 40px;
1458
+ line-height: 18px;
1459
+ background: #fff;
1460
+ overflow-x: auto;
1461
+ overflow-y: hidden;
1462
+ border-top: 1px solid #e6e6e6;
1463
+ &::-webkit-scrollbar {
1464
+ height: 5px;
1465
+ }
1466
+ > img {
1467
+ // > .operate-icon {
1468
+ margin-left: 10px;
1469
+ }
1470
+ /deep/ .ant-tabs .ant-tabs-top-content > .ant-tabs-tabpane {
1471
+ height: 300px !important;
1472
+ overflow: auto !important;
1473
+ }
1474
+ /deep/ .ant-upload-list {
1475
+ display: none;
1476
+ }
1477
+ /deep/ .ant-upload {
1478
+ height: 32px;
1479
+ vertical-align: middle;
1480
+ display: inline-block;
1481
+ }
1482
+ .no-click {
1483
+ pointer-events: none;
1484
+ opacity: 0.4;
1485
+ }
1486
+ .svg-icon {
1487
+ color: rgba(0, 0, 0, 0.6);
1488
+ }
1489
+ }
1490
+ .emoji-wrapper {
1491
+ width: 500px;
1492
+ height: 300px;
1493
+ overflow: auto;
1494
+ display: grid;
1495
+ grid-template-columns: repeat(10, 1fr);
1496
+ .emoji {
1497
+ display: inline-block;
1498
+ font-size: 20px;
1499
+ margin: 10px;
1500
+ text-align: center;
1501
+ }
1502
+ &::-webkit-scrollbar {
1503
+ width: 5px;
1504
+ }
1505
+ }
1506
+ .message {
1507
+ position: relative;
1508
+ height: 150px;
1509
+ .message-send {
1510
+ position: absolute;
1511
+ bottom: 8px;
1512
+ right: 14px;
1513
+ height: 40px;
1514
+ border-radius: 20px;
1515
+ width: 86px;
1516
+ font-weight: 600;
1517
+ font-size: 18px;
1518
+ color: #fff;
1519
+ background-color: @primary-color;
1520
+ border-color: @primary-color;
1521
+ &:hover {
1522
+ background-color: rgba(@primary-color, 0.7);
1523
+ border-color: rgba(@primary-color, 0.7);
1524
+ }
1525
+ &[disabled]:hover,
1526
+ &[disabled] {
1527
+ background-color: #f5f5f5;
1528
+ border-color: #d9d9d9;
1529
+ color: #bebebe;
1530
+ }
1531
+ }
1532
+ .prompt {
1533
+ position: absolute;
1534
+ bottom: 16px;
1535
+ right: 120px;
1536
+ color: #a6a6a6;
1537
+ }
1538
+ }
1539
+ .infinite-container {
1540
+ overflow-y: auto;
1541
+ }
1542
+ .message-wrapper {
1543
+ position: relative;
1544
+ .loading-icon {
1545
+ position: absolute;
1546
+ top: 0;
1547
+ left: 50%;
1548
+ }
1549
+ }
1550
+ .content-edit {
1551
+ width: 100%;
1552
+ height: 100%;
1553
+ padding: 0 16px 56px;
1554
+ word-break: break-word;
1555
+ &::-webkit-scrollbar {
1556
+ width: 5px;
1557
+ }
1558
+ cursor: text;
1559
+ > div {
1560
+ height: 100%;
1561
+ outline: none;
1562
+ overflow-y: auto;
1563
+ overflow-x: hidden;
1564
+ }
1565
+ }
1566
+ .overlay {
1567
+ position: absolute;
1568
+ width: 100%;
1569
+ height: 100%;
1570
+ top: 0;
1571
+ cursor: not-allowed;
1572
+ }
1573
+ .queue-page {
1574
+ display: flex;
1575
+ flex-direction: column;
1576
+ align-items: center;
1577
+ justify-content: center;
1578
+ position: absolute;
1579
+ width: 100%;
1580
+ height: 100%;
1581
+ top: 0;
1582
+ background: #fff;
1583
+ z-index: 500;
1584
+ border-top: 1px solid #e6e6e6;
1585
+ .queue-tips {
1586
+ font-size: 16px;
1587
+ color: #272727;
1588
+ line-height: 22px;
1589
+ margin-bottom: 16px;
1590
+ }
1591
+ .queue-btns {
1592
+ display: flex;
1593
+ justify-content: center;
1594
+ }
1595
+ .toSession {
1596
+ width: 80px;
1597
+ height: 80px;
1598
+ line-height: 80px;
1599
+ text-align: center;
1600
+ background: linear-gradient(180deg, #ffffff 0%, #f5f5f5 100%);
1601
+ box-shadow: 0px 4px 9px 0px rgba(186, 186, 186, 0.79);
1602
+ border-radius: 50%;
1603
+ color: #4b4b4b;
1604
+ font-size: 20px;
1605
+ font-weight: 500;
1606
+ font-family: PingFangSC-Medium, PingFang SC;
1607
+ transition: transform 0.3s ease;
1608
+ &.primary {
1609
+ background: linear-gradient(180deg, #2d7aff 0%, #2c5df4 100%);
1610
+ box-shadow: 0px 5px 8px 0px rgba(44, 101, 247, 0.39);
1611
+ color: #fff;
1612
+ }
1613
+ &.danger {
1614
+ background: linear-gradient(180deg, #ff4b4b 0%, #c80606 100%);
1615
+ box-shadow: 0px 5px 8px 0px rgba(217, 26, 26, 0.35);
1616
+ color: #fff;
1617
+ }
1618
+ &:hover {
1619
+ transform: scale(1.2);
1620
+ }
1621
+ & + .toSession {
1622
+ margin-left: 36px;
1623
+ }
1624
+ }
1625
+ }
1626
+ .toolbar {
1627
+ // margin-left: 10px;
1628
+ margin: 0 5px;
1629
+ font-size: 20px;
1630
+ outline: none;
1631
+ padding: 6px;
1632
+ box-sizing: content-box;
1633
+ &:hover {
1634
+ background-color: #ebebeb;
1635
+ border-radius: 6px;
1636
+ }
1637
+ }
1638
+ .closed-toolbar {
1639
+ z-index: 100;
1640
+ }
1641
+ /deep/ p {
1642
+ margin-bottom: 0;
1643
+ }
1644
+ .click-voice {
1645
+ color: #2d7aff;
1646
+ }
1647
+ </style>