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
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ .im-container{display:flex;flex-direction:column;height:100%;background-color:#f5f5f5;font-family:PingFang SC,Microsoft YaHei,sans-serif;position:relative}.header{display:flex;align-items:center;padding:12px 16px;background-color:#fff;border-bottom:1px solid #e5e5e5;gap:12px}.header .ri-arrow-left-line{font-size:24px;cursor:pointer;color:#333;padding:4px}.header .ri-arrow-left-line:hover{color:#1890ff}.user-info{flex:1;display:flex;align-items:center;gap:12px;min-width:0}.user-avatar{width:40px;height:40px;border-radius:50%;overflow:hidden;flex-shrink:0}.user-avatar img{width:100%;height:100%;object-fit:cover}.user-details{flex:1;min-width:0}.user-name{font-size:16px;font-weight:600;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.user-account{font-size:12px;color:#999;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.user-status{font-size:12px;color:#999}.header-actions{display:flex;align-items:center;gap:12px}.header-more-icon,.header-close-icon{font-size:20px;cursor:pointer;color:#666;padding:4px;transition:color .2s}.header-more-icon:hover,.header-close-icon:hover{color:#1890ff}.main{flex:1;overflow:hidden;display:flex;flex-direction:column}.chatBox{flex:1;display:flex;flex-direction:column;overflow:hidden}.chatList{flex:none;overflow-y:auto;padding:16px;scroll-behavior:smooth;transition:height .1s ease;position:relative}.chatList::-webkit-scrollbar{width:6px}.chatList::-webkit-scrollbar-thumb{background-color:#0003;border-radius:3px}.chatList::-webkit-scrollbar-track{background-color:transparent}.chatList-item{margin-bottom:16px}.chatList-item--compact{margin-top:-8px}.chatList-time{text-align:center;font-size:12px;color:#999;margin-bottom:16px}.chatList-wrapper{display:flex;gap:12px;align-items:flex-start}.chatList-item--mine .chatList-wrapper{justify-content:flex-end}.chatList-avatar{width:40px;height:40px;border-radius:50%;overflow:hidden;flex-shrink:0}.chatList-avatar img{width:100%;height:100%;object-fit:cover}.chatList-avatar--placeholder{width:40px;height:40px;flex-shrink:0}.chatList-content{flex:0 1 auto;min-width:0;max-width:60%;display:flex;flex-direction:column}.chatList-item--mine .chatList-content{align-items:flex-end}.chatList-sender-name{font-size:12px;color:#666;margin-bottom:4px;padding-left:12px}.chatList-item--mine .chatList-sender-name{padding-left:0;padding-right:12px}.chatList-text{position:relative;padding:10px 14px;border-radius:8px;background-color:#fff;word-wrap:break-word;word-break:break-word;box-shadow:0 1px 2px #0000000d}.chatList-text--mine{background-color:#95ec69;color:#333}.chatList-text--ai{background-color:#fff;border:1px solid #e5e5e5}.chatList-text--group{background-color:#fff}.chatList-text--no-bg{background-color:transparent;box-shadow:none;padding:0;border-radius:0}.chatList-arrow{position:absolute;top:12px;width:0;height:0;border:6px solid transparent}.chatList-text .chatList-arrow{left:-12px;border-right-color:#fff}.chatList-text--mine .chatList-arrow{left:auto;right:-12px;border-left-color:#95ec69;border-right-color:transparent}.chatList-text--ai .chatList-arrow{border-right-color:#fff}.chatList__msg--text{margin:0;font-size:14px;line-height:1.6;white-space:pre-wrap}.chatList__msg--img{max-width:200px;max-height:200px;border-radius:4px;cursor:pointer;display:block}.chatList__msg--audio{width:200px;height:40px}.chatList__msg--voice{display:flex;align-items:center;gap:8px;padding:8px 12px;background-color:#f0f0f0;border-radius:6px;cursor:pointer;transition:all .2s;-webkit-user-select:none;user-select:none}.chatList__msg--voice:hover{background-color:#e8e8e8}.voice-play-icon{font-size:20px;color:#0067cc;flex-shrink:0}.voice-duration{font-size:14px;color:#333;min-width:30px}.chatList__msg--video{max-width:300px;max-height:200px;border-radius:4px}.streaming-indicator{display:inline-block;animation:blink 1s infinite;margin-left:4px;color:#1890ff}@keyframes blink{0%,50%{opacity:1}51%,to{opacity:0}}.chatList-loading{text-align:center;padding:20px}.loading-dots{display:inline-flex;gap:6px}.loading-dots span{width:8px;height:8px;border-radius:50%;background-color:#1890ff;animation:bounce 1.4s infinite ease-in-out both}.loading-dots span:nth-child(1){animation-delay:-.32s}.loading-dots span:nth-child(2){animation-delay:-.16s}@keyframes bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.resize-handle{height:8px;background-color:#f5f5f5;cursor:ns-resize;display:flex;align-items:center;justify-content:center;transition:background-color .2s;position:relative;-webkit-user-select:none;user-select:none}.resize-handle:hover{background-color:#e5e5e5}.resize-handle.resizing{background-color:#1890ff}.resize-line{width:40px;height:3px;background-color:#d9d9d9;border-radius:2px;transition:background-color .2s}.resize-handle:hover .resize-line,.resize-handle.resizing .resize-line{background-color:#1890ff}.toolBox{display:flex;justify-content:space-between;align-items:center;padding:8px 16px;background-color:#fff;border-top:1px solid #e5e5e5}.toolBox-left,.toolBox-right{display:flex;gap:16px}.tool-icon{font-size:20px;color:#666;cursor:pointer;transition:color .2s}.tool-icon:hover{color:#1890ff}.tool-icon.recording-active{color:#ff4d4f;animation:pulse 1s infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.writeBox{flex:1;display:flex;flex-direction:column;background-color:#fff;border-top:1px solid #e5e5e5}.recording-dialog{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100;background-color:#000000e6;border-radius:12px;padding:32px 48px;box-shadow:0 8px 24px #0000004d;animation:fadeIn .3s ease}.recording-dialog-content{display:flex;flex-direction:column;align-items:center;gap:16px}.recording-icon-large{width:80px;height:80px;border-radius:50%;background-color:#ff4d4f;display:flex;align-items:center;justify-content:center;animation:pulse 1.5s infinite}.recording-icon-large i{font-size:40px;color:#fff}.recording-text{font-size:16px;color:#fffc}.recording-stop-btn{display:flex;align-items:center;gap:8px;padding:12px 24px;background-color:#fff;color:#ff4d4f;border:none;border-radius:24px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;margin-top:8px}.recording-stop-btn:hover{background-color:#ff4d4f;color:#fff;transform:scale(1.05)}.recording-stop-btn i{font-size:18px}.recording-dialog-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:#000000b3;display:flex;align-items:center;justify-content:center;z-index:100;pointer-events:auto;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.recording-dialog-content{display:flex;flex-direction:column;align-items:center;gap:16px;background-color:#000000e6;border-radius:12px;padding:32px 48px;box-shadow:0 8px 24px #0000004d;animation:slideUp .3s ease}.recording-icon{width:80px;height:80px;border-radius:50%;background-color:#ff4d4f;display:flex;align-items:center;justify-content:center;animation:pulse 1.5s infinite;transition:all .2s}.recording-icon i{font-size:40px;color:#fff}.recording-icon.cancel-mode{background-color:#ff7875;transform:scale(1.1)}.recording-icon.voice-to-text-mode{background-color:#1890ff;transform:scale(1.1)}.recording-time{font-size:32px;font-weight:600;color:#fff;font-variant-numeric:tabular-nums}.recording-hints{display:flex;gap:40px;margin-top:12px}.hint-item{display:flex;flex-direction:column;align-items:center;gap:8px;color:#ffffff80;transition:all .2s}.hint-item i{font-size:24px}.hint-item span{font-size:12px;font-weight:500;color:#fff9}.hint-item.active{color:#fff;transform:scale(1.1)}.hint-item.active i{animation:bounce .6s ease-in-out infinite;color:#1890ff;text-shadow:0 0 10px rgba(24,144,255,.8)}.input-container{flex:1;display:flex;flex-direction:column;min-height:0}.message-input{flex:1;width:100%;min-height:60px;padding:8px 12px;border:1px solid #d9d9d9;border-radius:4px;font-size:14px;line-height:1.6;resize:none;font-family:inherit;transition:border-color .2s}.message-input:focus{outline:none;border-color:#1890ff;box-shadow:0 0 0 2px #1890ff1a}.send-btn-wrapper{display:flex;gap:8px}.send-btn{display:flex;align-items:center;gap:6px;padding:8px 20px;background-color:#1890ff;color:#fff;border:none;border-radius:4px;font-size:14px;cursor:pointer;transition:background-color .2s}.send-btn:hover:not(:disabled){background-color:#40a9ff}.send-btn:disabled{background-color:#d9d9d9;cursor:not-allowed}.emoji-picker{position:absolute;bottom:200px;left:16px;background-color:#fff;border:1px solid #e5e5e5;border-radius:8px;box-shadow:0 4px 12px #00000026;padding:12px;z-index:1000;width:380px}.emoji-list{display:grid;grid-template-columns:repeat(12,1fr);gap:4px;max-height:none;overflow:visible}.emoji-item{font-size:20px;cursor:pointer;text-align:center;padding:0;border-radius:4px;transition:all .2s;line-height:1;-webkit-user-select:none;user-select:none;width:28px;height:28px;display:flex;align-items:center;justify-content:center}.context-menu{position:fixed;background-color:#fff;border:1px solid #e5e5e5;border-radius:6px;box-shadow:0 4px 12px #00000026;padding:4px 0;z-index:1000;min-width:120px}.context-menu-item{display:flex;align-items:center;gap:8px;padding:8px 16px;cursor:pointer;transition:background-color .2s}.context-menu-item:hover{background-color:#f5f5f5}.context-menu-item i{font-size:16px;color:#666}.context-menu-item span{font-size:14px;color:#333}.im-container--mobile{font-size:14px}.im-container--mobile .header{padding:10px 12px}.im-container--mobile .user-name{font-size:15px}.im-container--mobile .chatList{padding:12px}.im-container--mobile .chatList-avatar,.im-container--mobile .chatList-avatar--placeholder{width:36px;height:36px}.im-container--mobile .chatList-text{font-size:15px}.im-container--mobile .toolBox{padding:6px 12px}.im-container--mobile .tool-icon{font-size:22px}.im-container--mobile .input-container{padding:10px 12px}.im-container--mobile .message-input{font-size:15px}.im-container--mobile .send-btn{padding:6px 16px;font-size:15px}@media(max-width:768px){.chatList-content{max-width:75%}.emoji-picker{left:50%;transform:translate(-50%);max-width:90%}.emoji-list{grid-template-columns:repeat(10,1fr)}.emoji-item{font-size:18px;width:26px;height:26px}}.emoji-picker{position:absolute;bottom:200px;left:16px;background-color:#fff;border:1px solid #e5e5e5;border-radius:8px;box-shadow:0 4px 12px #00000026;padding:0;z-index:1000;width:420px}.emoji-tabs{display:flex;border-bottom:1px solid #e5e5e5;padding:8px 12px;gap:4px;background-color:#fafafa;border-radius:8px 8px 0 0}.emoji-tab{width:36px;height:36px;display:flex;align-items:center;justify-content:center;font-size:20px;cursor:pointer;border-radius:6px;transition:all .2s;-webkit-user-select:none;user-select:none}.emoji-tab:hover{background-color:#f0f0f0}.emoji-tab.active{background-color:#e6f7ff;border:1px solid #91d5ff}.emoji-list{display:grid;grid-template-columns:repeat(12,1fr);gap:4px;padding:12px}.emoji-item{cursor:pointer;text-align:center;padding:0;border-radius:4px;transition:all .2s;line-height:1;-webkit-user-select:none;user-select:none;width:28px;height:28px;display:flex;align-items:center;justify-content:center}.emoji-item img{width:24px;height:24px;object-fit:contain}.emoji-item:hover{background-color:#f5f5f5;transform:scale(1.15)}.emoji-img{width:20px;height:20px;vertical-align:middle;margin:0 2px}.favorite-dialog-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:2000;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.favorite-dialog{background-color:#fff;border-radius:12px;width:90%;max-width:400px;box-shadow:0 8px 24px #00000026;animation:slideUp .3s ease}@keyframes slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.favorite-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid #e5e5e5}.favorite-dialog-title{font-size:16px;font-weight:600;color:#333}.favorite-dialog-close{font-size:20px;color:#999;cursor:pointer;transition:color .2s}.favorite-dialog-close:hover{color:#333}.favorite-dialog-content{padding:20px;max-height:400px;overflow-y:auto}.favorite-default-content{display:flex;flex-direction:column;gap:16px}.favorite-message-preview{background-color:#f5f5f5;border-radius:8px;padding:12px}.favorite-message-type{display:flex;align-items:center;gap:6px;margin-bottom:8px;color:#666;font-size:13px}.favorite-message-type i{font-size:16px}.favorite-message-text{color:#333;font-size:14px;line-height:1.6;word-wrap:break-word}.favorite-message-image{max-width:100%}.favorite-message-image img{max-width:100%;max-height:200px;border-radius:4px;object-fit:contain}.favorite-note-input{width:100%;padding:10px;border:1px solid #e5e5e5;border-radius:6px;font-size:14px;line-height:1.6;resize:vertical;font-family:inherit;transition:border-color .2s}.favorite-note-input:focus{outline:none;border-color:#1890ff}.favorite-dialog-footer{display:flex;gap:12px;padding:16px 20px;border-top:1px solid #e5e5e5}.favorite-btn{flex:1;padding:10px 20px;border:none;border-radius:6px;font-size:14px;cursor:pointer;transition:all .2s}.favorite-btn-cancel{background-color:#f5f5f5;color:#666}.favorite-btn-cancel:hover{background-color:#e5e5e5}.favorite-btn-confirm{background-color:#1890ff;color:#fff}.favorite-btn-confirm:hover{background-color:#40a9ff}.favorite-btn-confirm:active{background-color:#096dd9}.favorites-list-dialog-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:3000;animation:fadeIn .2s ease}.favorites-list-dialog{background-color:#fff;border-radius:12px;width:90%;max-width:600px;max-height:80vh;display:flex;flex-direction:column;box-shadow:0 8px 24px #00000026;animation:slideUp .3s ease}.favorites-list-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid #e5e5e5}.favorites-list-title{font-size:16px;font-weight:600;color:#333}.favorites-list-close{font-size:20px;color:#999;cursor:pointer;transition:color .2s}.favorites-list-close:hover{color:#333}.favorites-list-content{flex:1;overflow-y:auto;padding:12px 0}.favorites-list-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;color:#999}.favorites-list-empty i{font-size:64px;margin-bottom:16px}.favorites-list-empty p{font-size:14px}.favorites-list-items{display:flex;flex-direction:column}.favorites-list-item{display:flex;align-items:center;padding:12px 20px;cursor:pointer;transition:background-color .2s;border-bottom:1px solid #f0f0f0}.favorites-list-item:hover{background-color:#f5f7fa}.favorites-list-item:last-child{border-bottom:none}.favorite-item-icon{font-size:24px;color:#1890ff;margin-right:12px;flex-shrink:0}.favorite-item-content{flex:1;min-width:0}.favorite-item-title{font-size:15px;font-weight:500;color:#333;margin-bottom:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.favorite-item-preview{font-size:13px;color:#999;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:4px}.favorite-item-time{font-size:12px;color:#bbb}.favorite-item-arrow{font-size:20px;color:#ccc;margin-left:12px;flex-shrink:0}.mention-list-container{position:relative;z-index:99999;pointer-events:auto!important}.mention-item{display:flex;align-items:center;padding:8px 12px;cursor:pointer;transition:background-color .2s;position:relative;z-index:99999;pointer-events:auto!important}.mention-item:hover,.mention-item-selected{background-color:#f5f5f5}.mention-avatar{width:36px;height:36px;border-radius:4px;margin-right:10px;flex-shrink:0;object-fit:cover}.mention-avatar-placeholder{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:500}.mention-info{flex:1;min-width:0;overflow:hidden}.mention-name{font-size:14px;color:#333;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:2px}.mention-account{font-size:12px;color:#999;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chatList__msg--file{display:flex;align-items:center;gap:12px;padding:12px;background-color:#f5f5f5;border-radius:6px;min-width:200px;cursor:pointer;transition:background-color .2s}.chatList__msg--file:hover{background-color:#e5e5e5}.file-icon{font-size:32px;color:#1890ff;flex-shrink:0}.file-info{flex:1;min-width:0}.file-name{font-size:14px;color:#333;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:4px}.file-size{font-size:12px;color:#999}.chatList-item--mine .chatList-content{display:flex;flex-direction:column;align-items:flex-end}.chatList-item--mine .chatList-text{text-align:left}.input-wrapper{position:relative;flex:1;transition:border-color .2s}.input-wrapper:focus-within{border-color:#0067cc;background:#fff}.message-input{width:100%;max-height:360px;padding:12px 100px 12px 12px;border:none;outline:none;background:transparent;font-size:14px;line-height:1.6;resize:vertical;font-family:inherit}.message-input::placeholder{color:#999}.input-actions{position:absolute;right:8px;bottom:30px;display:flex;gap:4px;align-items:center}.send-options-btn{width:32px;height:32px;border:none;background:transparent;color:#666;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px;transition:all .2s}.send-options-btn:hover:not(:disabled){background:#e8e8e8;color:#333}.send-options-btn:disabled{opacity:.4;cursor:not-allowed}.send-btn{height:32px;padding:0 16px;border:none;background:#0067cc;color:#fff;border-radius:4px;cursor:pointer;display:flex;align-items:center;gap:4px;font-size:14px;font-weight:500;transition:all .2s}.send-btn:hover:not(:disabled){background:#0052a3;transform:translateY(-1px);box-shadow:0 2px 8px #0067cc4d}.send-btn:active:not(:disabled){transform:translateY(0)}.send-btn:disabled{opacity:.5;cursor:not-allowed}.send-btn i{font-size:16px}.send-options-menu{position:absolute;right:12px;bottom:100%;margin-bottom:8px;background:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;min-width:160px;padding:8px 0;z-index:1000;animation:slideUp .2s ease}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.send-option-item{display:flex;align-items:center;gap:12px;padding:10px 16px;cursor:pointer;transition:background .2s;color:#333;font-size:14px}.send-option-item:hover{background:#f5f5f5}.send-option-item i{font-size:18px;color:#666;width:20px;text-align:center}.send-option-item:hover i{color:#0067cc}.send-option-item:has(.ri-fire-line):hover{background:#fff3f3}.send-option-item:has(.ri-fire-line):hover i{color:#ff4757}.send-option-item:has(.ri-alarm-warning-line):hover{background:#fff8e6}.send-option-item:has(.ri-alarm-warning-line):hover i{color:#ff9800}@media(max-width:768px){.message-input{padding:10px 90px 10px 10px;min-height:60px}.send-btn{padding:0 12px;font-size:13px}.send-options-menu{right:8px}}.scheduled-messages{margin-top:12px;background:#fff9e6;border:1px solid #ffe58f;border-radius:8px;padding:12px;max-height:200px;overflow-y:auto}.scheduled-messages-header{display:flex;align-items:center;gap:8px;margin-bottom:12px;color:#d48806;font-size:14px;font-weight:500}.scheduled-messages-header i{font-size:16px}.scheduled-message-item{display:flex;align-items:flex-start;gap:12px;padding:10px;background:#fff;border-radius:6px;margin-bottom:8px;border:1px solid #ffe58f;transition:all .2s}.scheduled-message-item:last-child{margin-bottom:0}.scheduled-message-item:hover{border-color:#ffc53d;box-shadow:0 2px 8px #faad1426}.scheduled-message-text{color:#333;font-size:14px;line-height:1.5;margin-bottom:6px;word-break:break-word}.scheduled-message-time{display:flex;align-items:center;gap:4px;color:#d48806;font-size:12px}.scheduled-message-time i{font-size:14px}.scheduled-message-actions{display:flex;gap:4px;flex-shrink:0}.scheduled-action-btn{width:28px;height:28px;border:none;background:transparent;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;transition:all .2s;color:#666}.scheduled-action-btn:hover{background:#f5f5f5}.edit-btn:hover{color:#0067cc;background:#e6f7ff}.cancel-btn:hover{color:#ff4d4f;background:#fff1f0}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.scheduled-message-item{animation:slideIn .3s ease}.template-dialog-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:2000;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.template-dialog{background:#fff;border-radius:12px;width:90%;max-width:600px;max-height:80vh;overflow:hidden;box-shadow:0 8px 32px #0003;animation:slideUp .3s ease;display:flex;flex-direction:column}.template-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background:#0067cc;color:#fff;font-weight:500;flex-shrink:0}.template-header-actions{display:flex;gap:12px}.template-header-actions i{font-size:20px;cursor:pointer;padding:4px;border-radius:4px;transition:background .2s}.template-header-actions i:hover{background:#fff3}.template-dialog-body{padding:20px;overflow-y:auto;flex:1}.template-filters{margin-bottom:20px}.template-search{width:100%;padding:10px 12px;border:2px solid #e0e0e0;border-radius:8px;font-size:14px;outline:none;transition:border-color .2s;margin-bottom:12px}.template-search:focus{border-color:#0067cc}.template-categories{display:flex;gap:8px;flex-wrap:wrap}.category-btn{padding:8px 16px;border:2px solid #e0e0e0;background:#fff;color:#666;border-radius:20px;cursor:pointer;font-size:14px;font-weight:500;transition:all .2s;white-space:nowrap}.category-btn:hover{border-color:#0067cc;color:#0067cc}.category-btn.active{border-color:#0067cc;background:#0067cc;color:#fff}.template-list{display:flex;flex-direction:column;gap:12px}.template-item{display:flex;gap:12px;padding:16px;border:2px solid #e0e0e0;border-radius:8px;transition:all .2s}.template-item:hover{border-color:#0067cc;box-shadow:0 2px 8px #0067cc1a}.template-content{flex:1;cursor:pointer}.template-name{font-weight:600;color:#333;margin-bottom:8px;font-size:15px}.template-preview{color:#666;font-size:14px;line-height:1.5;margin-bottom:8px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;white-space:pre-wrap}.template-meta{display:flex;gap:12px;font-size:12px;color:#999}.template-category{color:#0067cc}.template-actions{display:flex;flex-direction:column;gap:8px;justify-content:center}.template-actions i{font-size:18px;padding:8px;border-radius:4px;cursor:pointer;transition:all .2s;color:#666}.template-actions i:hover{background:#f5f5f5;color:#0067cc}.template-actions .ri-delete-bin-line:hover{color:#f44}.template-empty{text-align:center;padding:60px 20px;color:#999}.template-empty i{font-size:64px;color:#ddd;margin-bottom:16px}.template-empty p{font-size:16px;margin-bottom:20px}.add-template-btn{padding:10px 24px;background:#0067cc;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.add-template-btn:hover{background:#0052a3;transform:translateY(-1px);box-shadow:0 4px 12px #0067cc4d}.template-editor-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:2100;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.template-editor{background:#fff;border-radius:12px;width:90%;max-width:500px;max-height:80vh;overflow:hidden;box-shadow:0 8px 32px #0003;animation:slideUp .3s ease;display:flex;flex-direction:column}.template-editor-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background:#0067cc;color:#fff;font-weight:500;flex-shrink:0}.template-editor-header i{font-size:20px;cursor:pointer;padding:4px;border-radius:4px;transition:background .2s}.template-editor-header i:hover{background:#fff3}.template-editor-body{padding:20px;overflow-y:auto;flex:1}.form-group{margin-bottom:20px}.form-group label{display:block;font-weight:500;color:#333;margin-bottom:8px;font-size:14px}.form-input{width:100%;padding:10px 12px;border:2px solid #e0e0e0;border-radius:8px;font-size:14px;outline:none;transition:border-color .2s}.form-input:focus{border-color:#0067cc}.category-selector{display:flex;gap:8px;flex-wrap:wrap}.category-option{padding:8px 16px;border:2px solid #e0e0e0;background:#fff;color:#666;border-radius:20px;cursor:pointer;font-size:14px;font-weight:500;transition:all .2s}.category-option:hover{border-color:#0067cc;color:#0067cc}.category-option.active{border-color:#0067cc;background:#0067cc;color:#fff}.form-textarea{width:100%;padding:12px;border:2px solid #e0e0e0;border-radius:8px;font-size:14px;line-height:1.6;resize:vertical;outline:none;transition:border-color .2s;font-family:inherit;min-height:120px}.form-textarea:focus{border-color:#0067cc}.variable-hint{display:flex;align-items:center;gap:8px;padding:12px;background:#f0f7ff;border-radius:8px;color:#0067cc;font-size:13px}.variable-hint i{font-size:16px}.template-editor-footer{display:flex;gap:12px;padding:16px 20px;background:#f8f9fa;border-top:1px solid #e9ecef;flex-shrink:0}.btn-cancel,.btn-save{flex:1;padding:12px 20px;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.btn-cancel{background:#f5f5f5;color:#666}.btn-cancel:hover{background:#e8e8e8;color:#333}.btn-save{background:#0067cc;color:#fff}.btn-save:hover{background:#0052a3;transform:translateY(-1px);box-shadow:0 4px 12px #0067cc4d}@media(max-width:768px){.template-dialog,.template-editor{width:95%;margin:0 10px}.template-dialog-body,.template-editor-body{padding:16px}.template-categories{overflow-x:auto;flex-wrap:nowrap;padding-bottom:8px}.template-item{flex-direction:column}.template-actions{flex-direction:row;justify-content:flex-end}}@media(prefers-color-scheme:dark){.template-dialog,.template-editor{background:#1a1a1a;color:#fff}.template-dialog-body,.template-editor-body{background:#1a1a1a}.template-search,.form-input,.form-textarea{background:#2a2a2a;border-color:#404040;color:#fff}.template-item{border-color:#404040}.template-name{color:#fff}.template-preview{color:#ccc}.category-btn,.category-option{background:#2a2a2a;border-color:#404040;color:#ccc}.template-editor-footer{background:#2a2a2a;border-top-color:#404040}.btn-cancel{background:#404040;color:#ccc}.variable-hint{background:#1a3a5a}}.input-wrapper{display:flex;gap:8px}.message-input{flex:1;padding:12px;font-size:14px;line-height:1.5;resize:vertical;outline:none;transition:border-color .2s;font-family:inherit}.message-input:focus{border-color:#0067cc}.input-actions{display:flex;gap:4px;align-items:flex-end}.send-options-btn,.send-btn{padding:10px 12px;border:none;background:#0067cc;color:#fff;border-radius:6px;cursor:pointer;font-size:16px;transition:all .2s;display:flex;align-items:center;justify-content:center;min-width:40px;height:40px}.send-options-btn:hover:not(:disabled),.send-btn:hover:not(:disabled){background:#0052a3;transform:translateY(-1px);box-shadow:0 4px 12px #0067cc4d}.send-options-btn:disabled,.send-btn:disabled{opacity:.5;cursor:not-allowed;transform:none}.send-options-btn{position:relative}.send-options-btn:after{content:"";position:absolute;right:0;top:50%;transform:translateY(-50%);width:1px;height:20px;background:#ffffff4d}.send-options-menu{position:absolute;bottom:100%;right:0;background:#fff;border:1px solid #e0e0e0;border-radius:8px;box-shadow:0 4px 12px #00000026;z-index:100;min-width:160px;margin-bottom:8px;animation:slideUp .2s ease}.send-option-item{display:flex;align-items:center;gap:12px;padding:12px 16px;cursor:pointer;transition:all .2s;color:#333;font-size:14px}.send-option-item:hover{background:#f5f5f5;color:#0067cc}.send-option-item:first-child{border-radius:8px 8px 0 0}.send-option-item:last-child{border-radius:0 0 8px 8px}.send-option-item i{font-size:16px;width:20px;text-align:center}.scheduled-messages{margin-top:12px;padding:12px;background:#f8f9fa;border-radius:8px;border:1px solid #e9ecef}.scheduled-messages-header{display:flex;align-items:center;gap:8px;margin-bottom:12px;font-weight:500;color:#333;font-size:14px}.scheduled-messages-header i{font-size:16px;color:#0067cc}.scheduled-message-item{display:flex;align-items:center;justify-content:space-between;padding:12px;background:#fff;border-radius:6px;margin-bottom:8px;border:1px solid #e9ecef;transition:all .2s}.scheduled-message-item:hover{box-shadow:0 2px 8px #0000001a}.scheduled-message-content{flex:1;min-width:0}.scheduled-message-text{color:#333;font-size:14px;margin-bottom:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.scheduled-message-time{display:flex;align-items:center;gap:4px;color:#999;font-size:12px}.scheduled-message-time i{font-size:12px}.scheduled-message-actions{display:flex;gap:8px;margin-left:12px}.scheduled-action-btn{width:28px;height:28px;border:none;background:#f5f5f5;border-radius:4px;cursor:pointer;font-size:14px;transition:all .2s;display:flex;align-items:center;justify-content:center;color:#666}.scheduled-action-btn:hover{background:#e8e8e8;color:#333}.scheduled-action-btn.edit-btn:hover{background:#e6f7ff;color:#0067cc}.scheduled-action-btn.cancel-btn:hover{background:#fff1f0;color:#ff4d4f}@media(max-width:768px){.input-wrapper{flex-direction:column}.message-input{width:100%}.input-actions{width:100%;justify-content:flex-end}.send-options-btn,.send-btn{flex:1}.send-options-menu{position:fixed;bottom:auto;top:50%;right:50%;transform:translate(50%);min-width:200px;margin-bottom:0}.scheduled-messages{margin-top:8px;padding:8px}.scheduled-message-item{flex-direction:column;align-items:flex-start}.scheduled-message-actions{margin-left:0;margin-top:8px;width:100%}.scheduled-action-btn{flex:1}}.voice-to-text-dialog-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:2000;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.voice-to-text-dialog{background:#fff;border-radius:12px;width:90%;max-width:500px;max-height:80vh;overflow:hidden;box-shadow:0 8px 32px #0003;animation:slideUp .3s ease;display:flex;flex-direction:column}.voice-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background:#0067cc;color:#fff;font-weight:500;flex-shrink:0}.voice-dialog-header i{font-size:20px;cursor:pointer;padding:4px;border-radius:4px;transition:background .2s}.voice-dialog-header i:hover{background:#fff3}.voice-dialog-body{padding:20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:20px}.voice-recording-status{display:flex;flex-direction:column;align-items:center;gap:16px;padding:20px}.voice-icon-large{width:80px;height:80px;border-radius:50%;background-color:#ff4d4f;display:flex;align-items:center;justify-content:center;animation:pulse 1.5s infinite}.voice-icon-large i{font-size:40px;color:#fff}.voice-waveform{display:flex;align-items:center;justify-content:center;gap:4px;height:40px}.voice-waveform span{width:4px;background:#0067cc;border-radius:2px;animation:waveform .6s ease-in-out infinite}.voice-waveform span:nth-child(1){height:20px;animation-delay:0s}.voice-waveform span:nth-child(2){height:30px;animation-delay:.1s}.voice-waveform span:nth-child(3){height:40px;animation-delay:.2s}.voice-waveform span:nth-child(4){height:30px;animation-delay:.3s}.voice-waveform span:nth-child(5){height:20px;animation-delay:.4s}@keyframes waveform{0%,to{transform:scaleY(.5)}50%{transform:scaleY(1)}}.voice-time{font-size:32px;font-weight:600;color:#333;font-variant-numeric:tabular-nums}.voice-hint{font-size:14px;color:#666}.voice-result{display:flex;flex-direction:column;gap:12px}.result-label{font-size:14px;font-weight:500;color:#333}.result-textarea{width:100%;padding:12px;border:2px solid #e0e0e0;border-radius:8px;font-size:14px;line-height:1.6;resize:vertical;outline:none;transition:border-color .2s;font-family:inherit}.result-textarea:focus{border-color:#0067cc}.voice-mode-selector{display:flex;gap:8px;justify-content:center}.mode-btn{display:flex;align-items:center;gap:6px;padding:10px 16px;border:2px solid #e0e0e0;background:#fff;color:#666;border-radius:20px;cursor:pointer;font-size:14px;font-weight:500;transition:all .2s;white-space:nowrap}.mode-btn:hover{border-color:#0067cc;color:#0067cc}.mode-btn.active{border-color:#0067cc;background:#0067cc;color:#fff}.mode-btn i{font-size:16px}.voice-dialog-footer{display:flex;gap:12px;padding:16px 20px;background:#f8f9fa;border-top:1px solid #e9ecef;flex-shrink:0}.voice-action-btn{flex:1;padding:12px 20px;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.voice-action-btn.cancel{background:#f5f5f5;color:#666}.voice-action-btn.cancel:hover{background:#e8e8e8;color:#333}.voice-action-btn.primary{background:#0067cc;color:#fff}.voice-action-btn.primary:hover:not(:disabled){background:#0052a3;transform:translateY(-1px);box-shadow:0 4px 12px #0067cc4d}.voice-action-btn:disabled{opacity:.5;cursor:not-allowed}@media(max-width:768px){.voice-to-text-dialog{width:95%;margin:0 10px}.voice-dialog-body{padding:16px}.voice-icon-large{width:60px;height:60px}.voice-icon-large i{font-size:30px}.voice-time{font-size:24px}.voice-mode-selector{flex-wrap:wrap}.mode-btn{flex:1;min-width:100px}}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "cd-aichat",
3
+ "version": "1.0.0",
4
+ "description": "Vue3组件,用于与Dify API进行交互,实现AI聊天功能",
5
+ "main": "dist/cd-aichat.umd.js",
6
+ "module": "dist/cd-aichat.es.js",
7
+ "files": [
8
+ "dist",
9
+ "src"
10
+ ],
11
+ "keywords": [
12
+ "vue",
13
+ "vue3",
14
+ "component",
15
+ "ai",
16
+ "chat",
17
+ "dify"
18
+ ],
19
+ "author": "",
20
+ "license": "MIT",
21
+ "peerDependencies": {
22
+ "vue": "^3.3.8"
23
+ },
24
+ "dependencies": {
25
+ "@diycom/screenshots": "file:../screenshots",
26
+ "@diycom/cd-screencut": "file:../cd-srceencut",
27
+ "@tiptap/extension-image": "^3.14.0",
28
+ "@tiptap/extension-link": "^3.14.0",
29
+ "@tiptap/extension-mention": "^3.14.0",
30
+ "@tiptap/extension-placeholder": "^3.14.0",
31
+ "@tiptap/starter-kit": "^3.14.0",
32
+ "@tiptap/suggestion": "^3.14.0",
33
+ "@tiptap/vue-3": "^3.14.0",
34
+ "axios": "^1.4.0",
35
+ "html2canvas": "^1.4.1",
36
+ "paddleocr": "^1.0.6",
37
+ "react": "^19.2.3",
38
+ "react-dom": "^19.2.3",
39
+ "remixicon": "^4.8.0",
40
+ "tdesign-vue-next": "^1.17.7",
41
+ "tesseract.js": "^7.0.0",
42
+ "tippy.js": "^6.3.7"
43
+ },
44
+ "devDependencies": {
45
+ "@vitejs/plugin-vue": "^5.2.4",
46
+ "@vitest/ui": "^2.1.9",
47
+ "@vue/test-utils": "^2.4.6",
48
+ "fast-check": "^4.5.3",
49
+ "happy-dom": "^20.0.11",
50
+ "vite": "^6.0.5",
51
+ "vitest": "^2.1.9"
52
+ },
53
+ "scripts": {
54
+ "dev": "vite",
55
+ "build": "vite build",
56
+ "preview": "vite preview",
57
+ "test": "vitest",
58
+ "test:ui": "vitest --ui",
59
+ "test:run": "vitest run"
60
+ }
61
+ }
package/src/ailogo.png ADDED
Binary file
@@ -0,0 +1,538 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import AiChat from './AiChat.vue';
4
+
5
+ // Mock DifyApiService
6
+ vi.mock('../services/dify-api', () => {
7
+ return {
8
+ default: vi.fn().mockImplementation((config) => ({
9
+ baseURL: config.url || config,
10
+ agentId: config.agentId || arguments[1],
11
+ platform: config.platform || '',
12
+ scene: config.scene || '',
13
+ sendMessage: vi.fn().mockResolvedValue({
14
+ answer: 'AI response',
15
+ conversation_id: 'conv-001',
16
+ message_id: 'msg-001'
17
+ }),
18
+ updateConfig: vi.fn(),
19
+ resetConversation: vi.fn(),
20
+ isConversationExpired: vi.fn().mockReturnValue(false)
21
+ }))
22
+ };
23
+ });
24
+
25
+ describe('AiChat Props', () => {
26
+ describe('向后兼容性', () => {
27
+ it('应该支持旧的 aiConfig 格式(只有 url 和 agentId)', () => {
28
+ const wrapper = mount(AiChat, {
29
+ props: {
30
+ currentUserId: 'user-001',
31
+ chatType: 'ai',
32
+ aiConfig: {
33
+ url: 'https://api.dify.ai/v1',
34
+ agentId: 'agent-001'
35
+ }
36
+ }
37
+ });
38
+
39
+ expect(wrapper.exists()).toBe(true);
40
+ });
41
+
42
+ it('应该在缺少新字段时使用默认值', () => {
43
+ const wrapper = mount(AiChat, {
44
+ props: {
45
+ currentUserId: 'user-001',
46
+ chatType: 'ai',
47
+ aiConfig: {
48
+ url: 'https://api.dify.ai/v1',
49
+ agentId: 'agent-001'
50
+ }
51
+ }
52
+ });
53
+
54
+ const aiConfig = wrapper.props('aiConfig');
55
+ expect(aiConfig.platform).toBeUndefined();
56
+ expect(aiConfig.scene).toBeUndefined();
57
+ expect(aiConfig.knowledgeBase).toBeUndefined();
58
+ });
59
+ });
60
+
61
+ describe('新的 aiConfig 字段', () => {
62
+ it('应该接受 platform 字段', () => {
63
+ const wrapper = mount(AiChat, {
64
+ props: {
65
+ currentUserId: 'user-001',
66
+ chatType: 'ai',
67
+ aiConfig: {
68
+ url: 'https://api.dify.ai/v1',
69
+ agentId: 'agent-001',
70
+ platform: 'report'
71
+ }
72
+ }
73
+ });
74
+
75
+ expect(wrapper.props('aiConfig').platform).toBe('report');
76
+ });
77
+
78
+ it('应该接受 scene 字段', () => {
79
+ const wrapper = mount(AiChat, {
80
+ props: {
81
+ currentUserId: 'user-001',
82
+ chatType: 'ai',
83
+ aiConfig: {
84
+ url: 'https://api.dify.ai/v1',
85
+ agentId: 'agent-001',
86
+ scene: 'data-analysis'
87
+ }
88
+ }
89
+ });
90
+
91
+ expect(wrapper.props('aiConfig').scene).toBe('data-analysis');
92
+ });
93
+
94
+ it('应该接受 knowledgeBase 字段', () => {
95
+ const kb = {
96
+ type: 'json',
97
+ data: { test: 'data' }
98
+ };
99
+
100
+ const wrapper = mount(AiChat, {
101
+ props: {
102
+ currentUserId: 'user-001',
103
+ chatType: 'ai',
104
+ aiConfig: {
105
+ url: 'https://api.dify.ai/v1',
106
+ agentId: 'agent-001',
107
+ knowledgeBase: kb
108
+ }
109
+ }
110
+ });
111
+
112
+ expect(wrapper.props('aiConfig').knowledgeBase).toEqual(kb);
113
+ });
114
+
115
+ it('应该接受 inputVariables 字段', () => {
116
+ const vars = {
117
+ userRole: 'analyst',
118
+ currentPage: 'dashboard'
119
+ };
120
+
121
+ const wrapper = mount(AiChat, {
122
+ props: {
123
+ currentUserId: 'user-001',
124
+ chatType: 'ai',
125
+ aiConfig: {
126
+ url: 'https://api.dify.ai/v1',
127
+ agentId: 'agent-001',
128
+ inputVariables: vars
129
+ }
130
+ }
131
+ });
132
+
133
+ expect(wrapper.props('aiConfig').inputVariables).toEqual(vars);
134
+ });
135
+
136
+ it('应该接受 conversation 配置', () => {
137
+ const conversation = {
138
+ id: 'conv-001',
139
+ autoCreate: false,
140
+ timeout: 3600000
141
+ };
142
+
143
+ const wrapper = mount(AiChat, {
144
+ props: {
145
+ currentUserId: 'user-001',
146
+ chatType: 'ai',
147
+ aiConfig: {
148
+ url: 'https://api.dify.ai/v1',
149
+ agentId: 'agent-001',
150
+ conversation
151
+ }
152
+ }
153
+ });
154
+
155
+ expect(wrapper.props('aiConfig').conversation).toEqual(conversation);
156
+ });
157
+
158
+ it('应该接受 response 配置', () => {
159
+ const response = {
160
+ mode: 'streaming',
161
+ timeout: 60000,
162
+ maxRetries: 5
163
+ };
164
+
165
+ const wrapper = mount(AiChat, {
166
+ props: {
167
+ currentUserId: 'user-001',
168
+ chatType: 'ai',
169
+ aiConfig: {
170
+ url: 'https://api.dify.ai/v1',
171
+ agentId: 'agent-001',
172
+ response
173
+ }
174
+ }
175
+ });
176
+
177
+ expect(wrapper.props('aiConfig').response).toEqual(response);
178
+ });
179
+ });
180
+
181
+ describe('enableAiConfigHotReload prop', () => {
182
+ it('应该有默认值 true', () => {
183
+ const wrapper = mount(AiChat, {
184
+ props: {
185
+ currentUserId: 'user-001',
186
+ chatType: 'ai',
187
+ aiConfig: {
188
+ url: 'https://api.dify.ai/v1',
189
+ agentId: 'agent-001'
190
+ }
191
+ }
192
+ });
193
+
194
+ expect(wrapper.props('enableAiConfigHotReload')).toBe(true);
195
+ });
196
+
197
+ it('应该接受 false 值', () => {
198
+ const wrapper = mount(AiChat, {
199
+ props: {
200
+ currentUserId: 'user-001',
201
+ chatType: 'ai',
202
+ aiConfig: {
203
+ url: 'https://api.dify.ai/v1',
204
+ agentId: 'agent-001'
205
+ },
206
+ enableAiConfigHotReload: false
207
+ }
208
+ });
209
+
210
+ expect(wrapper.props('enableAiConfigHotReload')).toBe(false);
211
+ });
212
+ });
213
+
214
+ describe('完整配置', () => {
215
+ it('应该接受所有新字段的完整配置', () => {
216
+ const fullConfig = {
217
+ url: 'https://api.dify.ai/v1',
218
+ agentId: 'agent-001',
219
+ apiKey: 'key-001',
220
+ platform: 'report',
221
+ scene: 'data-analysis',
222
+ knowledgeBase: {
223
+ type: 'json',
224
+ data: { reports: ['sales', 'finance'] }
225
+ },
226
+ inputVariables: {
227
+ userRole: 'analyst',
228
+ currentPage: 'dashboard'
229
+ },
230
+ conversation: {
231
+ id: 'conv-001',
232
+ autoCreate: true,
233
+ timeout: 1800000
234
+ },
235
+ response: {
236
+ mode: 'blocking',
237
+ timeout: 30000,
238
+ maxRetries: 3
239
+ }
240
+ };
241
+
242
+ const wrapper = mount(AiChat, {
243
+ props: {
244
+ currentUserId: 'user-001',
245
+ chatType: 'ai',
246
+ aiConfig: fullConfig,
247
+ enableAiConfigHotReload: true
248
+ }
249
+ });
250
+
251
+ expect(wrapper.props('aiConfig')).toEqual(fullConfig);
252
+ expect(wrapper.props('enableAiConfigHotReload')).toBe(true);
253
+ });
254
+ });
255
+ });
256
+
257
+
258
+ describe('AiChat 配置热更新', () => {
259
+ it('应该在 aiConfig 更新时触发 aiConfigUpdate 事件', async () => {
260
+ const wrapper = mount(AiChat, {
261
+ props: {
262
+ currentUserId: 'user-001',
263
+ chatType: 'ai',
264
+ aiConfig: {
265
+ url: 'https://api.dify.ai/v1',
266
+ agentId: 'agent-001',
267
+ platform: 'report'
268
+ },
269
+ enableAiConfigHotReload: true
270
+ }
271
+ });
272
+
273
+ // 更新配置
274
+ await wrapper.setProps({
275
+ aiConfig: {
276
+ url: 'https://api.dify.ai/v1',
277
+ agentId: 'agent-001',
278
+ platform: 'lowcode'
279
+ }
280
+ });
281
+
282
+ // 等待下一个 tick
283
+ await wrapper.vm.$nextTick();
284
+
285
+ // 检查事件是否被触发
286
+ expect(wrapper.emitted('aiConfigUpdate')).toBeTruthy();
287
+ expect(wrapper.emitted('aiConfigUpdate')[0][0].success).toBe(true);
288
+ });
289
+
290
+ it('应该在 enableAiConfigHotReload 为 false 时不更新配置', async () => {
291
+ const wrapper = mount(AiChat, {
292
+ props: {
293
+ currentUserId: 'user-001',
294
+ chatType: 'ai',
295
+ aiConfig: {
296
+ url: 'https://api.dify.ai/v1',
297
+ agentId: 'agent-001',
298
+ platform: 'report'
299
+ },
300
+ enableAiConfigHotReload: false
301
+ }
302
+ });
303
+
304
+ // 更新配置
305
+ await wrapper.setProps({
306
+ aiConfig: {
307
+ url: 'https://api.dify.ai/v1',
308
+ agentId: 'agent-001',
309
+ platform: 'lowcode'
310
+ }
311
+ });
312
+
313
+ await wrapper.vm.$nextTick();
314
+
315
+ // 不应该触发事件
316
+ expect(wrapper.emitted('aiConfigUpdate')).toBeFalsy();
317
+ });
318
+
319
+ it('应该在非 AI 模式下不更新配置', async () => {
320
+ const wrapper = mount(AiChat, {
321
+ props: {
322
+ currentUserId: 'user-001',
323
+ chatType: 'person',
324
+ aiConfig: {
325
+ url: 'https://api.dify.ai/v1',
326
+ agentId: 'agent-001'
327
+ }
328
+ }
329
+ });
330
+
331
+ // 更新配置
332
+ await wrapper.setProps({
333
+ aiConfig: {
334
+ url: 'https://api.dify.ai/v1',
335
+ agentId: 'agent-002'
336
+ }
337
+ });
338
+
339
+ await wrapper.vm.$nextTick();
340
+
341
+ // 不应该触发事件
342
+ expect(wrapper.emitted('aiConfigUpdate')).toBeFalsy();
343
+ });
344
+ });
345
+
346
+ describe('AiChat 会话管理', () => {
347
+ it('应该在切换聊天对象时重置会话', async () => {
348
+ const wrapper = mount(AiChat, {
349
+ props: {
350
+ currentUserId: 'user-001',
351
+ chatType: 'ai',
352
+ chatUser: {
353
+ id: 'ai-001',
354
+ name: 'AI 助手 1'
355
+ },
356
+ aiConfig: {
357
+ url: 'https://api.dify.ai/v1',
358
+ agentId: 'agent-001'
359
+ }
360
+ }
361
+ });
362
+
363
+ // 切换聊天对象
364
+ await wrapper.setProps({
365
+ chatUser: {
366
+ id: 'ai-002',
367
+ name: 'AI 助手 2'
368
+ }
369
+ });
370
+
371
+ await wrapper.vm.$nextTick();
372
+
373
+ // 应该触发会话更新事件
374
+ expect(wrapper.emitted('conversationUpdate')).toBeTruthy();
375
+ expect(wrapper.emitted('conversationUpdate')[0][0].action).toBe('reset');
376
+ });
377
+ });
378
+
379
+
380
+ describe('AiChat 消息发送', () => {
381
+ it('应该在发送消息时触发 send 事件', async () => {
382
+ const wrapper = mount(AiChat, {
383
+ props: {
384
+ currentUserId: 'user-001',
385
+ chatType: 'person'
386
+ }
387
+ });
388
+
389
+ // 设置消息内容
390
+ const textarea = wrapper.find('textarea');
391
+ await textarea.setValue('Hello');
392
+
393
+ // 点击发送按钮
394
+ const sendBtn = wrapper.find('.send-btn');
395
+ await sendBtn.trigger('click');
396
+
397
+ // 检查事件
398
+ expect(wrapper.emitted('send')).toBeTruthy();
399
+ expect(wrapper.emitted('send')[0][0].content).toBe('Hello');
400
+ });
401
+
402
+ it('应该在 AI 模式下触发 aiResponseStart 事件', async () => {
403
+ const wrapper = mount(AiChat, {
404
+ props: {
405
+ currentUserId: 'user-001',
406
+ chatType: 'ai',
407
+ aiConfig: {
408
+ url: 'https://api.dify.ai/v1',
409
+ agentId: 'agent-001'
410
+ }
411
+ }
412
+ });
413
+
414
+ // 设置消息内容
415
+ const textarea = wrapper.find('textarea');
416
+ await textarea.setValue('Hello AI');
417
+
418
+ // 点击发送按钮
419
+ const sendBtn = wrapper.find('.send-btn');
420
+ await sendBtn.trigger('click');
421
+
422
+ // 等待异步操作
423
+ await wrapper.vm.$nextTick();
424
+ await new Promise(resolve => setTimeout(resolve, 100));
425
+
426
+ // 检查事件
427
+ expect(wrapper.emitted('aiResponseStart')).toBeTruthy();
428
+ });
429
+
430
+ it('应该在 AI 响应成功时触发 aiResponseComplete 事件', async () => {
431
+ const wrapper = mount(AiChat, {
432
+ props: {
433
+ currentUserId: 'user-001',
434
+ chatType: 'ai',
435
+ aiConfig: {
436
+ url: 'https://api.dify.ai/v1',
437
+ agentId: 'agent-001'
438
+ }
439
+ }
440
+ });
441
+
442
+ // 设置消息内容
443
+ const textarea = wrapper.find('textarea');
444
+ await textarea.setValue('Hello AI');
445
+
446
+ // 点击发送按钮
447
+ const sendBtn = wrapper.find('.send-btn');
448
+ await sendBtn.trigger('click');
449
+
450
+ // 等待异步操作
451
+ await wrapper.vm.$nextTick();
452
+ await new Promise(resolve => setTimeout(resolve, 100));
453
+
454
+ // 检查事件
455
+ expect(wrapper.emitted('aiResponseComplete')).toBeTruthy();
456
+ const event = wrapper.emitted('aiResponseComplete')[0][0];
457
+ expect(event.response).toBe('AI response');
458
+ expect(event.conversationId).toBe('conv-001');
459
+ });
460
+
461
+ it('应该在 AI 响应失败时触发 aiResponseError 事件', async () => {
462
+ // 创建一个会失败的 mock
463
+ const failingMock = vi.fn().mockImplementation((config) => ({
464
+ baseURL: config.url || config,
465
+ agentId: config.agentId || arguments[1],
466
+ sendMessage: vi.fn().mockRejectedValue(new Error('API Error')),
467
+ isConversationExpired: vi.fn().mockReturnValue(false),
468
+ resetConversation: vi.fn()
469
+ }));
470
+
471
+ // 临时替换 mock
472
+ const DifyApiService = await import('../services/dify-api');
473
+ const originalMock = DifyApiService.default;
474
+ DifyApiService.default = failingMock;
475
+
476
+ const wrapper = mount(AiChat, {
477
+ props: {
478
+ currentUserId: 'user-001',
479
+ chatType: 'ai',
480
+ aiConfig: {
481
+ url: 'https://api.dify.ai/v1',
482
+ agentId: 'agent-001'
483
+ }
484
+ }
485
+ });
486
+
487
+ // 设置消息内容
488
+ const textarea = wrapper.find('textarea');
489
+ await textarea.setValue('Hello AI');
490
+
491
+ // 点击发送按钮
492
+ const sendBtn = wrapper.find('.send-btn');
493
+ await sendBtn.trigger('click');
494
+
495
+ // 等待异步操作
496
+ await wrapper.vm.$nextTick();
497
+ await new Promise(resolve => setTimeout(resolve, 100));
498
+
499
+ // 检查事件
500
+ expect(wrapper.emitted('aiResponseError')).toBeTruthy();
501
+
502
+ // 恢复原始 mock
503
+ DifyApiService.default = originalMock;
504
+ });
505
+
506
+ it('应该在消息中包含 AI 元数据', async () => {
507
+ const wrapper = mount(AiChat, {
508
+ props: {
509
+ currentUserId: 'user-001',
510
+ chatType: 'ai',
511
+ aiConfig: {
512
+ url: 'https://api.dify.ai/v1',
513
+ agentId: 'agent-001',
514
+ platform: 'report',
515
+ scene: 'data-analysis',
516
+ inputVariables: {
517
+ userRole: 'analyst'
518
+ }
519
+ }
520
+ }
521
+ });
522
+
523
+ // 设置消息内容
524
+ const textarea = wrapper.find('textarea');
525
+ await textarea.setValue('Hello AI');
526
+
527
+ // 点击发送按钮
528
+ const sendBtn = wrapper.find('.send-btn');
529
+ await sendBtn.trigger('click');
530
+
531
+ // 等待异步操作
532
+ await wrapper.vm.$nextTick();
533
+ await new Promise(resolve => setTimeout(resolve, 100));
534
+
535
+ // 检查 aiResponseComplete 事件中的元数据
536
+ expect(wrapper.emitted('aiResponseComplete')).toBeTruthy();
537
+ });
538
+ });