cd-aichat 1.0.0

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 (356) hide show
  1. package/README.md +188 -0
  2. package/dist/ailogo.png +0 -0
  3. package/dist/cd-aichat.css +1 -0
  4. package/dist/cd-aichat.es.js +32223 -0
  5. package/dist/cd-aichat.umd.js +279 -0
  6. package/dist/index.css +1 -0
  7. package/package.json +61 -0
  8. package/src/ailogo.png +0 -0
  9. package/src/components/AiChat.test.js +538 -0
  10. package/src/components/AiChat.vue +2206 -0
  11. package/src/components/AiChatWidget.test.js +312 -0
  12. package/src/components/AiChatWidget.vue +963 -0
  13. package/src/components/BurnAfterReadDialog.test.js +121 -0
  14. package/src/components/BurnAfterReadDialog.vue +511 -0
  15. package/src/components/BurnAfterReadMessage.test.js +188 -0
  16. package/src/components/BurnAfterReadMessage.vue +193 -0
  17. package/src/components/BurnIndicator.test.js +101 -0
  18. package/src/components/BurnIndicator.vue +164 -0
  19. package/src/components/ChatWindow.vue +0 -0
  20. package/src/components/MentionList.vue +163 -0
  21. package/src/components/ResourceList.vue +194 -0
  22. package/src/components/RichTextEditor.vue +437 -0
  23. package/src/components/ScheduledSendDialog.vue +476 -0
  24. package/src/components/ScreenshotOverlay.vue +78 -0
  25. package/src/components/SendButtonGroup.test.js +174 -0
  26. package/src/components/SendButtonGroup.vue +166 -0
  27. package/src/components/UserDrawer.vue +0 -0
  28. package/src/components/screenshot/ScreenshotsBackground/getBoundsByPoints.ts +41 -0
  29. package/src/components/screenshot/ScreenshotsBackground/index.scss +27 -0
  30. package/src/components/screenshot/ScreenshotsBackground/index.tsx +145 -0
  31. package/src/components/screenshot/ScreenshotsButton/index.scss +29 -0
  32. package/src/components/screenshot/ScreenshotsButton/index.tsx +58 -0
  33. package/src/components/screenshot/ScreenshotsCanvas/getBoundsByPoints.ts +55 -0
  34. package/src/components/screenshot/ScreenshotsCanvas/getPoints.ts +60 -0
  35. package/src/components/screenshot/ScreenshotsCanvas/index.scss +84 -0
  36. package/src/components/screenshot/ScreenshotsCanvas/index.tsx +277 -0
  37. package/src/components/screenshot/ScreenshotsCanvas/isPointInDraw.ts +35 -0
  38. package/src/components/screenshot/ScreenshotsColor/index.scss +45 -0
  39. package/src/components/screenshot/ScreenshotsColor/index.tsx +39 -0
  40. package/src/components/screenshot/ScreenshotsContext.ts +56 -0
  41. package/src/components/screenshot/ScreenshotsMagnifier/index.scss +61 -0
  42. package/src/components/screenshot/ScreenshotsMagnifier/index.tsx +126 -0
  43. package/src/components/screenshot/ScreenshotsOperations/index.scss +25 -0
  44. package/src/components/screenshot/ScreenshotsOperations/index.tsx +118 -0
  45. package/src/components/screenshot/ScreenshotsOption/index.scss +50 -0
  46. package/src/components/screenshot/ScreenshotsOption/index.tsx +150 -0
  47. package/src/components/screenshot/ScreenshotsSize/index.scss +28 -0
  48. package/src/components/screenshot/ScreenshotsSize/index.tsx +41 -0
  49. package/src/components/screenshot/ScreenshotsSizeColor/index.scss +8 -0
  50. package/src/components/screenshot/ScreenshotsSizeColor/index.tsx +25 -0
  51. package/src/components/screenshot/ScreenshotsTextarea/calculateNodeSize.ts +117 -0
  52. package/src/components/screenshot/ScreenshotsTextarea/index.scss +19 -0
  53. package/src/components/screenshot/ScreenshotsTextarea/index.tsx +96 -0
  54. package/src/components/screenshot/composeImage.ts +57 -0
  55. package/src/components/screenshot/exports.ts +4 -0
  56. package/src/components/screenshot/hooks/useBounds.ts +35 -0
  57. package/src/components/screenshot/hooks/useCall.ts +17 -0
  58. package/src/components/screenshot/hooks/useCanvasContextRef.ts +8 -0
  59. package/src/components/screenshot/hooks/useCanvasMousedown.ts +13 -0
  60. package/src/components/screenshot/hooks/useCanvasMousemove.ts +13 -0
  61. package/src/components/screenshot/hooks/useCanvasMouseup.ts +13 -0
  62. package/src/components/screenshot/hooks/useCursor.ts +34 -0
  63. package/src/components/screenshot/hooks/useDispatcher.ts +8 -0
  64. package/src/components/screenshot/hooks/useDrawSelect.ts +16 -0
  65. package/src/components/screenshot/hooks/useEmiter.ts +61 -0
  66. package/src/components/screenshot/hooks/useHistory.ts +160 -0
  67. package/src/components/screenshot/hooks/useLang.ts +8 -0
  68. package/src/components/screenshot/hooks/useOperation.ts +37 -0
  69. package/src/components/screenshot/hooks/useReset.ts +26 -0
  70. package/src/components/screenshot/hooks/useStore.ts +8 -0
  71. package/src/components/screenshot/icons/iconfont.scss +88 -0
  72. package/src/components/screenshot/icons/iconfont.ttf +0 -0
  73. package/src/components/screenshot/icons/iconfont.woff +0 -0
  74. package/src/components/screenshot/icons/iconfont.woff2 +0 -0
  75. package/src/components/screenshot/index.tsx +169 -0
  76. package/src/components/screenshot/operations/Arrow/draw.ts +56 -0
  77. package/src/components/screenshot/operations/Arrow/index.tsx +193 -0
  78. package/src/components/screenshot/operations/Brush/draw.ts +45 -0
  79. package/src/components/screenshot/operations/Brush/index.tsx +169 -0
  80. package/src/components/screenshot/operations/Cancel/index.tsx +18 -0
  81. package/src/components/screenshot/operations/Ellipse/draw.ts +96 -0
  82. package/src/components/screenshot/operations/Ellipse/index.tsx +245 -0
  83. package/src/components/screenshot/operations/Mosaic/index.tsx +223 -0
  84. package/src/components/screenshot/operations/Ok/index.tsx +37 -0
  85. package/src/components/screenshot/operations/Pin/index.tsx +37 -0
  86. package/src/components/screenshot/operations/Rectangle/draw.ts +80 -0
  87. package/src/components/screenshot/operations/Rectangle/index.tsx +245 -0
  88. package/src/components/screenshot/operations/Redo/index.tsx +22 -0
  89. package/src/components/screenshot/operations/Save/index.tsx +37 -0
  90. package/src/components/screenshot/operations/Scan/index.tsx +46 -0
  91. package/src/components/screenshot/operations/Search/index.tsx +39 -0
  92. package/src/components/screenshot/operations/Text/index.tsx +307 -0
  93. package/src/components/screenshot/operations/Undo/index.tsx +22 -0
  94. package/src/components/screenshot/operations/index.ts +34 -0
  95. package/src/components/screenshot/operations/utils.ts +34 -0
  96. package/src/components/screenshot/screenshots.scss +13 -0
  97. package/src/components/screenshot/types.ts +53 -0
  98. package/src/components/screenshot/useGetLoadedImage.ts +29 -0
  99. package/src/components/screenshot/var.scss +107 -0
  100. package/src/components/screenshot/zh_CN.ts +37 -0
  101. package/src/emoji/100.gif +0 -0
  102. package/src/emoji/101.gif +0 -0
  103. package/src/emoji/102.gif +0 -0
  104. package/src/emoji/103.gif +0 -0
  105. package/src/emoji/104.gif +0 -0
  106. package/src/emoji/105.gif +0 -0
  107. package/src/emoji/106.gif +0 -0
  108. package/src/emoji/107.gif +0 -0
  109. package/src/emoji/108.gif +0 -0
  110. package/src/emoji/109.gif +0 -0
  111. package/src/emoji/110.gif +0 -0
  112. package/src/emoji/111.gif +0 -0
  113. package/src/emoji/112.gif +0 -0
  114. package/src/emoji/113.gif +0 -0
  115. package/src/emoji/114.gif +0 -0
  116. package/src/emoji/115.gif +0 -0
  117. package/src/emoji/116.gif +0 -0
  118. package/src/emoji/117.gif +0 -0
  119. package/src/emoji/118.gif +0 -0
  120. package/src/emoji/119.gif +0 -0
  121. package/src/emoji/120.gif +0 -0
  122. package/src/emoji/121.gif +0 -0
  123. package/src/emoji/122.gif +0 -0
  124. package/src/emoji/123.gif +0 -0
  125. package/src/emoji/124.gif +0 -0
  126. package/src/emoji/125.gif +0 -0
  127. package/src/emoji/126.gif +0 -0
  128. package/src/emoji/127.gif +0 -0
  129. package/src/emoji/128.gif +0 -0
  130. package/src/emoji/129.gif +0 -0
  131. package/src/emoji/130.gif +0 -0
  132. package/src/emoji/131.gif +0 -0
  133. package/src/emoji/132.gif +0 -0
  134. package/src/emoji/133.gif +0 -0
  135. package/src/emoji/134.gif +0 -0
  136. package/src/emoji/135.gif +0 -0
  137. package/src/emoji/136.gif +0 -0
  138. package/src/emoji/137.gif +0 -0
  139. package/src/emoji/138.gif +0 -0
  140. package/src/emoji/139.gif +0 -0
  141. package/src/emoji/140.gif +0 -0
  142. package/src/emoji/141.gif +0 -0
  143. package/src/emoji/142.gif +0 -0
  144. package/src/emoji/143.gif +0 -0
  145. package/src/emoji/144.gif +0 -0
  146. package/src/emoji/145.gif +0 -0
  147. package/src/emoji/146.gif +0 -0
  148. package/src/emoji/147.gif +0 -0
  149. package/src/emoji/148.gif +0 -0
  150. package/src/emoji/149.gif +0 -0
  151. package/src/emoji/150.gif +0 -0
  152. package/src/emoji/151.gif +0 -0
  153. package/src/emoji/152.gif +0 -0
  154. package/src/emoji/153.gif +0 -0
  155. package/src/emoji/154.gif +0 -0
  156. package/src/emoji/155.gif +0 -0
  157. package/src/emoji/156.gif +0 -0
  158. package/src/emoji/157.gif +0 -0
  159. package/src/emoji/158.gif +0 -0
  160. package/src/emoji/159.gif +0 -0
  161. package/src/emoji/160.gif +0 -0
  162. package/src/emoji/161.gif +0 -0
  163. package/src/emoji/162.gif +0 -0
  164. package/src/emoji/163.gif +0 -0
  165. package/src/emoji/164.gif +0 -0
  166. package/src/emoji/165.gif +0 -0
  167. package/src/emoji/166.gif +0 -0
  168. package/src/emoji/167.gif +0 -0
  169. package/src/emoji/168.gif +0 -0
  170. package/src/emoji/169.gif +0 -0
  171. package/src/emoji/170.gif +0 -0
  172. package/src/emoji/171.gif +0 -0
  173. package/src/emoji/172.gif +0 -0
  174. package/src/emoji/173.gif +0 -0
  175. package/src/emoji/174.gif +0 -0
  176. package/src/emoji/175.gif +0 -0
  177. package/src/emoji/176.gif +0 -0
  178. package/src/emoji/177.gif +0 -0
  179. package/src/emoji/178.gif +0 -0
  180. package/src/emoji/179.gif +0 -0
  181. package/src/emoji/180.gif +0 -0
  182. package/src/emoji/181.gif +0 -0
  183. package/src/emoji/182.gif +0 -0
  184. package/src/emoji/183.gif +0 -0
  185. package/src/emoji/184.gif +0 -0
  186. package/src/emoji/185.gif +0 -0
  187. package/src/emoji/186.gif +0 -0
  188. package/src/emoji/187.gif +0 -0
  189. package/src/emoji/188.gif +0 -0
  190. package/src/emoji/189.gif +0 -0
  191. package/src/emoji/190.gif +0 -0
  192. package/src/emoji/191.gif +0 -0
  193. package/src/emoji/192.gif +0 -0
  194. package/src/emoji/193.gif +0 -0
  195. package/src/emoji/194.gif +0 -0
  196. package/src/emoji/195.gif +0 -0
  197. package/src/emoji/196.gif +0 -0
  198. package/src/emoji/197.gif +0 -0
  199. package/src/emoji/198.gif +0 -0
  200. package/src/emoji/199.gif +0 -0
  201. package/src/emoji/200.png +0 -0
  202. package/src/emoji/201.png +0 -0
  203. package/src/emoji/202.png +0 -0
  204. package/src/emoji/203.png +0 -0
  205. package/src/emoji/204.png +0 -0
  206. package/src/emoji/205.png +0 -0
  207. package/src/emoji/206.png +0 -0
  208. package/src/emoji/207.png +0 -0
  209. package/src/emoji/208.png +0 -0
  210. package/src/emoji/209.png +0 -0
  211. package/src/emoji/210.png +0 -0
  212. package/src/emoji/211.png +0 -0
  213. package/src/emoji/212.png +0 -0
  214. package/src/emoji/213.png +0 -0
  215. package/src/emoji/214.png +0 -0
  216. package/src/emoji/215.png +0 -0
  217. package/src/emoji/216.png +0 -0
  218. package/src/emoji/217.png +0 -0
  219. package/src/emoji/218.png +0 -0
  220. package/src/emoji/219.png +0 -0
  221. package/src/emoji2/101--Streamline-The-Team.png +0 -0
  222. package/src/emoji2/128--Streamline-The-Team.png +0 -0
  223. package/src/emoji2/134--Streamline-The-Team.png +0 -0
  224. package/src/emoji2/173--Streamline-The-Team.png +0 -0
  225. package/src/emoji2/Airplane--Streamline-Emoji.svg +24 -0
  226. package/src/emoji2/Alien--Streamline-Emoji.svg +21 -0
  227. package/src/emoji2/Amazed-Face--Streamline-Emoji.svg +16 -0
  228. package/src/emoji2/Amusing-Face--Streamline-Emoji.svg +20 -0
  229. package/src/emoji2/Anguished-Face--Streamline-Emoji.svg +19 -0
  230. package/src/emoji2/Anxious-Face--Streamline-Emoji.svg +17 -0
  231. package/src/emoji2/Astonished-Face--Streamline-Emoji.svg +20 -0
  232. package/src/emoji2/Backhand-Index-Pointing-Down-1--Streamline-Emoji.svg +12 -0
  233. package/src/emoji2/Backhand-Index-Pointing-Left-1--Streamline-Emoji.svg +13 -0
  234. package/src/emoji2/Backhand-Index-Pointing-Right-1--Streamline-Emoji.svg +13 -0
  235. package/src/emoji2/Backhand-Index-Pointing-Up-1--Streamline-Emoji.svg +14 -0
  236. package/src/emoji2/Bar-Chart--Streamline-Emoji.svg +22 -0
  237. package/src/emoji2/Beaming-Face-With-Smiling-Eyes--Streamline-Emoji.svg +20 -0
  238. package/src/emoji2/Boy-1--Streamline-Emoji.svg +17 -0
  239. package/src/emoji2/Boy-2--Streamline-Emoji.svg +17 -0
  240. package/src/emoji2/Boy-3--Streamline-Emoji.svg +17 -0
  241. package/src/emoji2/Broken-Heart--Streamline-Emoji.svg +12 -0
  242. package/src/emoji2/Clapping-Hands-1--Streamline-Emoji.svg +23 -0
  243. package/src/emoji2/Clinking-Glasses-2--Streamline-Emoji.svg +43 -0
  244. package/src/emoji2/Confounded-Face--Streamline-Emoji.svg +17 -0
  245. package/src/emoji2/Confused-Face--Streamline-Emoji.svg +15 -0
  246. package/src/emoji2/Construction-Worker--Streamline-Emoji.svg +21 -0
  247. package/src/emoji2/Couple-With-Heart-Woman-Man-1--Streamline-Emoji.svg +40 -0
  248. package/src/emoji2/Couple-With-Heart-Woman-Man-2--Streamline-Emoji.svg +40 -0
  249. package/src/emoji2/Cowboy-Hat-Face--Streamline-Emoji.svg +22 -0
  250. package/src/emoji2/Crazy-Face--Streamline-Emoji.svg +25 -0
  251. package/src/emoji2/Crossed-Fingers-1--Streamline-Emoji.svg +25 -0
  252. package/src/emoji2/Crown--Streamline-Emoji.svg +35 -0
  253. package/src/emoji2/Crying-Face--Streamline-Emoji.svg +26 -0
  254. package/src/emoji2/Delivery-Truck--Streamline-Emoji.svg +31 -0
  255. package/src/emoji2/Determined-Face--Streamline-Emoji.svg +25 -0
  256. package/src/emoji2/Disappointed-Face--Streamline-Emoji.svg +15 -0
  257. package/src/emoji2/Dizzy-Face--Streamline-Emoji.svg +20 -0
  258. package/src/emoji2/Downcast-Face-With-Sweat--Streamline-Emoji.svg +18 -0
  259. package/src/emoji2/Drooling-Face-1--Streamline-Emoji.svg +19 -0
  260. package/src/emoji2/Drooling-Face-2--Streamline-Emoji.svg +18 -0
  261. package/src/emoji2/Ear--Streamline-Emoji.svg +14 -0
  262. package/src/emoji2/Exclamation-Mark--Streamline-Emoji.svg +12 -0
  263. package/src/emoji2/Exploding-Head--Streamline-Emoji.svg +24 -0
  264. package/src/emoji2/Expressionless-Face--Streamline-Emoji.svg +15 -0
  265. package/src/emoji2/Face-Blowing-A-Kiss--Streamline-Emoji.svg +18 -0
  266. package/src/emoji2/Face-Savoring-Food--Streamline-Emoji.svg +18 -0
  267. package/src/emoji2/Face-Screaming-In-Fear--Streamline-Emoji.svg +18 -0
  268. package/src/emoji2/Face-Vomiting--Streamline-Emoji.svg +28 -0
  269. package/src/emoji2/Face-With-Head-Bandage--Streamline-Emoji.svg +25 -0
  270. package/src/emoji2/Face-With-Medical-Mask--Streamline-Emoji.svg +23 -0
  271. package/src/emoji2/Face-With-Monocle--Streamline-Emoji.svg +26 -0
  272. package/src/emoji2/Face-With-Raised-Eyebrow--Streamline-Emoji.svg +17 -0
  273. package/src/emoji2/Face-With-Rolling-Eyes--Streamline-Emoji.svg +17 -0
  274. package/src/emoji2/Face-With-Steam-From-Nose--Streamline-Emoji.svg +19 -0
  275. package/src/emoji2/Face-With-Symbols-On-Mouth--Streamline-Emoji.svg +22 -0
  276. package/src/emoji2/Face-With-Tears-Of-Joy--Streamline-Emoji.svg +34 -0
  277. package/src/emoji2/Face-With-Thermometer--Streamline-Emoji.svg +31 -0
  278. package/src/emoji2/Face-With-Tongue--Streamline-Emoji.svg +18 -0
  279. package/src/emoji2/Face-Without-Mouth--Streamline-Emoji.svg +14 -0
  280. package/src/emoji2/Fearful-Face--Streamline-Emoji.svg +18 -0
  281. package/src/emoji2/Flexed-Biceps-1--Streamline-Emoji.svg +13 -0
  282. package/src/emoji2/Flushed-Face--Streamline-Emoji.svg +19 -0
  283. package/src/emoji2/Folded-Hands-1--Streamline-Emoji.svg +29 -0
  284. package/src/emoji2/Frowning-Face--Streamline-Emoji.svg +15 -0
  285. package/src/emoji2/Fuel-Pump--Streamline-Emoji.svg +30 -0
  286. package/src/emoji2/Girl-1--Streamline-Emoji.svg +23 -0
  287. package/src/emoji2/Glasses-1--Streamline-Emoji.svg +27 -0
  288. package/src/emoji2/Grimacing-Face--Streamline-Emoji.svg +19 -0
  289. package/src/emoji2/Grinning-Cat-Face--Streamline-Emoji.svg +32 -0
  290. package/src/emoji2/Grinning-Face--Streamline-Emoji.svg +16 -0
  291. package/src/emoji2/Grinning-Face-With-Sweat--Streamline-Emoji.svg +19 -0
  292. package/src/emoji2/Grinning-Squinting-Face--Streamline-Emoji.svg +16 -0
  293. package/src/emoji2/Hand-With-Fingers-Splayed-1--Streamline-Emoji.svg +14 -0
  294. package/src/emoji2/Heart-Suit--Streamline-Emoji.svg +9 -0
  295. package/src/emoji2/Hushed-Face-1--Streamline-Emoji.svg +17 -0
  296. package/src/emoji2/Hushed-Face-2--Streamline-Emoji.svg +15 -0
  297. package/src/emoji2/Index-Pointing-Up-1--Streamline-Emoji.svg +17 -0
  298. package/src/emoji2/Kissing-Face-With-Closed-Eyes--Streamline-Emoji.svg +18 -0
  299. package/src/emoji2/Loudly-Crying-Face--Streamline-Emoji.svg +16 -0
  300. package/src/emoji2/Lying-Face--Streamline-Emoji.svg +15 -0
  301. package/src/emoji2/Man-1--Streamline-Emoji.svg +17 -0
  302. package/src/emoji2/Man-Facepalming-1--Streamline-Emoji.svg +21 -0
  303. package/src/emoji2/Man-Gesturing-No-1--Streamline-Emoji.svg +34 -0
  304. package/src/emoji2/Man-Gesturing-Ok-1--Streamline-Emoji.svg +25 -0
  305. package/src/emoji2/Man-Health-Worker-1--Streamline-Emoji.svg +41 -0
  306. package/src/emoji2/Man-Raising-Hand-1--Streamline-Emoji.svg +26 -0
  307. package/src/emoji2/Man-Shrugging-1--Streamline-Emoji.svg +31 -0
  308. package/src/emoji2/Money-Mouth-Face-2--Streamline-Emoji.svg +30 -0
  309. package/src/emoji2/Mouth--Streamline-Emoji.svg +12 -0
  310. package/src/emoji2/Nauseated-Face-2--Streamline-Emoji.svg +19 -0
  311. package/src/emoji2/Neutral-Face--Streamline-Emoji.svg +15 -0
  312. package/src/emoji2/Ok-Hand-1--Streamline-Emoji.svg +14 -0
  313. package/src/emoji2/Old-Man-1--Streamline-Emoji.svg +27 -0
  314. package/src/emoji2/Old-Woman-1--Streamline-Emoji.svg +23 -0
  315. package/src/emoji2/Oncoming-Fist-1--Streamline-Emoji.svg +15 -0
  316. package/src/emoji2/Person-Wearing-Turban-2--Streamline-Emoji.svg +20 -0
  317. package/src/emoji2/Pile-Of-Poo--Streamline-Emoji.svg +15 -0
  318. package/src/emoji2/Police-Car-Light--Streamline-Emoji.svg +26 -0
  319. package/src/emoji2/Rocket--Streamline-Emoji.svg +32 -0
  320. package/src/emoji2/Sailboat--Streamline-Emoji.svg +18 -0
  321. package/src/emoji2/Shaved-Ice--Streamline-Emoji.svg +21 -0
  322. package/src/emoji2/Shortcake-2--Streamline-Emoji.svg +18 -0
  323. package/src/emoji2/Shushing-Face--Streamline-Emoji.svg +21 -0
  324. package/src/emoji2/Sign-Of-The-Horns-1--Streamline-Emoji.svg +19 -0
  325. package/src/emoji2/Sleeping-Face--Streamline-Emoji.svg +21 -0
  326. package/src/emoji2/Slightly-Smiling-Face--Streamline-Emoji.svg +15 -0
  327. package/src/emoji2/Smiling-Face-With-Halo--Streamline-Emoji.svg +20 -0
  328. package/src/emoji2/Smiling-Face-With-Heart-Eyes--Streamline-Emoji.svg +21 -0
  329. package/src/emoji2/Smirking-Face--Streamline-Emoji.svg +17 -0
  330. package/src/emoji2/Sun-With-Face--Streamline-Emoji.svg +24 -0
  331. package/src/emoji2/Thumbs-Down-1--Streamline-Emoji.svg +20 -0
  332. package/src/emoji2/Thumbs-Up-1--Streamline-Emoji.svg +19 -0
  333. package/src/emoji2/Winking-Face--Streamline-Emoji.svg +18 -0
  334. package/src/emoji2/Woman-Gesturing-No-1--Streamline-Emoji.svg +34 -0
  335. package/src/emoji2/Woman-Gesturing-Ok-2--Streamline-Emoji.svg +25 -0
  336. package/src/emoji2/Woman-Raising-Hand-1--Streamline-Emoji.svg +26 -0
  337. package/src/emoji2/Womans-Sandal--Streamline-Emoji.svg +13 -0
  338. package/src/emoji2/Worried-Face--Streamline-Emoji.svg +17 -0
  339. package/src/emoji2/Writing-Hand-1--Streamline-Emoji.svg +17 -0
  340. package/src/emoji2/Zipper-Mouth-Face--Streamline-Emoji.svg +21 -0
  341. package/src/index.js +19 -0
  342. package/src/services/burn-after-read-service.js +313 -0
  343. package/src/services/burn-after-read-service.test.js +325 -0
  344. package/src/services/dify-api.js +338 -0
  345. package/src/services/dify-api.test.js +376 -0
  346. package/src/services/scheduled-send-service.js +311 -0
  347. package/src/services/scheduled-send-service.test.js +317 -0
  348. package/src/styles/index.css +2368 -0
  349. package/src/utils/emoji.js +125 -0
  350. package/src/utils/emojiData.js +267 -0
  351. package/src/utils/eventEmitter.js +114 -0
  352. package/src/utils/state.js +224 -0
  353. package/src/utils/state.test.js +198 -0
  354. package/src/utils/storage.js +122 -0
  355. package/src/utils/storage.test.js +162 -0
  356. package/src/utils/validation.js +249 -0
@@ -0,0 +1,963 @@
1
+ <template>
2
+ <div class="ai-chat-widget">
3
+ <!-- 浮动触发按钮 -->
4
+ <transition name="fade">
5
+ <div
6
+ v-if="!isOpen"
7
+ :class="['ai-chat-trigger', { pulse: showPulse, dragging: isTriggerDragging }]"
8
+ :style="triggerStyle"
9
+ @mousedown="startTriggerDrag"
10
+ >
11
+ <slot name="trigger" :is-open="isOpen" :unread-count="unreadCount">
12
+ <img v-if="triggerImage" :src="triggerImage" class="trigger-image" alt="AI助手" />
13
+ <i v-else class="ri-robot-line trigger-icon"></i>
14
+ <span v-if="showBadge && unreadCount > 0" class="trigger-badge badge">
15
+ {{ unreadCount > 99 ? '99+' : unreadCount }}
16
+ </span>
17
+ </slot>
18
+ </div>
19
+ </transition>
20
+ <!-- 对话框窗口 -->
21
+ <transition name="slide-up">
22
+ <div
23
+ v-if="isOpen"
24
+ ref="dialogRef"
25
+ :class="['ai-chat-dialog', { maximized: isMaximized, dragging: isDragging }]"
26
+ :style="dialogStyle"
27
+ >
28
+ <!-- 对话框头部 -->
29
+ <div
30
+ class="ai-chat-dialog-header"
31
+ :style="{ background: headerColor }"
32
+ @mousedown="startDrag"
33
+ >
34
+ <div class="header-left">
35
+ <slot name="header" :title="title" :is-maximized="isMaximized">
36
+ <div class="header-info">
37
+ <div class="header-title">{{ title }}</div>
38
+ <div v-if="subtitle" class="header-subtitle">{{ subtitle }}</div>
39
+ </div>
40
+ </slot>
41
+ </div>
42
+ <div class="header-actions">
43
+ <button
44
+ class="header-btn"
45
+ title="最小化"
46
+ @click.stop="minimizeDialog"
47
+ >
48
+ <i class="ri-subtract-line"></i>
49
+ </button>
50
+ <button
51
+ class="header-btn"
52
+ :title="isMaximized ? '还原' : '最大化'"
53
+ @click.stop="toggleMaximize"
54
+ >
55
+ <i :class="isMaximized ? 'ri-contract-line' : 'ri-expand-diagonal-line'"></i>
56
+ </button>
57
+ <button
58
+ class="header-btn header-btn-close close-btn"
59
+ title="关闭"
60
+ @click.stop="closeDialog"
61
+ >
62
+ <i class="ri-close-line"></i>
63
+ </button>
64
+ </div>
65
+ </div>
66
+ <!-- 对话框内容 -->
67
+ <div class="ai-chat-dialog-body">
68
+ <!-- 快捷操作 -->
69
+ <div
70
+ v-if="showQuickActions && quickActions.length > 0 && !hasMessages"
71
+ class="quick-actions-container"
72
+ >
73
+ <div class="quick-actions-title">快速开始</div>
74
+ <div class="quick-actions-list">
75
+ <button
76
+ v-for="(action, index) in quickActions"
77
+ :key="index"
78
+ class="quick-action-btn"
79
+ @click="handleQuickAction(action)"
80
+ >
81
+ <i v-if="action.icon" :class="action.icon" class="action-icon"></i>
82
+ <span>{{ action.text }}</span>
83
+ </button>
84
+ </div>
85
+ </div>
86
+ <!-- AiChat 组件 -->
87
+ <AiChat
88
+ ref="chatRef"
89
+ chat-type="ai"
90
+ :chat-user="chatUser"
91
+ :current-user-id="currentUserId"
92
+ :current-user-avatar="currentUserAvatar"
93
+ :ai-config="aiConfig"
94
+ :initial-messages="initialMessages"
95
+ :hidden-tools="hiddenTools"
96
+ :show-back-button="false"
97
+ :show-close-button="false"
98
+ :is-mobile="isMobile"
99
+ :enable-ai-config-hot-reload="enableAiConfigHotReload"
100
+ @send="handleSend"
101
+ @aiResponseStart="handleAiResponseStart"
102
+ @aiResponseComplete="handleAiResponseComplete"
103
+ @aiResponseError="handleAiResponseError"
104
+ @conversationUpdate="handleConversationUpdate"
105
+ @aiConfigUpdate="handleAiConfigUpdate"
106
+ v-bind="$attrs"
107
+ >
108
+ <!-- 传递所有插槽 -->
109
+ <template v-for="(_, name) in $slots" #[name]="slotData">
110
+ <slot :name="name" v-bind="slotData"></slot>
111
+ </template>
112
+ </AiChat>
113
+ </div>
114
+ <!-- 调整大小手柄 -->
115
+ <div
116
+ v-if="resizable && !isMaximized && !isMobile"
117
+ class="resize-handle resize-handle-se"
118
+ @mousedown.stop="startResize"
119
+ ></div>
120
+ </div>
121
+ </transition>
122
+ <!-- 遮罩层 -->
123
+ <transition name="fade">
124
+ <div
125
+ v-if="isOpen && showMask"
126
+ class="ai-chat-mask"
127
+ :style="{ zIndex: zIndex - 1 }"
128
+ @click="handleMaskClick"
129
+ ></div>
130
+ </transition>
131
+ </div>
132
+ </template>
133
+ <script>
134
+ import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue';
135
+ import AiChat from './AiChat.vue';
136
+ export default {
137
+ name: 'AiChatWidget',
138
+ components: {
139
+ AiChat
140
+ },
141
+ inheritAttrs: false,
142
+ props: {
143
+ // === 位置配置 ===
144
+ position: {
145
+ type: String,
146
+ default: 'bottom-right',
147
+ validator: (value) => ['bottom-right', 'bottom-left', 'top-right', 'top-left'].includes(value)
148
+ },
149
+ offset: {
150
+ type: Object,
151
+ default: () => ({ x: 20, y: 20 })
152
+ },
153
+ // === 尺寸配置 ===
154
+ defaultSize: {
155
+ type: Object,
156
+ default: () => ({ width: 400, height: 600 })
157
+ },
158
+ minSize: {
159
+ type: Object,
160
+ default: () => ({ width: 320, height: 400 })
161
+ },
162
+ maxSize: {
163
+ type: Object,
164
+ default: () => ({ width: 800, height: 900 })
165
+ },
166
+ // === 行为配置 ===
167
+ draggable: {
168
+ type: Boolean,
169
+ default: true
170
+ },
171
+ triggerDraggable: {
172
+ type: Boolean,
173
+ default: true
174
+ },
175
+ resizable: {
176
+ type: Boolean,
177
+ default: true
178
+ },
179
+ defaultOpen: {
180
+ type: Boolean,
181
+ default: false
182
+ },
183
+ showMask: {
184
+ type: Boolean,
185
+ default: false
186
+ },
187
+ closeOnMaskClick: {
188
+ type: Boolean,
189
+ default: true
190
+ },
191
+ // === 触发按钮配置 ===
192
+ buttonIcon: {
193
+ type: String,
194
+ default: 'ri-robot-line'
195
+ },
196
+ buttonText: {
197
+ type: String,
198
+ default: ''
199
+ },
200
+ triggerImage: {
201
+ type: String,
202
+ default: ''
203
+ },
204
+ showBadge: {
205
+ type: Boolean,
206
+ default: true
207
+ },
208
+ badgeCount: {
209
+ type: Number,
210
+ default: 0
211
+ },
212
+ showPulse: {
213
+ type: Boolean,
214
+ default: true
215
+ },
216
+ // === 工具栏配置 ===
217
+ hiddenTools: {
218
+ type: Array,
219
+ default: () => ['location', 'card', 'voice', 'video']
220
+ },
221
+ // === AI 配置(继承自 AiChat) ===
222
+ aiConfig: {
223
+ type: Object,
224
+ required: true
225
+ },
226
+ currentUserId: {
227
+ type: String,
228
+ required: true
229
+ },
230
+ currentUserAvatar: {
231
+ type: String,
232
+ default: ''
233
+ },
234
+ chatUser: {
235
+ type: Object,
236
+ default: () => ({
237
+ id: 'ai_assistant',
238
+ name: 'AI 助手',
239
+ avatar: '',
240
+ account: 'ai'
241
+ })
242
+ },
243
+ initialMessages: {
244
+ type: Array,
245
+ default: () => []
246
+ },
247
+ enableAiConfigHotReload: {
248
+ type: Boolean,
249
+ default: true
250
+ },
251
+ // === 样式配置 ===
252
+ theme: {
253
+ type: String,
254
+ default: 'light',
255
+ validator: (value) => ['light', 'dark'].includes(value)
256
+ },
257
+ zIndex: {
258
+ type: Number,
259
+ default: 1000
260
+ },
261
+ headerColor: {
262
+ type: String,
263
+ default: '#0067CC'
264
+ },
265
+ // === 其他 ===
266
+ title: {
267
+ type: String,
268
+ default: 'AI 助手'
269
+ },
270
+ subtitle: {
271
+ type: String,
272
+ default: ''
273
+ },
274
+ showWelcome: {
275
+ type: Boolean,
276
+ default: true
277
+ },
278
+ // === 快捷操作配置 ===
279
+ quickActions: {
280
+ type: Array,
281
+ default: () => []
282
+ // 格式: [{ text: '创建报表', workflowId: 'workflow-001' }]
283
+ },
284
+ showQuickActions: {
285
+ type: Boolean,
286
+ default: true
287
+ }
288
+ },
289
+ emits: [
290
+ 'open', 'close', 'minimize', 'maximize', 'restore', 'drag', 'resize',
291
+ 'send', 'aiResponseStart', 'aiResponseComplete', 'aiResponseError',
292
+ 'conversationUpdate', 'aiConfigUpdate', 'quickAction'
293
+ ],
294
+ setup(props, { emit }) {
295
+ // Refs
296
+ const dialogRef = ref(null);
297
+ const chatRef = ref(null);
298
+ // 状态
299
+ const isOpen = ref(props.defaultOpen);
300
+ const isMaximized = ref(false);
301
+ const isDragging = ref(false);
302
+ const isResizing = ref(false);
303
+ const unreadCount = ref(props.badgeCount);
304
+ const hasMessages = ref(props.initialMessages.length > 0);
305
+ // 调试:输出初始状态
306
+ console.log('[AiChatWidget] 初始化:', {
307
+ defaultOpen: props.defaultOpen,
308
+ isOpen: isOpen.value,
309
+ position: props.position,
310
+ windowWidth: window.innerWidth,
311
+ isMobileCheck: window.innerWidth < 768
312
+ });
313
+ // 位置和尺寸
314
+ const dialogPosition = ref({ x: 0, y: 0 });
315
+ const dialogSize = ref({ ...props.defaultSize });
316
+ const savedPosition = ref({ x: 0, y: 0 });
317
+ const savedSize = ref({ ...props.defaultSize });
318
+ // 触发按钮位置
319
+ const triggerPosition = ref(null);
320
+ const isTriggerDragging = ref(false);
321
+ // 拖拽相关
322
+ const dragOffset = ref({ x: 0, y: 0 });
323
+ const resizeStart = ref({ x: 0, y: 0, width: 0, height: 0 });
324
+ // 响应式检测
325
+ const isMobile = computed(() => {
326
+ return window.innerWidth < 768;
327
+ });
328
+ // 触发按钮样式
329
+ const triggerStyle = computed(() => {
330
+ const style = {
331
+ zIndex: props.zIndex
332
+ };
333
+ // 如果已经拖动过,使用保存的位置
334
+ if (triggerPosition.value) {
335
+ style.left = `${triggerPosition.value.x}px`;
336
+ style.top = `${triggerPosition.value.y}px`;
337
+ return style;
338
+ }
339
+ // 否则使用默认位置
340
+ const [vertical, horizontal] = props.position.split('-');
341
+ style[vertical] = `${props.offset.y}px`;
342
+ style[horizontal] = `${props.offset.x}px`;
343
+ return style;
344
+ });
345
+ // 对话框样式
346
+ const dialogStyle = computed(() => {
347
+ if (isMaximized.value) {
348
+ return {
349
+ top: 0,
350
+ left: 0,
351
+ width: '100vw',
352
+ height: '100vh',
353
+ zIndex: props.zIndex
354
+ };
355
+ }
356
+ return {
357
+ top: `${dialogPosition.value.y}px`,
358
+ left: `${dialogPosition.value.x}px`,
359
+ width: `${dialogSize.value.width}px`,
360
+ height: `${dialogSize.value.height}px`,
361
+ zIndex: props.zIndex
362
+ };
363
+ });
364
+ // 计算初始位置
365
+ const calculateInitialPosition = () => {
366
+ const [vertical, horizontal] = props.position.split('-');
367
+ const x = horizontal === 'right'
368
+ ? window.innerWidth - dialogSize.value.width - props.offset.x
369
+ : props.offset.x;
370
+ const y = vertical === 'bottom'
371
+ ? window.innerHeight - dialogSize.value.height - props.offset.y
372
+ : props.offset.y;
373
+ dialogPosition.value = { x, y };
374
+ };
375
+ // 打开对话框
376
+ const openDialog = () => {
377
+ isOpen.value = true;
378
+ calculateInitialPosition();
379
+ unreadCount.value = 0;
380
+ emit('open');
381
+ // 移动端自动最大化
382
+ if (isMobile.value) {
383
+ isMaximized.value = true;
384
+ }
385
+ };
386
+ // 关闭对话框
387
+ const closeDialog = () => {
388
+ isOpen.value = false;
389
+ isMaximized.value = false;
390
+ emit('close');
391
+ };
392
+ // 最小化对话框
393
+ const minimizeDialog = () => {
394
+ isOpen.value = false;
395
+ emit('minimize');
396
+ };
397
+ // 切换最大化
398
+ const toggleMaximize = () => {
399
+ if (isMaximized.value) {
400
+ // 还原
401
+ dialogPosition.value = { ...savedPosition.value };
402
+ dialogSize.value = { ...savedSize.value };
403
+ isMaximized.value = false;
404
+ emit('restore');
405
+ } else {
406
+ // 保存当前状态
407
+ savedPosition.value = { ...dialogPosition.value };
408
+ savedSize.value = { ...dialogSize.value };
409
+ // 最大化
410
+ isMaximized.value = true;
411
+ emit('maximize');
412
+ }
413
+ };
414
+ // 开始拖拽
415
+ const startDrag = (e) => {
416
+ if (!props.draggable || isMaximized.value || isMobile.value) return;
417
+ isDragging.value = true;
418
+ const rect = dialogRef.value.getBoundingClientRect();
419
+ dragOffset.value = {
420
+ x: e.clientX - rect.left,
421
+ y: e.clientY - rect.top
422
+ };
423
+ document.addEventListener('mousemove', onDrag);
424
+ document.addEventListener('mouseup', stopDrag);
425
+ };
426
+ // 拖拽中
427
+ const onDrag = (e) => {
428
+ if (!isDragging.value) return;
429
+ let x = e.clientX - dragOffset.value.x;
430
+ let y = e.clientY - dragOffset.value.y;
431
+ // 限制在视口内
432
+ const maxX = window.innerWidth - dialogSize.value.width;
433
+ const maxY = window.innerHeight - dialogSize.value.height;
434
+ x = Math.max(0, Math.min(x, maxX));
435
+ y = Math.max(0, Math.min(y, maxY));
436
+ dialogPosition.value = { x, y };
437
+ emit('drag', { x, y });
438
+ };
439
+ // 停止拖拽
440
+ const stopDrag = () => {
441
+ isDragging.value = false;
442
+ document.removeEventListener('mousemove', onDrag);
443
+ document.removeEventListener('mouseup', stopDrag);
444
+ };
445
+ // 触发按钮拖动相关
446
+ const triggerDragStart = ref({ x: 0, y: 0 });
447
+ const hasMoved = ref(false);
448
+ const dragThreshold = 5; // 拖拽阈值(像素)
449
+
450
+ const startTriggerDrag = (e) => {
451
+ if (!props.triggerDraggable || isMobile.value) {
452
+ openDialog();
453
+ return;
454
+ }
455
+ e.preventDefault();
456
+ // 记录起始位置
457
+ triggerDragStart.value = { x: e.clientX, y: e.clientY };
458
+ hasMoved.value = false;
459
+ // 计算初始位置(如果还没有保存过位置)
460
+ if (!triggerPosition.value) {
461
+ const [vertical, horizontal] = props.position.split('-');
462
+ const x = horizontal === 'right'
463
+ ? window.innerWidth - 60 - props.offset.x
464
+ : props.offset.x;
465
+ const y = vertical === 'bottom'
466
+ ? window.innerHeight - 60 - props.offset.y
467
+ : props.offset.y;
468
+ triggerPosition.value = { x, y };
469
+ }
470
+ dragOffset.value = {
471
+ x: e.clientX - triggerPosition.value.x,
472
+ y: e.clientY - triggerPosition.value.y
473
+ };
474
+ // 只添加 mousemove 监听来检测是否开始拖拽
475
+ document.addEventListener('mousemove', checkDragStart);
476
+ document.addEventListener('mouseup', stopTriggerDrag);
477
+ };
478
+
479
+ const checkDragStart = (e) => {
480
+ const deltaX = Math.abs(e.clientX - triggerDragStart.value.x);
481
+ const deltaY = Math.abs(e.clientY - triggerDragStart.value.y);
482
+
483
+ if (deltaX > dragThreshold || deltaY > dragThreshold) {
484
+ // 超过阈值,开始真正的拖拽
485
+ hasMoved.value = true;
486
+ isTriggerDragging.value = true;
487
+ document.removeEventListener('mousemove', checkDragStart);
488
+ document.addEventListener('mousemove', onTriggerDrag);
489
+ }
490
+ };
491
+
492
+ const onTriggerDrag = (e) => {
493
+ let x = e.clientX - dragOffset.value.x;
494
+ let y = e.clientY - dragOffset.value.y;
495
+ // 限制在视口内(按钮大小 60px)
496
+ const maxX = window.innerWidth - 60;
497
+ const maxY = window.innerHeight - 60;
498
+ x = Math.max(0, Math.min(x, maxX));
499
+ y = Math.max(0, Math.min(y, maxY));
500
+ triggerPosition.value = { x, y };
501
+ };
502
+
503
+ const stopTriggerDrag = (e) => {
504
+ document.removeEventListener('mousemove', checkDragStart);
505
+ document.removeEventListener('mousemove', onTriggerDrag);
506
+ document.removeEventListener('mouseup', stopTriggerDrag);
507
+
508
+ // 如果没有移动,触发点击打开对话框
509
+ if (!hasMoved.value) {
510
+ openDialog();
511
+ }
512
+
513
+ // 重置状态
514
+ setTimeout(() => {
515
+ isTriggerDragging.value = false;
516
+ hasMoved.value = false;
517
+ }, 50);
518
+ };
519
+ // 开始调整大小
520
+ const startResize = (e) => {
521
+ if (!props.resizable) return;
522
+ isResizing.value = true;
523
+ resizeStart.value = {
524
+ x: e.clientX,
525
+ y: e.clientY,
526
+ width: dialogSize.value.width,
527
+ height: dialogSize.value.height
528
+ };
529
+ document.addEventListener('mousemove', onResize);
530
+ document.addEventListener('mouseup', stopResize);
531
+ };
532
+ // 调整大小中
533
+ const onResize = (e) => {
534
+ if (!isResizing.value) return;
535
+ const deltaX = e.clientX - resizeStart.value.x;
536
+ const deltaY = e.clientY - resizeStart.value.y;
537
+ let newWidth = resizeStart.value.width + deltaX;
538
+ let newHeight = resizeStart.value.height + deltaY;
539
+ // 应用尺寸限制
540
+ newWidth = Math.max(props.minSize.width, Math.min(newWidth, props.maxSize.width));
541
+ newHeight = Math.max(props.minSize.height, Math.min(newHeight, props.maxSize.height));
542
+ dialogSize.value = { width: newWidth, height: newHeight };
543
+ emit('resize', { width: newWidth, height: newHeight });
544
+ };
545
+ // 停止调整大小
546
+ const stopResize = () => {
547
+ isResizing.value = false;
548
+ document.removeEventListener('mousemove', onResize);
549
+ document.removeEventListener('mouseup', stopResize);
550
+ };
551
+ // 处理遮罩点击
552
+ const handleMaskClick = () => {
553
+ if (props.closeOnMaskClick) {
554
+ closeDialog();
555
+ }
556
+ };
557
+ // 事件处理
558
+ const handleSend = (data) => {
559
+ hasMessages.value = true;
560
+ emit('send', data);
561
+ };
562
+ const handleAiResponseStart = (data) => {
563
+ emit('aiResponseStart', data);
564
+ };
565
+ const handleAiResponseComplete = (data) => {
566
+ emit('aiResponseComplete', data);
567
+ };
568
+ const handleAiResponseError = (data) => {
569
+ emit('aiResponseError', data);
570
+ };
571
+ const handleConversationUpdate = (data) => {
572
+ emit('conversationUpdate', data);
573
+ };
574
+ const handleAiConfigUpdate = (data) => {
575
+ emit('aiConfigUpdate', data);
576
+ };
577
+ // 处理快捷操作点击
578
+ const handleQuickAction = (action) => {
579
+ emit('quickAction', action);
580
+ // 如果有工作流 ID,更新 AI 配置
581
+ if (action.workflowId) {
582
+ const updatedConfig = {
583
+ ...props.aiConfig,
584
+ agentId: action.workflowId
585
+ };
586
+ emit('aiConfigUpdate', { config: updatedConfig, success: true });
587
+ }
588
+ // 发送快捷操作文本作为消息
589
+ if (action.text) {
590
+ handleSend({
591
+ message: {
592
+ content: action.text,
593
+ type: 'text'
594
+ },
595
+ content: action.text
596
+ });
597
+ }
598
+ };
599
+ // 监听 badgeCount 变化
600
+ watch(() => props.badgeCount, (newCount) => {
601
+ unreadCount.value = newCount;
602
+ });
603
+ // 调试:监听 isOpen 变化
604
+ watch(isOpen, (newVal, oldVal) => {
605
+ console.log('[AiChatWidget] isOpen 变化:', {
606
+ from: oldVal,
607
+ to: newVal,
608
+ stack: new Error().stack
609
+ });
610
+ });
611
+ // 监听窗口大小变化
612
+ const handleResize = () => {
613
+ if (isOpen.value && !isMaximized.value) {
614
+ // 确保对话框在视口内
615
+ const maxX = window.innerWidth - dialogSize.value.width;
616
+ const maxY = window.innerHeight - dialogSize.value.height;
617
+ if (dialogPosition.value.x > maxX) {
618
+ dialogPosition.value.x = Math.max(0, maxX);
619
+ }
620
+ if (dialogPosition.value.y > maxY) {
621
+ dialogPosition.value.y = Math.max(0, maxY);
622
+ }
623
+ }
624
+ };
625
+ onMounted(() => {
626
+ window.addEventListener('resize', handleResize);
627
+ console.log('[AiChatWidget] onMounted:', {
628
+ isOpen: isOpen.value,
629
+ isMobile: isMobile.value,
630
+ windowWidth: window.innerWidth
631
+ });
632
+ // 如果默认打开,计算初始位置
633
+ if (isOpen.value) {
634
+ console.log('[AiChatWidget] 默认打开,计算位置');
635
+ calculateInitialPosition();
636
+ // 移动端自动最大化
637
+ if (isMobile.value) {
638
+ console.log('[AiChatWidget] 移动端,自动最大化');
639
+ isMaximized.value = true;
640
+ }
641
+ }
642
+ });
643
+ onBeforeUnmount(() => {
644
+ window.removeEventListener('resize', handleResize);
645
+ document.removeEventListener('mousemove', onDrag);
646
+ document.removeEventListener('mouseup', stopDrag);
647
+ document.removeEventListener('mousemove', onResize);
648
+ document.removeEventListener('mouseup', stopResize);
649
+ document.removeEventListener('mousemove', onTriggerDrag);
650
+ document.removeEventListener('mouseup', stopTriggerDrag);
651
+ });
652
+ return {
653
+ dialogRef,
654
+ chatRef,
655
+ isOpen,
656
+ isMaximized,
657
+ isDragging,
658
+ isResizing,
659
+ isTriggerDragging,
660
+ unreadCount,
661
+ hasMessages,
662
+ dialogPosition,
663
+ dialogSize,
664
+ isMobile,
665
+ triggerStyle,
666
+ dialogStyle,
667
+ openDialog,
668
+ closeDialog,
669
+ minimizeDialog,
670
+ toggleMaximize,
671
+ startDrag,
672
+ startResize,
673
+ startTriggerDrag,
674
+ handleMaskClick,
675
+ handleSend,
676
+ handleAiResponseStart,
677
+ handleAiResponseComplete,
678
+ handleAiResponseError,
679
+ handleConversationUpdate,
680
+ handleAiConfigUpdate,
681
+ handleQuickAction,
682
+ // 暴露的公共方法
683
+ open: openDialog,
684
+ close: closeDialog,
685
+ minimize: minimizeDialog,
686
+ maximize: () => {
687
+ if (!isMaximized.value) toggleMaximize();
688
+ },
689
+ restore: () => {
690
+ if (isMaximized.value) toggleMaximize();
691
+ },
692
+ getIsOpen: () => isOpen.value,
693
+ getIsMaximized: () => isMaximized.value
694
+ };
695
+ }
696
+ };
697
+ </script>
698
+ <style scoped>
699
+ /* 浮动触发按钮 */
700
+ .ai-chat-trigger {
701
+ position: fixed;
702
+ width: 60px;
703
+ height: 60px;
704
+ border-radius: 50%;
705
+ background: #0067CC;
706
+ box-shadow: 0 4px 12px rgba(0, 103, 204, 0.4);
707
+ cursor: move;
708
+ display: flex;
709
+ align-items: center;
710
+ justify-content: center;
711
+ transition: all 0.3s ease;
712
+ user-select: none;
713
+ }
714
+ .ai-chat-trigger.dragging {
715
+ transition: none;
716
+ cursor: grabbing;
717
+ opacity: 0.9;
718
+ }
719
+ .ai-chat-trigger:hover {
720
+ transform: scale(1.1);
721
+ box-shadow: 0 6px 20px rgba(0, 103, 204, 0.6);
722
+ }
723
+ .ai-chat-trigger.pulse {
724
+ animation: pulse 2s infinite;
725
+ }
726
+ @keyframes pulse {
727
+ 0%, 100% {
728
+ box-shadow: 0 4px 12px rgba(0, 103, 204, 0.4);
729
+ }
730
+ 50% {
731
+ box-shadow: 0 4px 20px rgba(0, 103, 204, 0.8);
732
+ }
733
+ }
734
+ .trigger-icon {
735
+ font-size: 28px;
736
+ color: white;
737
+ }
738
+ .trigger-image {
739
+ width: 40px;
740
+ height: 40px;
741
+ object-fit: contain;
742
+ }
743
+ .trigger-badge {
744
+ position: absolute;
745
+ top: -5px;
746
+ right: -5px;
747
+ min-width: 20px;
748
+ height: 20px;
749
+ padding: 0 6px;
750
+ background: #ff4757;
751
+ color: white;
752
+ border-radius: 10px;
753
+ font-size: 12px;
754
+ font-weight: bold;
755
+ display: flex;
756
+ align-items: center;
757
+ justify-content: center;
758
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
759
+ }
760
+ /* 对话框窗口 */
761
+ .ai-chat-dialog {
762
+ position: fixed;
763
+ background: white;
764
+ border-radius: 12px;
765
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
766
+ display: flex;
767
+ flex-direction: column;
768
+ overflow: hidden;
769
+ transition: all 0.3s ease;
770
+ }
771
+ .ai-chat-dialog.maximized {
772
+ border-radius: 0 !important;
773
+ }
774
+ .ai-chat-dialog.dragging {
775
+ transition: none;
776
+ cursor: move;
777
+ }
778
+ /* 对话框头部 */
779
+ .ai-chat-dialog-header {
780
+ display: flex;
781
+ align-items: center;
782
+ justify-content: space-between;
783
+ padding: 12px 16px;
784
+ background: #0067CC;
785
+ color: white;
786
+ cursor: move;
787
+ user-select: none;
788
+ min-height: 50px;
789
+ }
790
+ .header-left {
791
+ flex: 1;
792
+ min-width: 0;
793
+ }
794
+ .header-info {
795
+ display: flex;
796
+ flex-direction: column;
797
+ gap: 2px;
798
+ }
799
+ .header-title {
800
+ font-size: 16px;
801
+ font-weight: 600;
802
+ white-space: nowrap;
803
+ overflow: hidden;
804
+ text-overflow: ellipsis;
805
+ }
806
+ .header-subtitle {
807
+ font-size: 12px;
808
+ opacity: 0.9;
809
+ white-space: nowrap;
810
+ overflow: hidden;
811
+ text-overflow: ellipsis;
812
+ }
813
+ .header-actions {
814
+ display: flex;
815
+ gap: 8px;
816
+ align-items: center;
817
+ }
818
+ .header-btn {
819
+ width: 32px;
820
+ height: 32px;
821
+ border: none;
822
+ background: rgba(255, 255, 255, 0.2);
823
+ color: white;
824
+ border-radius: 6px;
825
+ cursor: pointer;
826
+ display: flex;
827
+ align-items: center;
828
+ justify-content: center;
829
+ transition: all 0.2s;
830
+ font-size: 18px;
831
+ }
832
+ .header-btn:hover {
833
+ background: rgba(255, 255, 255, 0.3);
834
+ }
835
+ .header-btn-close:hover {
836
+ background: rgba(255, 77, 87, 0.9);
837
+ }
838
+ /* 对话框内容 */
839
+ .ai-chat-dialog-body {
840
+ flex: 1;
841
+ overflow: hidden;
842
+ position: relative;
843
+ display: flex;
844
+ flex-direction: column;
845
+ }
846
+ /* 快捷操作 */
847
+ .quick-actions-container {
848
+ padding: 16px;
849
+ background: #f8f9fa;
850
+ border-bottom: 1px solid #e9ecef;
851
+ }
852
+ .quick-actions-title {
853
+ font-size: 14px;
854
+ color: #666;
855
+ margin-bottom: 12px;
856
+ font-weight: 500;
857
+ }
858
+ .quick-actions-list {
859
+ display: flex;
860
+ flex-wrap: wrap;
861
+ gap: 8px;
862
+ }
863
+ .quick-action-btn {
864
+ display: inline-flex;
865
+ align-items: center;
866
+ gap: 6px;
867
+ padding: 8px 16px;
868
+ background: white;
869
+ border: 1px solid #0067CC;
870
+ color: #0067CC;
871
+ border-radius: 20px;
872
+ cursor: pointer;
873
+ font-size: 14px;
874
+ transition: all 0.2s ease;
875
+ white-space: nowrap;
876
+ }
877
+ .quick-action-btn:hover {
878
+ background: #0067CC;
879
+ color: white;
880
+ transform: translateY(-1px);
881
+ box-shadow: 0 2px 8px rgba(0, 103, 204, 0.2);
882
+ }
883
+ .action-icon {
884
+ font-size: 16px;
885
+ }
886
+ /* 调整大小手柄 */
887
+ .resize-handle {
888
+ position: absolute;
889
+ background: transparent;
890
+ }
891
+ .resize-handle-se {
892
+ right: 0;
893
+ bottom: 0;
894
+ width: 16px;
895
+ height: 16px;
896
+ cursor: se-resize;
897
+ }
898
+ .resize-handle-se::after {
899
+ content: '';
900
+ position: absolute;
901
+ right: 2px;
902
+ bottom: 2px;
903
+ width: 12px;
904
+ height: 12px;
905
+ border-right: 2px solid #ddd;
906
+ border-bottom: 2px solid #ddd;
907
+ }
908
+ /* 遮罩层 */
909
+ .ai-chat-mask {
910
+ position: fixed;
911
+ top: 0;
912
+ left: 0;
913
+ right: 0;
914
+ bottom: 0;
915
+ background: rgba(0, 0, 0, 0.3);
916
+ }
917
+ /* 动画 */
918
+ .fade-enter-active, .fade-leave-active {
919
+ transition: opacity 0.3s;
920
+ }
921
+ .fade-enter-from, .fade-leave-to {
922
+ opacity: 0;
923
+ }
924
+ .slide-up-enter-active {
925
+ animation: slideUp 0.3s ease;
926
+ }
927
+ .slide-up-leave-active {
928
+ animation: slideDown 0.3s ease;
929
+ }
930
+ @keyframes slideUp {
931
+ from {
932
+ transform: translateY(20px);
933
+ opacity: 0;
934
+ }
935
+ to {
936
+ transform: translateY(0);
937
+ opacity: 1;
938
+ }
939
+ }
940
+ @keyframes slideDown {
941
+ from {
942
+ transform: translateY(0);
943
+ opacity: 1;
944
+ }
945
+ to {
946
+ transform: translateY(20px);
947
+ opacity: 0;
948
+ }
949
+ }
950
+ /* 移动端适配 */
951
+ @media (max-width: 768px) {
952
+ .ai-chat-dialog {
953
+ border-radius: 0 !important;
954
+ top: 0 !important;
955
+ left: 0 !important;
956
+ width: 100vw !important;
957
+ height: 100vh !important;
958
+ }
959
+ .resize-handle {
960
+ display: none;
961
+ }
962
+ }
963
+ </style>