vue2-client 1.22.2 → 1.22.3

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 (170) hide show
  1. package/.claude/settings.local.json +30 -30
  2. package/.env.his +19 -19
  3. package/.eslintrc.js +74 -74
  4. package/.history/.eslintrc_20260521171150.js +74 -0
  5. package/.history/.eslintrc_20260521171213.js +74 -0
  6. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154443.vue +726 -0
  7. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154700.vue +478 -0
  8. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175435.vue +706 -0
  9. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175450.vue +694 -0
  10. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260611152602.vue +755 -0
  11. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513145941.vue +524 -0
  12. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513153133.vue +731 -0
  13. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513160316.vue +525 -0
  14. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260601144150.vue +1046 -0
  15. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310142713.vue +512 -0
  16. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310145118.vue +511 -0
  17. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260311094834.vue +696 -0
  18. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260320143028.vue +693 -0
  19. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260409101450.vue +677 -0
  20. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164645.vue +758 -0
  21. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164714.vue +693 -0
  22. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508171651.vue +716 -0
  23. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509133717.vue +695 -0
  24. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509171115.vue +664 -0
  25. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140637.vue +1455 -0
  26. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140935.vue +1441 -0
  27. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513150818.vue +1441 -0
  28. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153119.vue +1442 -0
  29. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153126.vue +1486 -0
  30. package/.history/src/base-client/components/common/XForm/XFormItem_20260513140854.vue +1607 -0
  31. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140403.vue +643 -0
  32. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140829.vue +628 -0
  33. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519142824.vue +104 -0
  34. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519143155.vue +102 -0
  35. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171231.vue +1241 -0
  36. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171441.vue +1223 -0
  37. package/.history/src/base-client/components/his/HAi/HAi_20260612174826.vue +472 -0
  38. package/.history/src/base-client/components/his/HAi/HAi_20260612175839.vue +538 -0
  39. package/.history/src/base-client/components/his/HAi/HAi_20260615103331.vue +650 -0
  40. package/.history/src/base-client/components/his/XHDescriptions/XHDescriptions_20260424134504.vue +1469 -0
  41. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171133.vue +788 -0
  42. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171151.vue +780 -0
  43. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511170841.vue +585 -0
  44. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511171138.vue +787 -0
  45. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260512141830.vue +739 -0
  46. package/.history/src/components/STable/index_20260409155138.js +806 -0
  47. package/.history/src/components/STable/index_20260409155218.js +814 -0
  48. package/.history/src/expression/core/Expression_20260305164427.js +1371 -0
  49. package/.history/src/expression/core/Expression_20260305170258.js +1358 -0
  50. package/.history/src/expression/core/Program_20260305111830.js +944 -0
  51. package/.history/src/expression/core/Program_20260305112041.js +931 -0
  52. package/.history/src/logic/LogicRunner_20260304154306.js +170 -0
  53. package/.history/src/logic/LogicRunner_20260304155553.js +112 -0
  54. package/.history/src/logic/LogicRunner_20260305105834.js +112 -0
  55. package/.history/src/logic/LogicRunner_20260305112718.js +129 -0
  56. package/.history/src/logic/LogicRunner_20260305182436.js +133 -0
  57. package/.history/src/logic/LogicRunner_20260306151301.js +213 -0
  58. package/.history/src/logic/LogicRunner_20260306152419.js +213 -0
  59. package/.history/src/logic/plugins/common/DateTools_20260305154159.js +61 -0
  60. package/.history/src/logic/plugins/common/DateTools_20260305154217.js +44 -0
  61. package/.history/src/logic/plugins/common/DateTools_20260305161014.js +44 -0
  62. package/.history/src/logic/plugins/common/HttpTools_20260305164352.js +80 -0
  63. package/.history/src/logic/plugins/common/HttpTools_20260305170258.js +75 -0
  64. package/.history/src/logic/plugins/common/HttpTools_20260305171634.js +75 -0
  65. package/.history/src/logic/plugins/common/HttpTools_20260306152419.js +72 -0
  66. package/.history/src/services/api/restTools_20260427142149.js +245 -0
  67. package/.history/src/services/api/restTools_20260427142853.js +230 -0
  68. package/.history/src/services/api/restTools_20260519135558.js +230 -0
  69. package/.history/src/services/api/restTools_20260519140825.js +230 -0
  70. package/.history/src/services/api/restTools_20260519151223.js +230 -0
  71. package/.history/src/utils/indexedDB_20260306150918.js +593 -0
  72. package/.history/src/utils/indexedDB_20260306151301.js +586 -0
  73. package/.idea/af-vue2-client.iml +9 -0
  74. package/.idea/codeStyles/Project.xml +62 -0
  75. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  76. package/.idea/misc.xml +6 -0
  77. package/.idea/modules.xml +1 -1
  78. package/Components.md +60 -60
  79. package/index.js +31 -31
  80. package/jest-transform-stub.js +8 -8
  81. package/jest.setup.js +7 -7
  82. package/package.json +1 -1
  83. package/preview-input-box.html +180 -0
  84. package/src/assets/img/querySlotDemo.svg +15 -15
  85. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  86. package/src/base-client/components/common/CitySelect/index.js +3 -3
  87. package/src/base-client/components/common/CitySelect/index.md +109 -109
  88. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  89. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  90. package/src/base-client/components/common/HIS/HButtons/HButtons.vue +55 -1
  91. package/src/base-client/components/common/HIS/HForm/HForm.vue +1186 -1186
  92. package/src/base-client/components/common/HIS/HTab/HTab.vue +88 -1
  93. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  94. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  95. package/src/base-client/components/common/Tree/index.js +2 -2
  96. package/src/base-client/components/common/Upload/index.js +3 -3
  97. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  98. package/src/base-client/components/common/XAddReport/XAddReport.vue +16 -1
  99. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  100. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  101. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  102. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  103. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  104. package/src/base-client/components/common/XDescriptions/index.md +382 -382
  105. package/src/base-client/components/common/XForm/index.md +178 -178
  106. package/src/base-client/components/common/XInput/XInput.vue +32 -1
  107. package/src/base-client/components/common/XInspectionDetailDrawer/index.vue +1 -1
  108. package/src/base-client/components/common/XMarkdownViewer/demo.vue +102 -102
  109. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  110. package/src/base-client/components/common/XStepView/index.js +3 -3
  111. package/src/base-client/components/common/XStepView/index.md +31 -31
  112. package/src/base-client/components/common/XTable/index.md +255 -255
  113. package/src/base-client/components/his/HAi/HAi.vue +1177 -436
  114. package/src/base-client/components/his/XList/XList.vue +337 -58
  115. package/src/base-client/components/his/XSidebar/XSidebar.vue +36 -12
  116. package/src/base-client/components/his/XTransfer/index.md +327 -327
  117. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  118. package/src/base-client/plugins/Config.js +19 -19
  119. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  120. package/src/components/Charts/Bar.vue +62 -62
  121. package/src/components/Charts/ChartCard.vue +134 -134
  122. package/src/components/Charts/Liquid.vue +67 -67
  123. package/src/components/Charts/MiniArea.vue +39 -39
  124. package/src/components/Charts/MiniBar.vue +39 -39
  125. package/src/components/Charts/MiniProgress.vue +75 -75
  126. package/src/components/Charts/MiniSmoothArea.vue +40 -40
  127. package/src/components/Charts/Radar.vue +68 -68
  128. package/src/components/Charts/RankList.vue +77 -77
  129. package/src/components/Charts/TagCloud.vue +113 -113
  130. package/src/components/Charts/TransferBar.vue +64 -64
  131. package/src/components/Charts/Trend.vue +82 -82
  132. package/src/components/Charts/chart.less +12 -12
  133. package/src/components/Charts/smooth.area.less +13 -13
  134. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  135. package/src/components/NumberInfo/index.js +3 -3
  136. package/src/components/NumberInfo/index.less +54 -54
  137. package/src/components/NumberInfo/index.md +43 -43
  138. package/src/components/STable/index.js +953 -953
  139. package/src/components/card/ChartCard.vue +79 -79
  140. package/src/components/chart/Bar.vue +60 -60
  141. package/src/components/chart/MiniArea.vue +67 -67
  142. package/src/components/chart/MiniBar.vue +59 -59
  143. package/src/components/chart/MiniProgress.vue +57 -57
  144. package/src/components/chart/Radar.vue +80 -80
  145. package/src/components/chart/RankingList.vue +60 -60
  146. package/src/components/chart/Trend.vue +79 -79
  147. package/src/components/chart/index.less +9 -9
  148. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  149. package/src/components/input/IInput.vue +66 -66
  150. package/src/components/menu/SideMenu.vue +75 -75
  151. package/src/components/menu/menu.js +273 -273
  152. package/src/components/tool/AStepItem.vue +60 -60
  153. package/src/layouts/CommonLayout.vue +56 -56
  154. package/src/lib.js +1 -1
  155. package/src/mock/extend/index.js +84 -84
  156. package/src/mock/goods/index.js +108 -108
  157. package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
  158. package/src/pages/system/dictionary/index.vue +44 -44
  159. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  160. package/src/pages/system/monitor/operLog/index.vue +37 -37
  161. package/src/services/api/cas.js +79 -79
  162. package/src/store/modules/setting.js +119 -119
  163. package/src/utils/errorCode.js +6 -6
  164. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
  165. package/.idea/MarsCodeWorkspaceAppSettings.xml +0 -7
  166. package/.idea/google-java-format.xml +0 -6
  167. package/.idea/inspectionProfiles/Project_Default.xml +0 -24
  168. package/.idea/jsLinters/eslint.xml +0 -6
  169. package/.idea/vue2-client.iml +0 -12
  170. package/.vscode/settings.json +0 -28
@@ -1,436 +1,1177 @@
1
- <template>
2
- <div class="ai-consultation-outer">
3
- <div class="ai-consultation-container">
4
- <div class="chat-area">
5
- <!-- 对话区域 -->
6
- <div class="dialog-area">
7
- <div
8
- v-for="(message, index) in dialogMessages"
9
- :key="index"
10
- :class="['dialog-message', message.type]"
11
- >
12
- <div class="message-text" v-html="renderMd(message.content)" />
13
- <span v-if="message.type === 'ai' && isAiStreaming && index === dialogMessages.length - 1" class="typing-cursor">▍</span>
14
- </div>
15
- </div>
16
- </div>
17
-
18
- <div class="bottom-input-wrapper">
19
- <div class="input-container">
20
- <a-textarea
21
- ref="consultTextarea"
22
- v-model="doctorInputText"
23
- placeholder="医生补充信息或提问..."
24
- class="bottom-input"
25
- :rows="1"
26
- resize="none"
27
- @input="handleInput"
28
- @keydown="handleKeydown"
29
- ></a-textarea>
30
-
31
- <div class="input-controls-right">
32
- <span class="enter-tip">Enter 发送 · Shift+Enter 换行</span>
33
- <a-button
34
- type="primary"
35
- shape="circle"
36
- class="send-btn"
37
- @click="handleSendMessage"
38
- :disabled="!doctorInputText.trim()"
39
- >
40
- <span class="send-icon">↑</span>
41
- </a-button>
42
- </div>
43
- </div>
44
- </div>
45
- </div>
46
- </div>
47
- </template>
48
-
49
- <script>
50
- import { startEventStreamPOST } from '@vue2-client/services/api/restTools'
51
- import { marked } from 'marked'
52
- import moment from 'moment/moment'
53
- import { mapState } from 'vuex'
54
-
55
- export default {
56
- name: 'AIConsultation',
57
- data() {
58
- return {
59
- currentDialogId: null,
60
- doctorInputText: '',
61
- isPlaying: false,
62
- isRecording: false,
63
- patientComplaint: '',
64
- doctorQuestions: [],
65
- examinationOrder: null,
66
- aiDiagnosis: null,
67
- dialogMessages: [],
68
- currentStreamConnection: null,
69
- isAiStreaming: false,
70
- resizeTimeout: null
71
- }
72
- },
73
- computed: {
74
- ...mapState('account', {currUser: 'user'})
75
- },
76
- mounted() {
77
- this.$nextTick(() => {
78
- this.autoResizeTextarea()
79
- })
80
- },
81
- beforeDestroy() {
82
- // 组件销毁时关闭流式连接
83
- if (this.currentStreamConnection) {
84
- this.currentStreamConnection()
85
- this.currentStreamConnection = null
86
- }
87
- if (this.resizeTimeout) {
88
- clearTimeout(this.resizeTimeout)
89
- }
90
- },
91
- methods: {
92
- autoResizeTextarea() {
93
- this.$nextTick(() => {
94
- const textarea = this.$refs.consultTextarea?.$el || this.$refs.consultTextarea
95
- if (!textarea) return
96
-
97
- textarea.style.height = 'auto'
98
- const scrollHeight = textarea.scrollHeight
99
- textarea.style.height = `${Math.min(Math.max(scrollHeight, 120), 250)}px`
100
- })
101
- },
102
-
103
- handleInput() {
104
- if (this.resizeTimeout) clearTimeout(this.resizeTimeout)
105
- this.resizeTimeout = setTimeout(() => {
106
- this.autoResizeTextarea()
107
- }, 16)
108
- },
109
-
110
- renderMd(text) {
111
- if (!text) return ''
112
- try {
113
- return marked.parse(text, { breaks: true, gfm: true, headerIds: false, mangle: false })
114
- } catch {
115
- return text
116
- }
117
- },
118
-
119
- handleKeydown(event) {
120
- if (event.key === 'Enter' && !event.shiftKey) {
121
- event.preventDefault()
122
- this.handleSendMessage()
123
- }
124
- },
125
-
126
- initDialog() {
127
- if (!this.currentDialogId) {
128
- this.currentDialogId = moment().format('YYYYMMDDHHmmss')
129
- }
130
- },
131
-
132
- clearDialog() {
133
- this.currentDialogId = moment().format('YYYYMMDDHHmmss')
134
- this.dialogMessages = []
135
- },
136
-
137
- handleSendMessage() {
138
- if (!this.doctorInputText.trim()) return
139
-
140
- // 确保有dialogId
141
- if (!this.currentDialogId) {
142
- this.initDialog()
143
- }
144
-
145
- const messageContent = this.doctorInputText.trim()
146
- const doctorMessage = {
147
- type: 'user',
148
- content: messageContent,
149
- time: new Date().toLocaleTimeString(),
150
- timestamp: Date.now()
151
- }
152
- this.dialogMessages.push(doctorMessage)
153
- this.scrollToBottom()
154
-
155
- this.doctorInputText = ''
156
- this.autoResizeTextarea()
157
-
158
- const chatId = this.currentDialogId
159
- let aiContent = ''
160
- const aiMsgIndex = this.dialogMessages.length
161
- this.dialogMessages.push({
162
- type: 'ai',
163
- content: '',
164
- time: new Date().toLocaleTimeString(),
165
- timestamp: Date.now()
166
- })
167
- this.scrollToBottom()
168
-
169
- this.isAiStreaming = true
170
-
171
- this.currentStreamConnection = startEventStreamPOST(
172
- '/his-web/api/af-his/ai/chat/stream',
173
- { userMessage: messageContent, chatId, model: '', prompt: '', useContext: true, user: this.currUser.operInfo },
174
- {'Content-Type': 'application/json'},
175
- (data, type) => {
176
- if (type === 'additionalInfo' || type === 'sourceInfo') return
177
-
178
- let textChunk = ''
179
- if (typeof data === 'object' && data !== null) {
180
- const choices = data.choices
181
- if (Array.isArray(choices) && choices.length > 0) {
182
- const delta = choices[0].delta
183
-
184
- // 优先取 delta.content(标准 OpenAI 格式)
185
- if (delta && typeof delta.content === 'string' && delta.content) {
186
- textChunk = delta.content
187
- }
188
-
189
- // 兼容百川模型的 thinking 字段
190
- if (!textChunk && delta && delta.thinking) {
191
- const thinking = delta.thinking
192
- // 取 summary 描述
193
- if (thinking.summary && typeof thinking.summary === 'string') {
194
- textChunk = `[思考中] ${thinking.summary}`
195
- }
196
- // 取 reasoning steps
197
- if (Array.isArray(thinking.steps)) {
198
- const activeStep = thinking.steps.find(s => s.status === 'in_progress')
199
- if (activeStep && activeStep.label) {
200
- textChunk = `[思考中] ${activeStep.label}`
201
- }
202
- }
203
- }
204
-
205
- // 检测模型拒答
206
- const finishReason = choices[0].finish_reason
207
- if (finishReason === 'refuse_answer') {
208
- const refuseTip = '\n\n> ⚠️ 很抱歉,当前问题我无法回答,请尝试调整提问方式或联系管理员。'
209
- if (!this.dialogMessages[aiMsgIndex].content.includes('无法回答')) {
210
- this.dialogMessages[aiMsgIndex].content += refuseTip
211
- this.isAiStreaming = false
212
- this.scrollToBottom()
213
- }
214
- }
215
- }
216
- } else if (typeof data === 'string') {
217
- textChunk = data
218
- }
219
-
220
- if (textChunk) {
221
- aiContent += textChunk
222
- this.dialogMessages[aiMsgIndex].content = aiContent
223
- this.scrollToBottom()
224
- }
225
- },
226
- (error) => {
227
- this.isAiStreaming = false
228
- this.dialogMessages[aiMsgIndex].content += `\n\n[错误: ${error.message || '请求失败'}]`
229
- this.scrollToBottom()
230
- },
231
- () => {
232
- this.isAiStreaming = false
233
- this.scrollToBottom()
234
- }
235
- )
236
- },
237
-
238
- setPatientComplaint(complaint) {
239
- this.patientComplaint = complaint
240
- },
241
-
242
- scrollToBottom(delay = 0) {
243
- this.$nextTick(() => {
244
- setTimeout(() => {
245
- const chatArea = document.querySelector('.chat-area')
246
- if (chatArea) {
247
- chatArea.scrollTop = chatArea.scrollHeight
248
- }
249
- }, delay)
250
- })
251
- },
252
-
253
- reset() {
254
- if (this.currentStreamConnection) {
255
- this.currentStreamConnection()
256
- this.currentStreamConnection = null
257
- }
258
- this.isAiStreaming = false
259
- this.patientComplaint = ''
260
- this.doctorQuestions = []
261
- this.examinationOrder = null
262
- this.aiDiagnosis = null
263
- this.doctorInputText = ''
264
- this.isPlaying = false
265
- this.isRecording = false
266
- this.dialogMessages = []
267
- this.$nextTick(() => {
268
- this.autoResizeTextarea()
269
- const chatArea = document.querySelector('.chat-area')
270
- if (chatArea) {
271
- chatArea.scrollTop = 0
272
- }
273
- })
274
- }
275
- }
276
- }
277
- </script>
278
-
279
- <style scoped>
280
- .ai-consultation-outer {
281
- box-sizing: border-box;
282
- margin: 0;
283
- padding: 0;
284
- width: 100%;
285
- height: 860px;
286
- }
287
-
288
- .ai-consultation-container {
289
- width: 100%;
290
- height: 100%;
291
- display: flex;
292
- flex-direction: column;
293
- background: #FFFFFF;
294
- border: 1px solid #E5E9F0;
295
- }
296
-
297
- .chat-area {
298
- flex: 1;
299
- overflow-y: auto;
300
- padding: 16px;
301
- background: #fff;
302
- min-height: 690px;
303
- }
304
-
305
- .dialog-area {
306
- display: flex;
307
- flex-direction: column;
308
- }
309
-
310
- /* 底部输入框区域 */
311
- .bottom-input-wrapper {
312
- flex-shrink: 0;
313
- padding: 12px 16px;
314
- background: #fff;
315
- border-top: 1px solid #E5E9F0;
316
- }
317
-
318
- .input-container {
319
- position: relative;
320
- width: 100%;
321
- }
322
-
323
- .bottom-input {
324
- width: 100%;
325
- min-height: 52px;
326
- border: 1px solid #E5E9F0;
327
- border-radius: 4px;
328
- padding: 12px 60px 12px 16px;
329
- font-family: 'Source Han Sans', 'Microsoft YaHei', sans-serif;
330
- font-size: 16px;
331
- color: #313131;
332
- resize: none;
333
- outline: none;
334
- box-sizing: border-box;
335
- }
336
-
337
- .bottom-input:focus {
338
- border-color: #1890ff;
339
- box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
340
- }
341
-
342
- .bottom-input::placeholder {
343
- color: #999;
344
- }
345
-
346
- .input-controls-right {
347
- position: absolute;
348
- right: 20px;
349
- bottom: 12px;
350
- display: flex;
351
- align-items: center;
352
- gap: 8px;
353
- z-index: 2;
354
- }
355
-
356
- .enter-tip {
357
- font-family: 'Inter', sans-serif;
358
- font-size: 14px;
359
- font-weight: 500;
360
- color: #9E9E9E;
361
- padding: 4px 8px;
362
- }
363
-
364
- .send-btn {
365
- width: 30px;
366
- height: 30px;
367
- background: #0057FE;
368
- border: none;
369
- border-radius: 50%;
370
- color: #fff;
371
- font-size: 14px;
372
- cursor: pointer;
373
- display: flex;
374
- align-items: center;
375
- justify-content: center;
376
- padding: 0;
377
- }
378
-
379
- .send-btn:hover {
380
- background: #0040cc;
381
- }
382
-
383
- .send-icon {
384
- font-size: 14px;
385
- font-weight: bold;
386
- }
387
-
388
- /* 对话区域样式 */
389
- .dialog-message {
390
- display: flex;
391
- margin-bottom: 16px;
392
- align-items: flex-start;
393
- }
394
-
395
- .dialog-message:last-child {
396
- margin-bottom: 0;
397
- }
398
-
399
- .dialog-message.ai {
400
- flex-direction: row;
401
- }
402
-
403
- .dialog-message.user {
404
- flex-direction: row-reverse;
405
- }
406
-
407
- .dialog-message.user .message-text {
408
- text-align: right;
409
- }
410
-
411
- .message-text {
412
- opacity: 1;
413
- font-family: Source Han Sans;
414
- font-size: 16px;
415
- font-weight: normal;
416
- line-height: normal;
417
- text-align: justify;
418
- letter-spacing: 0em;
419
- font-feature-settings: "kern" on;
420
- max-width: 100%;
421
- color: #313131;
422
- }
423
-
424
- .typing-cursor {
425
- display: inline-block;
426
- margin-left: 2px;
427
- color: #0057FE;
428
- font-size: 18px;
429
- animation: blink 1s step-end infinite;
430
- }
431
-
432
- @keyframes blink {
433
- 0%, 100% { opacity: 1; }
434
- 50% { opacity: 0; }
435
- }
436
- </style>
1
+ <template>
2
+ <div class="ai-consultation-outer">
3
+ <div class="ai-consultation-container">
4
+ <div class="chat-area-wrapper">
5
+ <!-- 问题导航条 -->
6
+ <div class="message-nav">
7
+ <div
8
+ v-for="(navItem, navIndex) in navMessages"
9
+ :key="`nav-${navIndex}`"
10
+ class="nav-dot"
11
+ :class="{ active: activeNavIndex === navIndex }"
12
+ :title="navItem.content"
13
+ @click="scrollToMessage(navItem.index)"
14
+ />
15
+ </div>
16
+ <div class="chat-area">
17
+ <!-- 对话区域 -->
18
+ <div class="dialog-area">
19
+ <template v-for="(item, index) in displayItems">
20
+ <div
21
+ v-if="item.type === 'divider'"
22
+ :key="`divider-${index}`"
23
+ class="dialog-divider"
24
+ >
25
+ <span class="dialog-divider-text">{{ item.text }}</span>
26
+ </div>
27
+ <div
28
+ v-else
29
+ :key="`msg-${index}`"
30
+ :class="['dialog-message', item.type]"
31
+ >
32
+ <div class="message-content">
33
+ <div class="message-bubble">
34
+ <div class="message-text" v-html="renderMd(item.content)" />
35
+ </div>
36
+ <!-- 用户消息操作按钮 - 悬浮显示 -->
37
+ <div v-if="item.type === 'user'" class="message-actions user-actions">
38
+ <span class="action-btn" title="复制" @click="copyMessage(item)">
39
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="20" height="20" viewBox="0 0 24 24"><defs><clipPath id="master_svg0_2979_064909"><rect x="24" y="0" width="24" height="24" rx="0"/></clipPath></defs><g transform="matrix(0,1,-1,0,24,-24)" clip-path="url(#master_svg0_2979_064909)"><path d="M35.0998046875,10.30078125C35.0998046875,10.30078125,43.1998046875,10.30078125,43.1998046875,10.30078125C43.1998046875,10.30078125,43.1998046875,8.30078125,43.1998046875,8.30078125C43.1998046875,8.30078125,35.0998046875,8.30078125,35.0998046875,8.30078125C35.0998046875,8.30078125,35.0998046875,10.30078125,35.0998046875,10.30078125C35.0998046875,10.30078125,35.0998046875,10.30078125,35.0998046875,10.30078125ZM43.1998046875,10.30078125C43.6416046875,10.30078125,43.9998046875,10.65895125,43.9998046875,11.10078125C43.9998046875,11.10078125,45.9998046875,11.10078125,45.9998046875,11.10078125C45.9998046875,9.55438425,44.7462046875,8.30078125,43.1998046875,8.30078125C43.1998046875,8.30078125,43.1998046875,10.30078125,43.1998046875,10.30078125C43.1998046875,10.30078125,43.1998046875,10.30078125,43.1998046875,10.30078125ZM43.9998046875,11.10078125C43.9998046875,11.10078125,43.9998046875,19.20078125,43.9998046875,19.20078125C43.9998046875,19.20078125,45.9998046875,19.20078125,45.9998046875,19.20078125C45.9998046875,19.20078125,45.9998046875,11.10078125,45.9998046875,11.10078125C45.9998046875,11.10078125,43.9998046875,11.10078125,43.9998046875,11.10078125C43.9998046875,11.10078125,43.9998046875,11.10078125,43.9998046875,11.10078125ZM43.9998046875,19.20078125C43.9998046875,19.64258125,43.6416046875,20.00078125,43.1998046875,20.00078125C43.1998046875,20.00078125,43.1998046875,22.00078125,43.1998046875,22.00078125C44.7462046875,22.00078125,45.9998046875,20.74718125,45.9998046875,19.20078125C45.9998046875,19.20078125,43.9998046875,19.20078125,43.9998046875,19.20078125C43.9998046875,19.20078125,43.9998046875,19.20078125,43.9998046875,19.20078125ZM43.1998046875,20.00078125C43.1998046875,20.00078125,35.0998046875,20.00078125,35.0998046875,20.00078125C35.0998046875,20.00078125,35.0998046875,22.00078125,35.0998046875,22.00078125C35.0998046875,22.00078125,43.1998046875,22.00078125,43.1998046875,22.00078125C43.1998046875,22.00078125,43.1998046875,20.00078125,43.1998046875,20.00078125C43.1998046875,20.00078125,43.1998046875,20.00078125,43.1998046875,20.00078125ZM35.0998046875,20.00078125C34.6579746875,20.00078125,34.2998046875,19.64258125,34.2998046875,19.20078125C34.2998046875,19.20078125,32.2998046875,19.20078125,32.2998046875,19.20078125C32.2998046875,20.74718125,33.5534076875,22.00078125,35.0998046875,22.00078125C35.0998046875,22.00078125,35.0998046875,20.00078125,35.0998046875,20.00078125C35.0998046875,20.00078125,35.0998046875,20.00078125,35.0998046875,20.00078125ZM34.2998046875,19.20078125C34.2998046875,19.20078125,34.2998046875,11.10078125,34.2998046875,11.10078125C34.2998046875,11.10078125,32.2998046875,11.10078125,32.2998046875,11.10078125C32.2998046875,11.10078125,32.2998046875,19.20078125,32.2998046875,19.20078125C32.2998046875,19.20078125,34.2998046875,19.20078125,34.2998046875,19.20078125C34.2998046875,19.20078125,34.2998046875,19.20078125,34.2998046875,19.20078125ZM34.2998046875,11.10078125C34.2998046875,10.65895125,34.6579746875,10.30078125,35.0998046875,10.30078125C35.0998046875,10.30078125,35.0998046875,8.30078125,35.0998046875,8.30078125C33.5534076875,8.30078125,32.2998046875,9.55438425,32.2998046875,11.10078125C32.2998046875,11.10078125,34.2998046875,11.10078125,34.2998046875,11.10078125C34.2998046875,11.10078125,34.2998046875,11.10078125,34.2998046875,11.10078125Z" fill="#94979E" fill-opacity="1"/><path d="M29.7,15.7C30.2522802,15.7,30.6999998,15.2523,30.6999998,14.7C30.6999998,14.1477,30.2522802,13.7,29.7,13.7C29.7,13.7,29.7,15.7,29.7,15.7C29.7,15.7,29.7,15.7,29.7,15.7ZM27,12.9C27,12.9,26,12.9,26,12.9C26,12.9,27,12.9,27,12.9C27,12.9,27,12.9,27,12.9ZM28.8,3C28.8,3,28.8,2,28.8,2C28.8,2,28.8,3,28.8,3C28.8,3,28.8,3,28.8,3ZM36.9,3C36.9,3,36.9,2,36.9,2C36.9,2,36.9,3,36.9,3C36.9,3,36.9,3,36.9,3ZM37.7,5.7C37.7,6.2522802,38.1477,6.6999998,38.7,6.6999998C39.2523,6.6999998,39.7,6.2522802,39.7,5.7C39.7,5.7,37.7,5.7,37.7,5.7C37.7,5.7,37.7,5.7,37.7,5.7ZM29.7,13.7C29.7,13.7,28.8,13.7,28.8,13.7C28.8,13.7,28.8,15.7,28.8,15.7C28.8,15.7,29.7,15.7,29.7,15.7C29.7,15.7,29.7,13.7,29.7,13.7C29.7,13.7,29.7,13.7,29.7,13.7ZM28.8,13.7C28.5878301,13.7,28.38434,13.6157,28.2343099,13.4657C28.2343099,13.4657,26.82010102,14.8799,26.82010102,14.8799C27.345203,15.405,28.057389999999998,15.7,28.8,15.7C28.8,15.7,28.8,13.7,28.8,13.7C28.8,13.7,28.8,13.7,28.8,13.7ZM28.2343099,13.4657C28.08429,13.3157,28,13.1122,28,12.9C28,12.9,26,12.9,26,12.9C26,13.6426,26.294999,14.3548,26.82010102,14.8799C26.82010102,14.8799,28.2343099,13.4657,28.2343099,13.4657C28.2343099,13.4657,28.2343099,13.4657,28.2343099,13.4657ZM28,12.9C28,12.9,28,4.8,28,4.8C28,4.8,26,4.8,26,4.8C26,4.8,26,12.9,26,12.9C26,12.9,28,12.9,28,12.9C28,12.9,28,12.9,28,12.9ZM28,4.8C28,4.5878301,28.08429,4.38434,28.2343099,4.2343098999999995C28.2343099,4.2343098999999995,26.82010102,2.82010102,26.82010102,2.82010102C26.294999,3.3452029999999997,26,4.05739,26,4.8C26,4.8,28,4.8,28,4.8C28,4.8,28,4.8,28,4.8ZM28.2343099,4.2343098999999995C28.38434,4.08429,28.5878301,4,28.8,4C28.8,4,28.8,2,28.8,2C28.057389999999998,2,27.345203,2.294999,26.82010102,2.82010102C26.82010102,2.82010102,28.2343099,4.2343098999999995,28.2343099,4.2343098999999995C28.2343099,4.2343098999999995,28.2343099,4.2343098999999995,28.2343099,4.2343098999999995ZM28.8,4C28.8,4,36.9,4,36.9,4C36.9,4,36.9,2,36.9,2C36.9,2,28.8,2,28.8,2C28.8,2,28.8,4,28.8,4C28.8,4,28.8,4,28.8,4ZM36.9,4C37.1122,4,37.3157,4.08429,37.4657,4.2343098999999995C37.4657,4.2343098999999995,38.8799,2.82010102,38.8799,2.82010102C38.3548,2.294999,37.6426,2,36.9,2C36.9,2,36.9,4,36.9,4C36.9,4,36.9,4,36.9,4ZM37.4657,4.2343098999999995C37.615700000000004,4.38434,37.7,4.5878301,37.7,4.8C37.7,4.8,39.7,4.8,39.7,4.8C39.7,4.05739,39.405,3.3452029999999997,38.8799,2.82010102C38.8799,2.82010102,37.4657,4.2343098999999995,37.4657,4.2343098999999995C37.4657,4.2343098999999995,37.4657,4.2343098999999995,37.4657,4.2343098999999995ZM37.7,4.8C37.7,4.8,37.7,5.7,37.7,5.7C37.7,5.7,39.7,5.7,39.7,5.7C39.7,5.7,39.7,4.8,39.7,4.8C39.7,4.8,37.7,4.8,37.7,4.8C37.7,4.8,37.7,4.8,37.7,4.8Z" fill="#94979E" fill-opacity="1"/></g></svg>
40
+ </span>
41
+ <span class="action-btn" title="修改" @click="editMessage(item)">
42
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="20" height="20" viewBox="0 0 24 24"><path d="M21.4545,8.3636398C22.181801,7.6363597,22.181801,6.5454497,21.4545,5.818179799999999C21.4545,5.818179799999999,18.181801,2.5454547400000003,18.181801,2.5454547400000003C17.4545,1.81818175,16.363599999999998,1.81818175,15.6364,2.5454547400000003C15.6364,2.5454547400000003,2,16.181800000000003,2,16.181800000000003C2,16.181800000000003,2,22,2,22C2,22,7.8181801,22,7.8181801,22C7.8181801,22,21.4545,8.3636398,21.4545,8.3636398ZM16.909100000000002,3.8181797C16.909100000000002,3.8181797,20.181801,7.09091,20.181801,7.09091C20.181801,7.09091,17.4545,9.8181796,17.4545,9.8181796C17.4545,9.8181796,14.1818,6.5454497,14.1818,6.5454497C14.1818,6.5454497,16.909100000000002,3.8181797,16.909100000000002,3.8181797ZM3.81818,20.181799C3.81818,20.181799,3.81818,16.909100000000002,3.81818,16.909100000000002C3.81818,16.909100000000002,12.9091,7.8181796,12.9091,7.8181796C12.9091,7.8181796,16.181800000000003,11.09091,16.181800000000003,11.09091C16.181800000000003,11.09091,7.09091,20.181799,7.09091,20.181799C7.09091,20.181799,3.81818,20.181799,3.81818,20.181799Z" fill="#94979E" fill-opacity="1"/></svg>
43
+ </span>
44
+ <span class="action-btn" title="收藏" @click="favoriteMessage(item)">
45
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="20" height="20" viewBox="0 0 24 24"><path d="M21.9251463125,8.9689453225C21.9251463125,8.5271173125,21.5670453125,8.1689453125,21.1252463125,8.1689453125C20.6833453125,8.1689453125,20.3251453125,8.5271173125,20.3251453125,8.9689453225C20.3251453125,8.9689453225,21.9251463125,8.9689453225,21.9251463125,8.9689453225C21.9251463125,8.9689453225,21.9251463125,8.9689453225,21.9251463125,8.9689453225ZM4.9064453225,18.2314453125C4.4646173125,18.2314453125,4.1064453125,18.5896153125,4.1064453125,19.0314453125C4.1064453125,19.473245312499998,4.4646173125,19.8314453125,4.9064453225,19.8314453125C4.9064453225,19.8314453125,4.9064453225,18.2314453125,4.9064453225,18.2314453125C4.9064453225,18.2314453125,4.9064453225,18.2314453125,4.9064453225,18.2314453125ZM20.3251453125,8.9689453225C20.3251453125,8.9689453225,20.3251453125,18.0314455125,20.3251453125,18.0314455125C20.3251453125,18.0314455125,21.9251463125,18.0314455125,21.9251463125,18.0314455125C21.9251463125,18.0314455125,21.9251463125,8.9689453225,21.9251463125,8.9689453225C21.9251463125,8.9689453225,20.3251453125,8.9689453225,20.3251453125,8.9689453225C20.3251453125,8.9689453225,20.3251453125,8.9689453225,20.3251453125,8.9689453225ZM20.1252463125,18.2314453125C20.1252463125,18.2314453125,4.9064453225,18.2314453125,4.9064453225,18.2314453125C4.9064453225,18.2314453125,4.9064453225,19.8314453125,4.9064453225,19.8314453125C4.9064453225,19.8314453125,20.1252463125,19.8314453125,20.1252463125,19.8314453125C20.1252463125,19.8314453125,20.1252463125,18.2314453125,20.1252463125,18.2314453125C20.1252463125,18.2314453125,20.1252463125,18.2314453125,20.1252463125,18.2314453125ZM20.3251453125,18.0314455125C20.3251453125,18.1419058125,20.2356453125,18.2314453125,20.1252463125,18.2314453125C20.1252463125,18.2314453125,20.1252463125,19.8314453125,20.1252463125,19.8314453125C21.1193443125,19.8314453125,21.9251463125,19.0255453125,21.9251463125,18.0314455125C21.9251463125,18.0314455125,20.3251453125,18.0314455125,20.3251453125,18.0314455125C20.3251453125,18.0314455125,20.3251453125,18.0314455125,20.3251453125,18.0314455125Z" fill="#94979E" fill-opacity="1"/><rect x="3.800000011920929" y="4.800000011920929" width="14.399999976158142" height="11.399999976158142" rx="1.199999988079071" fill-opacity="0" stroke-opacity="1" stroke="#94979E" fill="none" stroke-width="1.600000023841858"/><path d="M12,8C12,7.44771501,11.552285,7,11,7C10.44771501,7,10,7.44771501,10,8C10,8,12,8,12,8C12,8,12,8,12,8ZM10,13.4000001C10,13.95228,10.44771501,14.4000001,11,14.4000001C11.552285,14.4000001,12,13.95228,12,13.4000001C12,13.4000001,10,13.4000001,10,13.4000001C10,13.4000001,10,13.4000001,10,13.4000001ZM10,8C10,8,10,13.4000001,10,13.4000001C10,13.4000001,12,13.4000001,12,13.4000001C12,13.4000001,12,8,12,8C12,8,10,8,10,8C10,8,10,8,10,8Z" fill="#94979E" fill-opacity="1"/><path d="M16.7001953125,10.701171875C16.7001953125,10.148886885,16.2524803125,9.701171875,15.7001953125,9.701171875C15.1479103225,9.701171875,14.7001953125,10.148886885,14.7001953125,10.701171875C14.7001953125,10.701171875,16.7001953125,10.701171875,16.7001953125,10.701171875C16.7001953125,10.701171875,16.7001953125,10.701171875,16.7001953125,10.701171875ZM14.7001953125,16.101171975C14.7001953125,16.653451875000002,15.1479103225,17.101171975,15.7001953125,17.101171975C16.2524803125,17.101171975,16.7001953125,16.653451875000002,16.7001953125,16.101171975C16.7001953125,16.101171975,14.7001953125,16.101171975,14.7001953125,16.101171975C14.7001953125,16.101171975,14.7001953125,16.101171975,14.7001953125,16.101171975ZM14.7001953125,10.701171875C14.7001953125,10.701171875,14.7001953125,16.101171975,14.7001953125,16.101171975C14.7001953125,16.101171975,16.7001953125,16.101171975,16.7001953125,16.101171975C16.7001953125,16.101171975,16.7001953125,10.701171875,16.7001953125,10.701171875C16.7001953125,10.701171875,14.7001953125,10.701171875,14.7001953125,10.701171875C14.7001953125,10.701171875,14.7001953125,10.701171875,14.7001953125,10.701171875Z" fill="#94979E" fill-opacity="1" transform="matrix(0,1,-1,0,24.4013671875,-4.9990234375)"/></svg>
46
+ </span>
47
+ <span class="action-btn" title="删除" @click="deleteMessage(item)">
48
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="20" height="20" viewBox="0 0 24 24"><defs><clipPath id="master_svg0_2979_064907"><rect x="0" y="0" width="24" height="24" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_2979_064907)"><path d="M3.9000000953674316,5.60009765625C3.3477151053674317,5.60009765625,2.9000000953674316,6.04781266625,2.9000000953674316,6.60009765625C2.9000000953674316,7.1523826562499995,3.3477151053674317,7.60009765625,3.9000000953674316,7.60009765625C3.9000000953674316,7.60009765625,3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625C3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625ZM20.100001095367432,7.60009765625C20.652300095367433,7.60009765625,21.100001095367432,7.1523826562499995,21.100001095367432,6.60009765625C21.100001095367432,6.04781266625,20.652300095367433,5.60009765625,20.100001095367432,5.60009765625C20.100001095367432,5.60009765625,20.100001095367432,7.60009765625,20.100001095367432,7.60009765625C20.100001095367432,7.60009765625,20.100001095367432,7.60009765625,20.100001095367432,7.60009765625ZM3.9000000953674316,7.60009765625C3.9000000953674316,7.60009765625,20.100001095367432,7.60009765625,20.100001095367432,7.60009765625C20.100001095367432,7.60009765625,20.100001095367432,5.60009765625,20.100001095367432,5.60009765625C20.100001095367432,5.60009765625,3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625C3.9000000953674316,5.60009765625,3.9000000953674316,7.60009765625,3.9000000953674316,7.60009765625C3.9000000953674316,7.60009765625,3.9000000953674316,7.60009765625,3.9000000953674316,7.60009765625Z" fill="#94979E" fill-opacity="1"/><path d="M18.298828220367433,6.5999999C18.298828220367433,6.5999999,19.298828220367433,6.5999999,19.298828220367433,6.5999999C19.298828220367433,6.04772,18.851128220367432,5.5999999,18.298828220367433,5.5999999C18.298828220367433,5.5999999,18.298828220367433,6.5999999,18.298828220367433,6.5999999C18.298828220367433,6.5999999,18.298828220367433,6.5999999,18.298828220367433,6.5999999ZM5.698828220367432,19.200001C5.698828220367432,19.200001,4.698828220367432,19.200001,4.698828220367432,19.200001C4.698828220367432,19.200001,5.698828220367432,19.200001,5.698828220367432,19.200001C5.698828220367432,19.200001,5.698828220367432,19.200001,5.698828220367432,19.200001ZM5.698828220367432,6.5999999C5.698828220367432,6.5999999,5.698828220367432,5.5999999,5.698828220367432,5.5999999C5.146543230367431,5.5999999,4.698828220367432,6.04772,4.698828220367432,6.5999999C4.698828220367432,6.5999999,5.698828220367432,6.5999999,5.698828220367432,6.5999999C5.698828220367432,6.5999999,5.698828220367432,6.5999999,5.698828220367432,6.5999999ZM7.398828220367432,6.5999999C7.398828220367432,7.1522799,7.8465483203674316,7.5999999,8.398828220367431,7.5999999C8.951108420367433,7.5999999,9.398828020367432,7.1522799,9.398828020367432,6.5999999C9.398828020367432,6.5999999,7.398828220367432,6.5999999,7.398828220367432,6.5999999C7.398828220367432,6.5999999,7.398828220367432,6.5999999,7.398828220367432,6.5999999ZM10.198828220367432,3C10.198828220367432,3,10.198828220367432,2,10.198828220367432,2C10.198828220367432,2,10.198828220367432,3,10.198828220367432,3C10.198828220367432,3,10.198828220367432,3,10.198828220367432,3ZM13.798828620367432,3C13.798828620367432,3,13.798828620367432,2,13.798828620367432,2C13.798828620367432,2,13.798828620367432,3,13.798828620367432,3C13.798828620367432,3,13.798828620367432,3,13.798828620367432,3ZM14.59882782036743,6.5999999C14.59882782036743,7.1522799,15.046548220367432,7.5999999,15.598828220367432,7.5999999C16.151128220367433,7.5999999,16.59882822036743,7.1522799,16.59882822036743,6.5999999C16.59882822036743,6.5999999,14.59882782036743,6.5999999,14.59882782036743,6.5999999C14.59882782036743,6.5999999,14.59882782036743,6.5999999,14.59882782036743,6.5999999ZM17.298828220367433,6.5999999C17.298828220367433,6.5999999,17.298828220367433,19.200001,17.298828220367433,19.200001C17.298828220367433,19.200001,19.298828220367433,19.200001,19.298828220367433,19.200001C19.298828220367433,19.200001,19.298828220367433,6.5999999,19.298828220367433,6.5999999C19.298828220367433,6.5999999,17.298828220367433,6.5999999,17.298828220367433,6.5999999C17.298828220367433,6.5999999,17.298828220367433,6.5999999,17.298828220367433,6.5999999ZM17.298828220367433,19.200001C17.298828220367433,19.412201,17.214528220367434,19.6157,17.064528220367432,19.765699C17.064528220367432,19.765699,18.47872822036743,21.179899,18.47872822036743,21.179899C19.00382822036743,20.6548,19.298828220367433,19.9426,19.298828220367433,19.200001C19.298828220367433,19.200001,17.298828220367433,19.200001,17.298828220367433,19.200001C17.298828220367433,19.200001,17.298828220367433,19.200001,17.298828220367433,19.200001ZM17.064528220367432,19.765699C16.91452822036743,19.915701,16.71102822036743,20,16.498828220367432,20C16.498828220367432,20,16.498828220367432,22,16.498828220367432,22C17.241428220367432,22,17.95362822036743,21.705,18.47872822036743,21.179899C18.47872822036743,21.179899,17.064528220367432,19.765699,17.064528220367432,19.765699C17.064528220367432,19.765699,17.064528220367432,19.765699,17.064528220367432,19.765699ZM16.498828220367432,20C16.498828220367432,20,7.4988282203674315,20,7.4988282203674315,20C7.4988282203674315,20,7.4988282203674315,22,7.4988282203674315,22C7.4988282203674315,22,16.498828220367432,22,16.498828220367432,22C16.498828220367432,22,16.498828220367432,20,16.498828220367432,20C16.498828220367432,20,16.498828220367432,20,16.498828220367432,20ZM7.4988282203674315,20C7.286658320367431,20,7.0831682203674315,19.915701,6.933138120367431,19.765699C6.933138120367431,19.765699,5.518929240367432,21.179899,5.518929240367432,21.179899C6.044031220367431,21.705,6.7562182203674315,22,7.4988282203674315,22C7.4988282203674315,22,7.4988282203674315,20,7.4988282203674315,20C7.4988282203674315,20,7.4988282203674315,20,7.4988282203674315,20ZM6.933138120367431,19.765699C6.783118220367432,19.6157,6.698828220367432,19.412201,6.698828220367432,19.200001C6.698828220367432,19.200001,4.698828220367432,19.200001,4.698828220367432,19.200001C4.698828220367432,19.9426,4.993827220367431,20.6548,5.518929240367432,21.179899C5.518929240367432,21.179899,6.933138120367431,19.765699,6.933138120367431,19.765699C6.933138120367431,19.765699,6.933138120367431,19.765699,6.933138120367431,19.765699ZM6.698828220367432,19.200001C6.698828220367432,19.200001,6.698828220367432,6.5999999,6.698828220367432,6.5999999C6.698828220367432,6.5999999,4.698828220367432,6.5999999,4.698828220367432,6.5999999C4.698828220367432,6.5999999,4.698828220367432,19.200001,4.698828220367432,19.200001C4.698828220367432,19.200001,6.698828220367432,19.200001,6.698828220367432,19.200001C6.698828220367432,19.200001,6.698828220367432,19.200001,6.698828220367432,19.200001ZM5.698828220367432,7.5999999C5.698828220367432,7.5999999,18.298828220367433,7.5999999,18.298828220367433,7.5999999C18.298828220367433,7.5999999,18.298828220367433,5.5999999,18.298828220367433,5.5999999C18.298828220367433,5.5999999,5.698828220367432,5.5999999,5.698828220367432,5.5999999C5.698828220367432,5.5999999,5.698828220367432,7.5999999,5.698828220367432,7.5999999C5.698828220367432,7.5999999,5.698828220367432,7.5999999,5.698828220367432,7.5999999ZM9.398828020367432,6.5999999C9.398828020367432,6.5999999,9.398828020367432,4.8,9.398828020367432,4.8C9.398828020367432,4.8,7.398828220367432,4.8,7.398828220367432,4.8C7.398828220367432,4.8,7.398828220367432,6.5999999,7.398828220367432,6.5999999C7.398828220367432,6.5999999,9.398828020367432,6.5999999,9.398828020367432,6.5999999C9.398828020367432,6.5999999,9.398828020367432,6.5999999,9.398828020367432,6.5999999ZM9.398828020367432,4.8C9.398828020367432,4.5878301,9.483118020367431,4.38434,9.633138220367432,4.2343098999999995C9.633138220367432,4.2343098999999995,8.218928320367432,2.82010102,8.218928320367432,2.82010102C7.6938281203674315,3.345202,7.398828220367432,4.05739,7.398828220367432,4.8C7.398828220367432,4.8,9.398828020367432,4.8,9.398828020367432,4.8C9.398828020367432,4.8,9.398828020367432,4.8,9.398828020367432,4.8ZM9.633138220367432,4.2343098999999995C9.783168320367432,4.08429,9.986658120367432,4,10.198828220367432,4C10.198828220367432,4,10.198828220367432,2,10.198828220367432,2C9.456218220367433,2,8.744028120367432,2.294999,8.218928320367432,2.82010102C8.218928320367432,2.82010102,9.633138220367432,4.2343098999999995,9.633138220367432,4.2343098999999995C9.633138220367432,4.2343098999999995,9.633138220367432,4.2343098999999995,9.633138220367432,4.2343098999999995ZM10.198828220367432,4C10.198828220367432,4,13.798828620367432,4,13.798828620367432,4C13.798828620367432,4,13.798828620367432,2,13.798828620367432,2C13.798828620367432,2,10.198828220367432,2,10.198828220367432,2C10.198828220367432,2,10.198828220367432,4,10.198828220367432,4C10.198828220367432,4,10.198828220367432,4,10.198828220367432,4ZM13.798828620367432,4C14.010998220367432,4,14.214488520367432,4.08429,14.364518620367432,4.2343098999999995C14.364518620367432,4.2343098999999995,15.778728220367432,2.82010102,15.778728220367432,2.82010102C15.253628220367432,2.294999,14.541438620367432,2,13.798828620367432,2C13.798828620367432,2,13.798828620367432,4,13.798828620367432,4C13.798828620367432,4,13.798828620367432,4,13.798828620367432,4ZM14.364518620367432,4.2343098999999995C14.514538320367432,4.38434,14.59882782036743,4.5878301,14.59882782036743,4.8C14.59882782036743,4.8,16.59882822036743,4.8,16.59882822036743,4.8C16.59882822036743,4.05739,16.303828220367432,3.345202,15.778728220367432,2.82010102C15.778728220367432,2.82010102,14.364518620367432,4.2343098999999995,14.364518620367432,4.2343098999999995C14.364518620367432,4.2343098999999995,14.364518620367432,4.2343098999999995,14.364518620367432,4.2343098999999995ZM14.59882782036743,4.8C14.59882782036743,4.8,14.59882782036743,6.5999999,14.59882782036743,6.5999999C14.59882782036743,6.5999999,16.59882822036743,6.5999999,16.59882822036743,6.5999999C16.59882822036743,6.5999999,16.59882822036743,4.8,16.59882822036743,4.8C16.59882822036743,4.8,14.59882782036743,4.8,14.59882782036743,4.8C14.59882782036743,4.8,14.59882782036743,4.8,14.59882782036743,4.8Z" fill="#94979E" fill-opacity="1"/><path d="M11.198828220367432,11.10009765625C11.198828220367432,10.54781266625,10.751113220367431,10.10009765625,10.198828220367432,10.10009765625C9.646543230367431,10.10009765625,9.198828220367432,10.54781266625,9.198828220367432,11.10009765625C9.198828220367432,11.10009765625,11.198828220367432,11.10009765625,11.198828220367432,11.10009765625C11.198828220367432,11.10009765625,11.198828220367432,11.10009765625,11.198828220367432,11.10009765625ZM9.198828220367432,16.50009775625C9.198828220367432,17.052377656250002,9.646543230367431,17.50009775625,10.198828220367432,17.50009775625C10.751113220367431,17.50009775625,11.198828220367432,17.052377656250002,11.198828220367432,16.50009775625C11.198828220367432,16.50009775625,9.198828220367432,16.50009775625,9.198828220367432,16.50009775625C9.198828220367432,16.50009775625,9.198828220367432,16.50009775625,9.198828220367432,16.50009775625ZM9.198828220367432,11.10009765625C9.198828220367432,11.10009765625,9.198828220367432,16.50009775625,9.198828220367432,16.50009775625C9.198828220367432,16.50009775625,11.198828220367432,16.50009775625,11.198828220367432,16.50009775625C11.198828220367432,16.50009775625,11.198828220367432,11.10009765625,11.198828220367432,11.10009765625C11.198828220367432,11.10009765625,9.198828220367432,11.10009765625,9.198828220367432,11.10009765625C9.198828220367432,11.10009765625,9.198828220367432,11.10009765625,9.198828220367432,11.10009765625Z" fill="#94979E" fill-opacity="1"/><path d="M14.800390720367432,11.10009765625C14.800390720367432,10.54781266625,14.352675720367431,10.10009765625,13.800390720367432,10.10009765625C13.248105730367431,10.10009765625,12.800390720367432,10.54781266625,12.800390720367432,11.10009765625C12.800390720367432,11.10009765625,14.800390720367432,11.10009765625,14.800390720367432,11.10009765625C14.800390720367432,11.10009765625,14.800390720367432,11.10009765625,14.800390720367432,11.10009765625ZM12.800390720367432,16.50009775625C12.800390720367432,17.052377656250002,13.248105730367431,17.50009775625,13.800390720367432,17.50009775625C14.352675720367431,17.50009775625,14.800390720367432,17.052377656250002,14.800390720367432,16.50009775625C14.800390720367432,16.50009775625,12.800390720367432,16.50009775625,12.800390720367432,16.50009775625C12.800390720367432,16.50009775625,12.800390720367432,16.50009775625,12.800390720367432,16.50009775625ZM12.800390720367432,11.10009765625C12.800390720367432,11.10009765625,12.800390720367432,16.50009775625,12.800390720367432,16.50009775625C12.800390720367432,16.50009775625,14.800390720367432,16.50009775625,14.800390720367432,16.50009775625C14.800390720367432,16.50009775625,14.800390720367432,11.10009765625,14.800390720367432,11.10009765625C14.800390720367432,11.10009765625,12.800390720367432,11.10009765625,12.800390720367432,11.10009765625C12.800390720367432,11.10009765625,12.800390720367432,11.10009765625,12.800390720367432,11.10009765625Z" fill="#94979E" fill-opacity="1"/></g></svg>
49
+ </span>
50
+ </div>
51
+ <!-- AI消息操作按钮 - 始终显示 -->
52
+ <div v-if="item.type === 'ai'" class="message-actions ai-actions">
53
+ <span class="action-btn" title="复制" @click="copyMessage(item)">
54
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="20" height="20" viewBox="0 0 24 24"><defs><clipPath id="master_svg0_2979_064909"><rect x="24" y="0" width="24" height="24" rx="0"/></clipPath></defs><g transform="matrix(0,1,-1,0,24,-24)" clip-path="url(#master_svg0_2979_064909)"><path d="M35.0998046875,10.30078125C35.0998046875,10.30078125,43.1998046875,10.30078125,43.1998046875,10.30078125C43.1998046875,10.30078125,43.1998046875,8.30078125,43.1998046875,8.30078125C43.1998046875,8.30078125,35.0998046875,8.30078125,35.0998046875,8.30078125C35.0998046875,8.30078125,35.0998046875,10.30078125,35.0998046875,10.30078125C35.0998046875,10.30078125,35.0998046875,10.30078125,35.0998046875,10.30078125ZM43.1998046875,10.30078125C43.6416046875,10.30078125,43.9998046875,10.65895125,43.9998046875,11.10078125C43.9998046875,11.10078125,45.9998046875,11.10078125,45.9998046875,11.10078125C45.9998046875,9.55438425,44.7462046875,8.30078125,43.1998046875,8.30078125C43.1998046875,8.30078125,43.1998046875,10.30078125,43.1998046875,10.30078125C43.1998046875,10.30078125,43.1998046875,10.30078125,43.1998046875,10.30078125ZM43.9998046875,11.10078125C43.9998046875,11.10078125,43.9998046875,19.20078125,43.9998046875,19.20078125C43.9998046875,19.20078125,45.9998046875,19.20078125,45.9998046875,19.20078125C45.9998046875,19.20078125,45.9998046875,11.10078125,45.9998046875,11.10078125C45.9998046875,11.10078125,43.9998046875,11.10078125,43.9998046875,11.10078125C43.9998046875,11.10078125,43.9998046875,11.10078125,43.9998046875,11.10078125ZM43.9998046875,19.20078125C43.9998046875,19.64258125,43.6416046875,20.00078125,43.1998046875,20.00078125C43.1998046875,20.00078125,43.1998046875,22.00078125,43.1998046875,22.00078125C44.7462046875,22.00078125,45.9998046875,20.74718125,45.9998046875,19.20078125C45.9998046875,19.20078125,43.9998046875,19.20078125,43.9998046875,19.20078125C43.9998046875,19.20078125,43.9998046875,19.20078125,43.9998046875,19.20078125ZM43.1998046875,20.00078125C43.1998046875,20.00078125,35.0998046875,20.00078125,35.0998046875,20.00078125C35.0998046875,20.00078125,35.0998046875,22.00078125,35.0998046875,22.00078125C35.0998046875,22.00078125,43.1998046875,22.00078125,43.1998046875,22.00078125C43.1998046875,22.00078125,43.1998046875,20.00078125,43.1998046875,20.00078125C43.1998046875,20.00078125,43.1998046875,20.00078125,43.1998046875,20.00078125ZM35.0998046875,20.00078125C34.6579746875,20.00078125,34.2998046875,19.64258125,34.2998046875,19.20078125C34.2998046875,19.20078125,32.2998046875,19.20078125,32.2998046875,19.20078125C32.2998046875,20.74718125,33.5534076875,22.00078125,35.0998046875,22.00078125C35.0998046875,22.00078125,35.0998046875,20.00078125,35.0998046875,20.00078125C35.0998046875,20.00078125,35.0998046875,20.00078125,35.0998046875,20.00078125ZM34.2998046875,19.20078125C34.2998046875,19.20078125,34.2998046875,11.10078125,34.2998046875,11.10078125C34.2998046875,11.10078125,32.2998046875,11.10078125,32.2998046875,11.10078125C32.2998046875,11.10078125,32.2998046875,19.20078125,32.2998046875,19.20078125C32.2998046875,19.20078125,34.2998046875,19.20078125,34.2998046875,19.20078125C34.2998046875,19.20078125,34.2998046875,19.20078125,34.2998046875,19.20078125ZM34.2998046875,11.10078125C34.2998046875,10.65895125,34.6579746875,10.30078125,35.0998046875,10.30078125C35.0998046875,10.30078125,35.0998046875,8.30078125,35.0998046875,8.30078125C33.5534076875,8.30078125,32.2998046875,9.55438425,32.2998046875,11.10078125C32.2998046875,11.10078125,34.2998046875,11.10078125,34.2998046875,11.10078125C34.2998046875,11.10078125,34.2998046875,11.10078125,34.2998046875,11.10078125Z" fill="#94979E" fill-opacity="1"/><path d="M29.7,15.7C30.2522802,15.7,30.6999998,15.2523,30.6999998,14.7C30.6999998,14.1477,30.2522802,13.7,29.7,13.7C29.7,13.7,29.7,15.7,29.7,15.7C29.7,15.7,29.7,15.7,29.7,15.7ZM27,12.9C27,12.9,26,12.9,26,12.9C26,12.9,27,12.9,27,12.9C27,12.9,27,12.9,27,12.9ZM28.8,3C28.8,3,28.8,2,28.8,2C28.8,2,28.8,3,28.8,3C28.8,3,28.8,3,28.8,3ZM36.9,3C36.9,3,36.9,2,36.9,2C36.9,2,36.9,3,36.9,3C36.9,3,36.9,3,36.9,3ZM37.7,5.7C37.7,6.2522802,38.1477,6.6999998,38.7,6.6999998C39.2523,6.6999998,39.7,6.2522802,39.7,5.7C39.7,5.7,37.7,5.7,37.7,5.7C37.7,5.7,37.7,5.7,37.7,5.7ZM29.7,13.7C29.7,13.7,28.8,13.7,28.8,13.7C28.8,13.7,28.8,15.7,28.8,15.7C28.8,15.7,29.7,15.7,29.7,15.7C29.7,15.7,29.7,13.7,29.7,13.7C29.7,13.7,29.7,13.7,29.7,13.7ZM28.8,13.7C28.5878301,13.7,28.38434,13.6157,28.2343099,13.4657C28.2343099,13.4657,26.82010102,14.8799,26.82010102,14.8799C27.345203,15.405,28.057389999999998,15.7,28.8,15.7C28.8,15.7,28.8,13.7,28.8,13.7C28.8,13.7,28.8,13.7,28.8,13.7ZM28.2343099,13.4657C28.08429,13.3157,28,13.1122,28,12.9C28,12.9,26,12.9,26,12.9C26,13.6426,26.294999,14.3548,26.82010102,14.8799C26.82010102,14.8799,28.2343099,13.4657,28.2343099,13.4657C28.2343099,13.4657,28.2343099,13.4657,28.2343099,13.4657ZM28,12.9C28,12.9,28,4.8,28,4.8C28,4.8,26,4.8,26,4.8C26,4.8,26,12.9,26,12.9C26,12.9,28,12.9,28,12.9C28,12.9,28,12.9,28,12.9ZM28,4.8C28,4.5878301,28.08429,4.38434,28.2343099,4.2343098999999995C28.2343099,4.2343098999999995,26.82010102,2.82010102,26.82010102,2.82010102C26.294999,3.3452029999999997,26,4.05739,26,4.8C26,4.8,28,4.8,28,4.8C28,4.8,28,4.8,28,4.8ZM28.2343099,4.2343098999999995C28.38434,4.08429,28.5878301,4,28.8,4C28.8,4,28.8,2,28.8,2C28.057389999999998,2,27.345203,2.294999,26.82010102,2.82010102C26.82010102,2.82010102,28.2343099,4.2343098999999995,28.2343099,4.2343098999999995C28.2343099,4.2343098999999995,28.2343099,4.2343098999999995,28.2343099,4.2343098999999995ZM28.8,4C28.8,4,36.9,4,36.9,4C36.9,4,36.9,2,36.9,2C36.9,2,28.8,2,28.8,2C28.8,2,28.8,4,28.8,4C28.8,4,28.8,4,28.8,4ZM36.9,4C37.1122,4,37.3157,4.08429,37.4657,4.2343098999999995C37.4657,4.2343098999999995,38.8799,2.82010102,38.8799,2.82010102C38.3548,2.294999,37.6426,2,36.9,2C36.9,2,36.9,4,36.9,4C36.9,4,36.9,4,36.9,4ZM37.4657,4.2343098999999995C37.615700000000004,4.38434,37.7,4.5878301,37.7,4.8C37.7,4.8,39.7,4.8,39.7,4.8C39.7,4.05739,39.405,3.3452029999999997,38.8799,2.82010102C38.8799,2.82010102,37.4657,4.2343098999999995,37.4657,4.2343098999999995C37.4657,4.2343098999999995,37.4657,4.2343098999999995,37.4657,4.2343098999999995ZM37.7,4.8C37.7,4.8,37.7,5.7,37.7,5.7C37.7,5.7,39.7,5.7,39.7,5.7C39.7,5.7,39.7,4.8,39.7,4.8C39.7,4.8,37.7,4.8,37.7,4.8C37.7,4.8,37.7,4.8,37.7,4.8Z" fill="#94979E" fill-opacity="1"/></g></svg>
55
+ </span>
56
+ <span class="action-btn" title="刷新" @click="regenerateAiResponse(item)">
57
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#94979E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-9-9c2.52 0 4.93 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/></svg>
58
+ </span>
59
+ <span class="action-btn" title="收藏" @click="favoriteMessage(item)">
60
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="20" height="20" viewBox="0 0 24 24"><path d="M21.9251463125,8.9689453225C21.9251463125,8.5271173125,21.5670453125,8.1689453125,21.1252463125,8.1689453125C20.6833453125,8.1689453125,20.3251453125,8.5271173125,20.3251453125,8.9689453225C20.3251453125,8.9689453225,21.9251463125,8.9689453225,21.9251463125,8.9689453225C21.9251463125,8.9689453225,21.9251463125,8.9689453225,21.9251463125,8.9689453225ZM4.9064453225,18.2314453125C4.4646173125,18.2314453125,4.1064453125,18.5896153125,4.1064453125,19.0314453125C4.1064453125,19.473245312499998,4.4646173125,19.8314453125,4.9064453225,19.8314453125C4.9064453225,19.8314453125,4.9064453225,18.2314453125,4.9064453225,18.2314453125C4.9064453225,18.2314453125,4.9064453225,18.2314453125,4.9064453225,18.2314453125ZM20.3251453125,8.9689453225C20.3251453125,8.9689453225,20.3251453125,18.0314455125,20.3251453125,18.0314455125C20.3251453125,18.0314455125,21.9251463125,18.0314455125,21.9251463125,18.0314455125C21.9251463125,18.0314455125,21.9251463125,8.9689453225,21.9251463125,8.9689453225C21.9251463125,8.9689453225,20.3251453125,8.9689453225,20.3251453125,8.9689453225C20.3251453125,8.9689453225,20.3251453125,8.9689453225,20.3251453125,8.9689453225ZM20.1252463125,18.2314453125C20.1252463125,18.2314453125,4.9064453225,18.2314453125,4.9064453225,18.2314453125C4.9064453225,18.2314453125,4.9064453225,19.8314453125,4.9064453225,19.8314453125C4.9064453225,19.8314453125,20.1252463125,19.8314453125,20.1252463125,19.8314453125C20.1252463125,19.8314453125,20.1252463125,18.2314453125,20.1252463125,18.2314453125C20.1252463125,18.2314453125,20.1252463125,18.2314453125,20.1252463125,18.2314453125ZM20.3251453125,18.0314455125C20.3251453125,18.1419058125,20.2356453125,18.2314453125,20.1252463125,18.2314453125C20.1252463125,18.2314453125,20.1252463125,19.8314453125,20.1252463125,19.8314453125C21.1193443125,19.8314453125,21.9251463125,19.0255453125,21.9251463125,18.0314455125C21.9251463125,18.0314455125,20.3251453125,18.0314455125,20.3251453125,18.0314455125C20.3251453125,18.0314455125,20.3251453125,18.0314455125,20.3251453125,18.0314455125Z" fill="#94979E" fill-opacity="1"/><rect x="3.800000011920929" y="4.800000011920929" width="14.399999976158142" height="11.399999976158142" rx="1.199999988079071" fill-opacity="0" stroke-opacity="1" stroke="#94979E" fill="none" stroke-width="1.600000023841858"/><path d="M12,8C12,7.44771501,11.552285,7,11,7C10.44771501,7,10,7.44771501,10,8C10,8,12,8,12,8C12,8,12,8,12,8ZM10,13.4000001C10,13.95228,10.44771501,14.4000001,11,14.4000001C11.552285,14.4000001,12,13.95228,12,13.4000001C12,13.4000001,10,13.4000001,10,13.4000001C10,13.4000001,10,13.4000001,10,13.4000001ZM10,8C10,8,10,13.4000001,10,13.4000001C10,13.4000001,12,13.4000001,12,13.4000001C12,13.4000001,12,8,12,8C12,8,10,8,10,8C10,8,10,8,10,8Z" fill="#94979E" fill-opacity="1"/><path d="M16.7001953125,10.701171875C16.7001953125,10.148886885,16.2524803125,9.701171875,15.7001953125,9.701171875C15.1479103225,9.701171875,14.7001953125,10.148886885,14.7001953125,10.701171875C14.7001953125,10.701171875,16.7001953125,10.701171875,16.7001953125,10.701171875C16.7001953125,10.701171875,16.7001953125,10.701171875,16.7001953125,10.701171875ZM14.7001953125,16.101171975C14.7001953125,16.653451875000002,15.1479103225,17.101171975,15.7001953125,17.101171975C16.2524803125,17.101171975,16.7001953125,16.653451875000002,16.7001953125,16.101171975C16.7001953125,16.101171975,14.7001953125,16.101171975,14.7001953125,16.101171975C14.7001953125,16.101171975,14.7001953125,16.101171975,14.7001953125,16.101171975ZM14.7001953125,10.701171875C14.7001953125,10.701171875,14.7001953125,16.101171975,14.7001953125,16.101171975C14.7001953125,16.101171975,16.7001953125,16.101171975,16.7001953125,16.101171975C16.7001953125,16.101171975,16.7001953125,10.701171875,16.7001953125,10.701171875C16.7001953125,10.701171875,14.7001953125,10.701171875,14.7001953125,10.701171875C14.7001953125,10.701171875,14.7001953125,10.701171875,14.7001953125,10.701171875Z" fill="#94979E" fill-opacity="1" transform="matrix(0,1,-1,0,24.4013671875,-4.9990234375)"/></svg>
61
+ </span>
62
+ <span class="action-btn" title="删除" @click="deleteMessage(item)">
63
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="20" height="20" viewBox="0 0 24 24"><defs><clipPath id="master_svg0_2979_064907"><rect x="0" y="0" width="24" height="24" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_2979_064907)"><path d="M3.9000000953674316,5.60009765625C3.3477151053674317,5.60009765625,2.9000000953674316,6.04781266625,2.9000000953674316,6.60009765625C2.9000000953674316,7.1523826562499995,3.3477151053674317,7.60009765625,3.9000000953674316,7.60009765625C3.9000000953674316,7.60009765625,3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625C3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625ZM20.100001095367432,7.60009765625C20.652300095367433,7.60009765625,21.100001095367432,7.1523826562499995,21.100001095367432,6.60009765625C21.100001095367432,6.04781266625,20.652300095367433,5.60009765625,20.100001095367432,5.60009765625C20.100001095367432,5.60009765625,20.100001095367432,7.60009765625,20.100001095367432,7.60009765625C20.100001095367432,7.60009765625,20.100001095367432,7.60009765625,20.100001095367432,7.60009765625ZM3.9000000953674316,7.60009765625C3.9000000953674316,7.60009765625,20.100001095367432,7.60009765625,20.100001095367432,7.60009765625C20.100001095367432,7.60009765625,20.100001095367432,5.60009765625,20.100001095367432,5.60009765625C20.100001095367432,5.60009765625,3.9000000953674316,5.60009765625,3.9000000953674316,5.60009765625C3.9000000953674316,5.60009765625,3.9000000953674316,7.60009765625,3.9000000953674316,7.60009765625C3.9000000953674316,7.60009765625,3.9000000953674316,7.60009765625,3.9000000953674316,7.60009765625Z" fill="#94979E" fill-opacity="1"/><path d="M18.298828220367433,6.5999999C18.298828220367433,6.5999999,19.298828220367433,6.5999999,19.298828220367433,6.5999999C19.298828220367433,6.04772,18.851128220367432,5.5999999,18.298828220367433,5.5999999C18.298828220367433,5.5999999,18.298828220367433,6.5999999,18.298828220367433,6.5999999C18.298828220367433,6.5999999,18.298828220367433,6.5999999,18.298828220367433,6.5999999ZM5.698828220367432,19.200001C5.698828220367432,19.200001,4.698828220367432,19.200001,4.698828220367432,19.200001C4.698828220367432,19.200001,5.698828220367432,19.200001,5.698828220367432,19.200001C5.698828220367432,19.200001,5.698828220367432,19.200001,5.698828220367432,19.200001ZM5.698828220367432,6.5999999C5.698828220367432,6.5999999,5.698828220367432,5.5999999,5.698828220367432,5.5999999C5.146543230367431,5.5999999,4.698828220367432,6.04772,4.698828220367432,6.5999999C4.698828220367432,6.5999999,5.698828220367432,6.5999999,5.698828220367432,6.5999999C5.698828220367432,6.5999999,5.698828220367432,6.5999999,5.698828220367432,6.5999999ZM7.398828220367432,6.5999999C7.398828220367432,7.1522799,7.8465483203674316,7.5999999,8.398828220367431,7.5999999C8.951108420367433,7.5999999,9.398828020367432,7.1522799,9.398828020367432,6.5999999C9.398828020367432,6.5999999,7.398828220367432,6.5999999,7.398828220367432,6.5999999C7.398828220367432,6.5999999,7.398828220367432,6.5999999,7.398828220367432,6.5999999ZM10.198828220367432,3C10.198828220367432,3,10.198828220367432,2,10.198828220367432,2C10.198828220367432,2,10.198828220367432,3,10.198828220367432,3C10.198828220367432,3,10.198828220367432,3,10.198828220367432,3ZM13.798828620367432,3C13.798828620367432,3,13.798828620367432,2,13.798828620367432,2C13.798828620367432,2,13.798828620367432,3,13.798828620367432,3C13.798828620367432,3,13.798828620367432,3,13.798828620367432,3ZM14.59882782036743,6.5999999C14.59882782036743,7.1522799,15.046548220367432,7.5999999,15.598828220367432,7.5999999C16.151128220367433,7.5999999,16.59882822036743,7.1522799,16.59882822036743,6.5999999C16.59882822036743,6.5999999,14.59882782036743,6.5999999,14.59882782036743,6.5999999C14.59882782036743,6.5999999,14.59882782036743,6.5999999,14.59882782036743,6.5999999ZM17.298828220367433,6.5999999C17.298828220367433,6.5999999,17.298828220367433,19.200001,17.298828220367433,19.200001C17.298828220367433,19.200001,19.298828220367433,19.200001,19.298828220367433,19.200001C19.298828220367433,19.200001,19.298828220367433,6.5999999,19.298828220367433,6.5999999C19.298828220367433,6.5999999,17.298828220367433,6.5999999,17.298828220367433,6.5999999C17.298828220367433,6.5999999,17.298828220367433,6.5999999,17.298828220367433,6.5999999ZM17.298828220367433,19.200001C17.298828220367433,19.412201,17.214528220367434,19.6157,17.064528220367432,19.765699C17.064528220367432,19.765699,18.47872822036743,21.179899,18.47872822036743,21.179899C19.00382822036743,20.6548,19.298828220367433,19.9426,19.298828220367433,19.200001C19.298828220367433,19.200001,17.298828220367433,19.200001,17.298828220367433,19.200001C17.298828220367433,19.200001,17.298828220367433,19.200001,17.298828220367433,19.200001ZM17.064528220367432,19.765699C16.91452822036743,19.915701,16.71102822036743,20,16.498828220367432,20C16.498828220367432,20,16.498828220367432,22,16.498828220367432,22C17.241428220367432,22,17.95362822036743,21.705,18.47872822036743,21.179899C18.47872822036743,21.179899,17.064528220367432,19.765699,17.064528220367432,19.765699C17.064528220367432,19.765699,17.064528220367432,19.765699,17.064528220367432,19.765699ZM16.498828220367432,20C16.498828220367432,20,7.4988282203674315,20,7.4988282203674315,20C7.4988282203674315,20,7.4988282203674315,22,7.4988282203674315,22C7.4988282203674315,22,16.498828220367432,22,16.498828220367432,22C16.498828220367432,22,16.498828220367432,20,16.498828220367432,20C16.498828220367432,20,16.498828220367432,20,16.498828220367432,20ZM7.4988282203674315,20C7.286658320367431,20,7.0831682203674315,19.915701,6.933138120367431,19.765699C6.933138120367431,19.765699,5.518929240367432,21.179899,5.518929240367432,21.179899C6.044031220367431,21.705,6.7562182203674315,22,7.4988282203674315,22C7.4988282203674315,22,7.4988282203674315,20,7.4988282203674315,20C7.4988282203674315,20,7.4988282203674315,20,7.4988282203674315,20ZM6.933138120367431,19.765699C6.783118220367432,19.6157,6.698828220367432,19.412201,6.698828220367432,19.200001C6.698828220367432,19.200001,4.698828220367432,19.200001,4.698828220367432,19.200001C4.698828220367432,19.9426,4.993827220367431,20.6548,5.518929240367432,21.179899C5.518929240367432,21.179899,6.933138120367431,19.765699,6.933138120367431,19.765699C6.933138120367431,19.765699,6.933138120367431,19.765699,6.933138120367431,19.765699ZM6.698828220367432,19.200001C6.698828220367432,19.200001,6.698828220367432,6.5999999,6.698828220367432,6.5999999C6.698828220367432,6.5999999,4.698828220367432,6.5999999,4.698828220367432,6.5999999C4.698828220367432,6.5999999,4.698828220367432,19.200001,4.698828220367432,19.200001C4.698828220367432,19.200001,6.698828220367432,19.200001,6.698828220367432,19.200001C6.698828220367432,19.200001,6.698828220367432,19.200001,6.698828220367432,19.200001ZM5.698828220367432,7.5999999C5.698828220367432,7.5999999,18.298828220367433,7.5999999,18.298828220367433,7.5999999C18.298828220367433,7.5999999,18.298828220367433,5.5999999,18.298828220367433,5.5999999C18.298828220367433,5.5999999,5.698828220367432,5.5999999,5.698828220367432,5.5999999C5.698828220367432,5.5999999,5.698828220367432,7.5999999,5.698828220367432,7.5999999C5.698828220367432,7.5999999,5.698828220367432,7.5999999,5.698828220367432,7.5999999ZM9.398828020367432,6.5999999C9.398828020367432,6.5999999,9.398828020367432,4.8,9.398828020367432,4.8C9.398828020367432,4.8,7.398828220367432,4.8,7.398828220367432,4.8C7.398828220367432,4.8,7.398828220367432,6.5999999,7.398828220367432,6.5999999C7.398828220367432,6.5999999,9.398828020367432,6.5999999,9.398828020367432,6.5999999C9.398828020367432,6.5999999,9.398828020367432,6.5999999,9.398828020367432,6.5999999ZM9.398828020367432,4.8C9.398828020367432,4.5878301,9.483118020367431,4.38434,9.633138220367432,4.2343098999999995C9.633138220367432,4.2343098999999995,8.218928320367432,2.82010102,8.218928320367432,2.82010102C7.6938281203674315,3.345202,7.398828220367432,4.05739,7.398828220367432,4.8C7.398828220367432,4.8,9.398828020367432,4.8,9.398828020367432,4.8C9.398828020367432,4.8,9.398828020367432,4.8,9.398828020367432,4.8ZM9.633138220367432,4.2343098999999995C9.783168320367432,4.08429,9.986658120367432,4,10.198828220367432,4C10.198828220367432,4,10.198828220367432,2,10.198828220367432,2C9.456218220367433,2,8.744028120367432,2.294999,8.218928320367432,2.82010102C8.218928320367432,2.82010102,9.633138220367432,4.2343098999999995,9.633138220367432,4.2343098999999995C9.633138220367432,4.2343098999999995,9.633138220367432,4.2343098999999995,9.633138220367432,4.2343098999999995ZM10.198828220367432,4C10.198828220367432,4,13.798828620367432,4,13.798828620367432,4C13.798828620367432,4,13.798828620367432,2,13.798828620367432,2C13.798828620367432,2,10.198828220367432,2,10.198828220367432,2C10.198828220367432,2,10.198828220367432,4,10.198828220367432,4C10.198828220367432,4,10.198828220367432,4,10.198828220367432,4ZM13.798828620367432,4C14.010998220367432,4,14.214488520367432,4.08429,14.364518620367432,4.2343098999999995C14.364518620367432,4.2343098999999995,15.778728220367432,2.82010102,15.778728220367432,2.82010102C15.253628220367432,2.294999,14.541438620367432,2,13.798828620367432,2C13.798828620367432,2,13.798828620367432,4,13.798828620367432,4C13.798828620367432,4,13.798828620367432,4,13.798828620367432,4ZM14.364518620367432,4.2343098999999995C14.514538320367432,4.38434,14.59882782036743,4.5878301,14.59882782036743,4.8C14.59882782036743,4.8,16.59882822036743,4.8,16.59882822036743,4.8C16.59882822036743,4.05739,16.303828220367432,3.345202,15.778728220367432,2.82010102C15.778728220367432,2.82010102,14.364518620367432,4.2343098999999995,14.364518620367432,4.2343098999999995C14.364518620367432,4.2343098999999995,14.364518620367432,4.2343098999999995,14.364518620367432,4.2343098999999995ZM14.59882782036743,4.8C14.59882782036743,4.8,14.59882782036743,6.5999999,14.59882782036743,6.5999999C14.59882782036743,6.5999999,16.59882822036743,6.5999999,16.59882822036743,6.5999999C16.59882822036743,6.5999999,16.59882822036743,4.8,16.59882822036743,4.8C16.59882822036743,4.8,14.59882782036743,4.8,14.59882782036743,4.8C14.59882782036743,4.8,14.59882782036743,4.8,14.59882782036743,4.8Z" fill="#94979E" fill-opacity="1"/><path d="M11.198828220367432,11.10009765625C11.198828220367432,10.54781266625,10.751113220367431,10.10009765625,10.198828220367432,10.10009765625C9.646543230367431,10.10009765625,9.198828220367432,10.54781266625,9.198828220367432,11.10009765625C9.198828220367432,11.10009765625,11.198828220367432,11.10009765625,11.198828220367432,11.10009765625C11.198828220367432,11.10009765625,11.198828220367432,11.10009765625,11.198828220367432,11.10009765625ZM9.198828220367432,16.50009775625C9.198828220367432,17.052377656250002,9.646543230367431,17.50009775625,10.198828220367432,17.50009775625C10.751113220367431,17.50009775625,11.198828220367432,17.052377656250002,11.198828220367432,16.50009775625C11.198828220367432,16.50009775625,9.198828220367432,16.50009775625,9.198828220367432,16.50009775625C9.198828220367432,16.50009775625,9.198828220367432,16.50009775625,9.198828220367432,16.50009775625ZM9.198828220367432,11.10009765625C9.198828220367432,11.10009765625,9.198828220367432,16.50009775625,9.198828220367432,16.50009775625C9.198828220367432,16.50009775625,11.198828220367432,16.50009775625,11.198828220367432,16.50009775625C11.198828220367432,16.50009775625,11.198828220367432,11.10009765625,11.198828220367432,11.10009765625C11.198828220367432,11.10009765625,9.198828220367432,11.10009765625,9.198828220367432,11.10009765625C9.198828220367432,11.10009765625,9.198828220367432,11.10009765625,9.198828220367432,11.10009765625Z" fill="#94979E" fill-opacity="1"/><path d="M14.800390720367432,11.10009765625C14.800390720367432,10.54781266625,14.352675720367431,10.10009765625,13.800390720367432,10.10009765625C13.248105730367431,10.10009765625,12.800390720367432,10.54781266625,12.800390720367432,11.10009765625C12.800390720367432,11.10009765625,14.800390720367432,11.10009765625,14.800390720367432,11.10009765625C14.800390720367432,11.10009765625,14.800390720367432,11.10009765625,14.800390720367432,11.10009765625ZM12.800390720367432,16.50009775625C12.800390720367432,17.052377656250002,13.248105730367431,17.50009775625,13.800390720367432,17.50009775625C14.352675720367431,17.50009775625,14.800390720367432,17.052377656250002,14.800390720367432,16.50009775625C14.800390720367432,16.50009775625,12.800390720367432,16.50009775625,12.800390720367432,16.50009775625C12.800390720367432,16.50009775625,12.800390720367432,16.50009775625,12.800390720367432,16.50009775625ZM12.800390720367432,11.10009765625C12.800390720367432,11.10009765625,12.800390720367432,16.50009775625,12.800390720367432,16.50009775625C12.800390720367432,16.50009775625,14.800390720367432,16.50009775625,14.800390720367432,16.50009775625C14.800390720367432,16.50009775625,14.800390720367432,11.10009765625,14.800390720367432,11.10009765625C14.800390720367432,11.10009765625,12.800390720367432,11.10009765625,12.800390720367432,11.10009765625C12.800390720367432,11.10009765625,12.800390720367432,11.10009765625,12.800390720367432,11.10009765625Z" fill="#94979E" fill-opacity="1"/></g></svg>
64
+ </span>
65
+ </div>
66
+ <div v-if="item.attachments && item.attachments.length" class="message-attachments">
67
+ <div
68
+ v-for="(file, fileIndex) in item.attachments"
69
+ :key="fileIndex"
70
+ :class="['attachment-item', { 'is-image': file.isImage }]"
71
+ >
72
+ <div v-if="file.isImage" class="image-preview" @click="previewImage(file)">
73
+ <img :src="file.url" :alt="file.name" />
74
+ <span class="image-name">{{ file.name }}</span>
75
+ </div>
76
+ <div v-else class="file-item">
77
+ <a-icon type="file" class="file-icon" />
78
+ <span class="file-name">{{ file.name }}</span>
79
+ </div>
80
+ <a-button
81
+ type="primary"
82
+ shape="circle"
83
+ size="small"
84
+ class="remove-btn"
85
+ @click.stop="removeAttachment(item, fileIndex)"
86
+ >
87
+ <a-icon type="close" />
88
+ </a-button>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ <span v-if="isAiStreaming && index === displayItems.length - 1 && item.type === 'ai'" class="typing-cursor">▍</span>
93
+ </div>
94
+ </template>
95
+ </div>
96
+ </div>
97
+
98
+ <div class="bottom-input-wrapper">
99
+ <div class="input-container">
100
+ <!-- 文件预览区域 - 仅当有附件时显示 -->
101
+ <div v-if="pendingAttachments.length" class="attachment-preview-area">
102
+ <div
103
+ v-for="(file, index) in pendingAttachments"
104
+ :key="index"
105
+ :class="['preview-item', { 'is-image': file.isImage }]"
106
+ >
107
+ <div v-if="file.isImage" class="preview-image">
108
+ <img :src="file.url" :alt="file.name" />
109
+ </div>
110
+ <div v-else class="preview-file">
111
+ <a-icon type="file" />
112
+ <span class="preview-file-name">{{ file.name }}</span>
113
+ </div>
114
+ <a-button
115
+ type="primary"
116
+ shape="circle"
117
+ size="small"
118
+ class="preview-remove-btn"
119
+ @click="removePendingAttachment(index)"
120
+ >
121
+ <a-icon type="close" />
122
+ </a-button>
123
+ </div>
124
+ <div class="add-upload-item" @click="triggerUpload">
125
+ <span class="add-upload-icon">+</span>
126
+ </div>
127
+ </div>
128
+
129
+ <div class="input-textarea-area">
130
+ <a-textarea
131
+ ref="consultTextarea"
132
+ v-model="doctorInputText"
133
+ placeholder="医生补充信息或提问..."
134
+ class="bottom-input"
135
+ :rows="1"
136
+ resize="none"
137
+ @input="handleInput"
138
+ @keydown="handleKeydown"
139
+ ></a-textarea>
140
+ </div>
141
+
142
+ <input
143
+ ref="uploadInput"
144
+ type="file"
145
+ style="display: none"
146
+ @change="handleFileChange"
147
+ multiple
148
+ accept="image/*,.pdf,.doc,.docx"
149
+ />
150
+
151
+ <div class="input-controls">
152
+ <div class="input-controls-left">
153
+ <a-button class="upload-btn" @click="triggerUpload">
154
+ <a-icon type="plus" class="upload-icon" />
155
+ <span class="upload-text">上传(报告、图片)</span>
156
+ </a-button>
157
+ </div>
158
+
159
+ <div class="input-controls-right">
160
+ <span class="enter-tip">Enter</span>
161
+ <a-button
162
+ type="primary"
163
+ shape="circle"
164
+ class="send-btn"
165
+ @click="handleSendMessage"
166
+ :disabled="!doctorInputText.trim() && !pendingAttachments.length"
167
+ >
168
+ <span class="send-icon">↑</span>
169
+ </a-button>
170
+ </div>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ </div>
175
+
176
+ <!-- 图片预览Modal -->
177
+ <a-modal :visible="previewVisible" :footer="null" @cancel="previewVisible = false" width="800px">
178
+ <img :src="previewImageUrl" alt="预览图片" style="width: 100%" />
179
+ </a-modal>
180
+ </div>
181
+ </div>
182
+ </template>
183
+
184
+ <script>
185
+ import { startEventStreamPOST } from '@vue2-client/services/api/restTools'
186
+ import { marked } from 'marked'
187
+ import moment from 'moment/moment'
188
+ import { mapState } from 'vuex'
189
+
190
+ export default {
191
+ name: 'AIConsultation',
192
+ data() {
193
+ return {
194
+ currentDialogId: null,
195
+ doctorInputText: '',
196
+ isPlaying: false,
197
+ isRecording: false,
198
+ patientComplaint: '',
199
+ doctorQuestions: [],
200
+ examinationOrder: null,
201
+ aiDiagnosis: null,
202
+ dialogMessages: [],
203
+ pendingAttachments: [],
204
+ currentStreamConnection: null,
205
+ isAiStreaming: false,
206
+ resizeTimeout: null,
207
+ isTestMode: true, // 测试模式开关,测试完成后改为 false 走真实接口
208
+ previewVisible: false,
209
+ previewImageUrl: '',
210
+ activeNavIndex: -1
211
+ }
212
+ },
213
+ computed: {
214
+ ...mapState('account', {currUser: 'user'}),
215
+ // 导航消息列表:仅包含用户消息
216
+ navMessages() {
217
+ return this.displayItems
218
+ .map((item, index) => ({ type: item.type, index, content: item.content || '' }))
219
+ .filter(item => item.type === 'user')
220
+ },
221
+ // dialogMessages 与日期分隔符合并成最终渲染列表
222
+ displayItems() {
223
+ const items = []
224
+ let lastDateKey = ''
225
+ this.dialogMessages.forEach(msg => {
226
+ const dateKey = this.getDateKey(msg.timestamp)
227
+ if (dateKey && dateKey !== lastDateKey) {
228
+ items.push({ type: 'divider', text: this.getDateLabel(msg.timestamp) })
229
+ lastDateKey = dateKey
230
+ }
231
+ items.push(msg)
232
+ })
233
+ return items
234
+ }
235
+ },
236
+ mounted() {
237
+ this.$nextTick(() => {
238
+ this.autoResizeTextarea()
239
+ })
240
+ },
241
+ beforeDestroy() {
242
+ // 组件销毁时关闭流式连接
243
+ if (this.currentStreamConnection) {
244
+ this.currentStreamConnection()
245
+ this.currentStreamConnection = null
246
+ }
247
+ if (this.resizeTimeout) {
248
+ clearTimeout(this.resizeTimeout)
249
+ }
250
+ },
251
+ methods: {
252
+ copyMessage(item) {
253
+ // 复制消息内容
254
+ const text = item.content || ''
255
+ navigator.clipboard.writeText(text).then(() => {
256
+ this.$message.success('已复制')
257
+ }).catch(() => {
258
+ this.$message.error('复制失败')
259
+ })
260
+ },
261
+
262
+ editMessage(item) {
263
+ // 修改消息 - 将消息内容填充到输入框
264
+ this.doctorInputText = item.content || ''
265
+ },
266
+
267
+ favoriteMessage(item) {
268
+ // 收藏消息
269
+ this.$message.success('已收藏')
270
+ },
271
+
272
+ deleteMessage(item) {
273
+ // 删除消息
274
+ const index = this.dialogMessages.indexOf(item)
275
+ if (index > -1) {
276
+ this.dialogMessages.splice(index, 1)
277
+ }
278
+ },
279
+
280
+ regenerateAiResponse(item) {
281
+ // 重新生成AI回复
282
+ this.$message.info('重新生成中...')
283
+ },
284
+
285
+ autoResizeTextarea() {
286
+ this.$nextTick(() => {
287
+ const textarea = this.$refs.consultTextarea?.$el || this.$refs.consultTextarea
288
+ if (!textarea) return
289
+
290
+ textarea.style.height = 'auto'
291
+ const scrollHeight = textarea.scrollHeight
292
+ textarea.style.height = `${Math.min(Math.max(scrollHeight, 120), 250)}px`
293
+ })
294
+ },
295
+
296
+ handleInput() {
297
+ if (this.resizeTimeout) clearTimeout(this.resizeTimeout)
298
+ this.resizeTimeout = setTimeout(() => {
299
+ this.autoResizeTextarea()
300
+ }, 16)
301
+ },
302
+
303
+ renderMd(text) {
304
+ if (!text) return ''
305
+ try {
306
+ return marked.parse(text, { breaks: true, gfm: true, headerIds: false, mangle: false })
307
+ } catch {
308
+ return text
309
+ }
310
+ },
311
+
312
+ handleKeydown(event) {
313
+ if (event.key === 'Enter' && !event.shiftKey) {
314
+ event.preventDefault()
315
+ this.handleSendMessage()
316
+ }
317
+ },
318
+
319
+ initDialog() {
320
+ if (!this.currentDialogId) {
321
+ this.currentDialogId = moment().format('YYYYMMDDHHmmss')
322
+ }
323
+ },
324
+
325
+ clearDialog() {
326
+ this.currentDialogId = moment().format('YYYYMMDDHHmmss')
327
+ this.dialogMessages = []
328
+ },
329
+
330
+ handleSendMessage() {
331
+ if (!this.doctorInputText.trim() && !this.pendingAttachments.length) return
332
+
333
+ // 确保有dialogId
334
+ if (!this.currentDialogId) {
335
+ this.initDialog()
336
+ }
337
+
338
+ const messageContent = this.doctorInputText.trim()
339
+ const attachments = [...this.pendingAttachments]
340
+ const doctorMessage = {
341
+ type: 'user',
342
+ content: messageContent,
343
+ time: new Date().toLocaleTimeString(),
344
+ timestamp: Date.now(),
345
+ attachments: attachments
346
+ }
347
+ this.dialogMessages.push(doctorMessage)
348
+ this.scrollToBottom()
349
+
350
+ this.doctorInputText = ''
351
+ this.pendingAttachments = []
352
+ this.autoResizeTextarea()
353
+
354
+ const chatId = this.currentDialogId
355
+ let aiContent = ''
356
+ const aiMsgIndex = this.dialogMessages.length
357
+ this.dialogMessages.push({
358
+ type: 'ai',
359
+ content: '',
360
+ time: new Date().toLocaleTimeString(),
361
+ timestamp: Date.now()
362
+ })
363
+ this.scrollToBottom()
364
+
365
+ this.isAiStreaming = true
366
+
367
+ // ==================== 测试模式 ====================
368
+ if (this.isTestMode) {
369
+ const allAiMessages = [
370
+ '**初步分析:**\n\n1. 患者老年男性,有高血压病史,症状提示可能存在 **冠心病、心律失常** 或 **心力衰竭**\n2. 建议完善以下检查:\n - 心电图(ECG)\n - 心脏彩超\n - 动态心电图(Holter)\n - 血脂、血糖、BNP\n\n3. 注意鉴别:\n - 甲状腺功能异常\n - 电解质紊乱\n - 药物影响',
371
+ '**进一步分析:**\n\n根据检查结果:\n- ST段压低、T波倒置:考虑 **心肌缺血**\n- 左室舒张功能减退:提示 **舒张性心衰(HFrEF 临界)**\n- EF 55% 处于正常下限\n\n**建议:**\n1. 加用 **阿司匹林** 抗血小板治疗\n2. 加用 **他汀类** 调脂稳斑\n3. 考虑 **ACEI/ARB** 控制血压、逆转心肌重构\n4. 必要时行 **冠脉造影** 明确冠脉病变\n5. 密切监测血压、心率',
372
+ '**冠脉病变评估:**\n\n- **LAD 中段 70% 狭窄**:临界病变,建议 PCI 干预\n- **LCX 远端 40% 狭窄**:轻度,可药物保守治疗\n\n**治疗方案:**\n1. **LAD 行 PCI + 支架植入**\n2. 术后双联抗血小板治疗(阿司匹林 + 氯吡格雷)至少 12 个月\n3. 强化他汀治疗至 LDL < 1.4 mmol/L\n4. 控制血压 < 130/80 mmHg\n5. 心肺康复、规律运动',
373
+ '**综合评估:**\n\n1. 患者 PCI 术后恢复良好,胸闷症状明显改善\n2. 心电图未见明显 ST-T 改变,提示心肌灌注改善\n3. 建议继续当前治疗方案,定期随访\n\n**出院建议:**\n1. 规律服药:阿司匹林 + 氯吡格雷 + 他汀 + ACEI\n2. 1 个月后复查心电图、血脂、肝肾功能\n3. 3 个月后复查心脏彩超评估心功能\n4. 适度有氧运动,避免剧烈运动\n5. 低盐低脂饮食,控制体重'
374
+ ]
375
+ const fullText = allAiMessages[Math.floor(Math.random() * allAiMessages.length)]
376
+ this.simulateTyping(aiMsgIndex, fullText)
377
+ return
378
+ }
379
+
380
+ // ==================== 真实接口 ====================
381
+ this.currentStreamConnection = startEventStreamPOST(
382
+ '/his-web/api/af-his/ai/chat/stream',
383
+ { userMessage: messageContent, chatId, model: '', prompt: '', useContext: true, user: this.currUser.operInfo },
384
+ {'Content-Type': 'application/json'},
385
+ (data, type) => {
386
+ if (type === 'additionalInfo' || type === 'sourceInfo') return
387
+
388
+ let textChunk = ''
389
+ if (typeof data === 'object' && data !== null) {
390
+ const choices = data.choices
391
+ if (Array.isArray(choices) && choices.length > 0) {
392
+ const delta = choices[0].delta
393
+
394
+ // 优先取 delta.content(标准 OpenAI 格式)
395
+ if (delta && typeof delta.content === 'string' && delta.content) {
396
+ textChunk = delta.content
397
+ }
398
+
399
+ // 兼容百川模型的 thinking 字段
400
+ if (!textChunk && delta && delta.thinking) {
401
+ const thinking = delta.thinking
402
+ if (thinking.summary && typeof thinking.summary === 'string') {
403
+ textChunk = `[思考中] ${thinking.summary}`
404
+ }
405
+ if (Array.isArray(thinking.steps)) {
406
+ const activeStep = thinking.steps.find(s => s.status === 'in_progress')
407
+ if (activeStep && activeStep.label) {
408
+ textChunk = `[思考中] ${activeStep.label}`
409
+ }
410
+ }
411
+ }
412
+
413
+ // 检测模型拒答
414
+ const finishReason = choices[0].finish_reason
415
+ if (finishReason === 'refuse_answer') {
416
+ const refuseTip = '\n\n> ⚠️ 很抱歉,当前问题我无法回答,请尝试调整提问方式或联系管理员。'
417
+ if (!this.dialogMessages[aiMsgIndex].content.includes('无法回答')) {
418
+ this.dialogMessages[aiMsgIndex].content += refuseTip
419
+ this.isAiStreaming = false
420
+ this.scrollToBottom()
421
+ }
422
+ }
423
+ }
424
+ } else if (typeof data === 'string') {
425
+ textChunk = data
426
+ }
427
+
428
+ if (textChunk) {
429
+ aiContent += textChunk
430
+ this.dialogMessages[aiMsgIndex].content = aiContent
431
+ this.scrollToBottom()
432
+ }
433
+ },
434
+ (error) => {
435
+ this.isAiStreaming = false
436
+ this.dialogMessages[aiMsgIndex].content += `\n\n[错误: ${error.message || '请求失败'}]`
437
+ this.scrollToBottom()
438
+ },
439
+ () => {
440
+ this.isAiStreaming = false
441
+ this.scrollToBottom()
442
+ }
443
+ )
444
+ },
445
+
446
+ simulateTyping(aiMsgIndex, fullText) {
447
+ let i = 0
448
+ const step = () => {
449
+ if (i < fullText.length) {
450
+ i += 3
451
+ this.dialogMessages[aiMsgIndex].content = fullText.slice(0, i)
452
+ this.scrollToBottom()
453
+ setTimeout(step, 20)
454
+ } else {
455
+ this.dialogMessages[aiMsgIndex].content = fullText
456
+ this.isAiStreaming = false
457
+ this.scrollToBottom()
458
+ }
459
+ }
460
+ setTimeout(step, 150)
461
+ },
462
+
463
+ setPatientComplaint(complaint) {
464
+ this.patientComplaint = complaint
465
+ },
466
+
467
+ scrollToBottom(delay = 0) {
468
+ this.$nextTick(() => {
469
+ setTimeout(() => {
470
+ const chatArea = document.querySelector('.chat-area')
471
+ if (chatArea) {
472
+ chatArea.scrollTop = chatArea.scrollHeight
473
+ }
474
+ }, delay)
475
+ })
476
+ },
477
+
478
+ scrollToMessage(displayIndex) {
479
+ this.$nextTick(() => {
480
+ const messages = document.querySelectorAll('.dialog-area > div')
481
+ const target = messages[displayIndex]
482
+ if (target) {
483
+ target.scrollIntoView({ behavior: 'smooth', block: 'center' })
484
+ }
485
+ })
486
+ },
487
+
488
+ reset() {
489
+ if (this.currentStreamConnection) {
490
+ this.currentStreamConnection()
491
+ this.currentStreamConnection = null
492
+ }
493
+ this.isAiStreaming = false
494
+ this.patientComplaint = ''
495
+ this.doctorQuestions = []
496
+ this.examinationOrder = null
497
+ this.aiDiagnosis = null
498
+ this.doctorInputText = ''
499
+ this.isPlaying = false
500
+ this.isRecording = false
501
+ this.dialogMessages = []
502
+ this.pendingAttachments.forEach(file => {
503
+ if (file.url) {
504
+ URL.revokeObjectURL(file.url)
505
+ }
506
+ })
507
+ this.pendingAttachments = []
508
+ this.$nextTick(() => {
509
+ this.autoResizeTextarea()
510
+ const chatArea = document.querySelector('.chat-area')
511
+ if (chatArea) {
512
+ chatArea.scrollTop = 0
513
+ }
514
+ })
515
+ },
516
+
517
+ triggerUpload() {
518
+ this.$refs.uploadInput.click()
519
+ },
520
+
521
+ handleFileChange(event) {
522
+ const files = Array.from(event.target.files || [])
523
+ if (!files.length) return
524
+
525
+ const attachments = files.map(file => {
526
+ const isImage = file.type.startsWith('image/')
527
+ return {
528
+ name: file.name,
529
+ size: file.size,
530
+ type: file.type,
531
+ isImage,
532
+ url: isImage ? URL.createObjectURL(file) : '',
533
+ rawFile: file
534
+ }
535
+ })
536
+
537
+ this.pendingAttachments = [...this.pendingAttachments, ...attachments]
538
+ event.target.value = ''
539
+ },
540
+
541
+ removePendingAttachment(index) {
542
+ const file = this.pendingAttachments[index]
543
+ if (file && file.url) {
544
+ URL.revokeObjectURL(file.url)
545
+ }
546
+ this.pendingAttachments.splice(index, 1)
547
+ },
548
+
549
+ removeAttachment(message, fileIndex) {
550
+ const file = message.attachments[fileIndex]
551
+ if (file && file.url) {
552
+ URL.revokeObjectURL(file.url)
553
+ }
554
+ message.attachments.splice(fileIndex, 1)
555
+ },
556
+
557
+ previewImage(file) {
558
+ if (file.url) {
559
+ this.previewImageUrl = file.url
560
+ this.previewVisible = true
561
+ }
562
+ },
563
+
564
+ // 初始化测试数据:两天内容(昨天 + 今天),不调用接口
565
+ // 获取时间戳的日期键(YYYY-MM-DD)
566
+ getDateKey(timestamp) {
567
+ if (!timestamp) return ''
568
+ return moment(timestamp).format('YYYY-MM-DD')
569
+ },
570
+
571
+ // 解析日期键为本地日期对象
572
+ parseDateKey(dateKey) {
573
+ return moment(dateKey, 'YYYY-MM-DD')
574
+ },
575
+
576
+ // 把日期戳格式化为"今天 / 昨天 / 具体日期"
577
+ getDateLabel(timestamp) {
578
+ if (!timestamp) return ''
579
+ const m = moment(timestamp)
580
+ const today = moment().startOf('day')
581
+ const yesterday = today.clone().subtract(1, 'day')
582
+ const target = m.clone().startOf('day')
583
+
584
+ if (target.isSame(today, 'day')) return '今天'
585
+ if (target.isSame(yesterday, 'day')) return '昨天'
586
+ // 跨年显示年份
587
+ if (target.year() !== today.year()) {
588
+ return m.format('YYYY年M月D日')
589
+ }
590
+ return m.format('M月D日')
591
+ }
592
+ }
593
+ }
594
+ </script>
595
+
596
+ <style scoped>
597
+ .ai-consultation-outer {
598
+ box-sizing: border-box;
599
+ margin: 0;
600
+ padding: 0;
601
+ width: 100%;
602
+ height: 100%;
603
+ }
604
+
605
+ .ai-consultation-container {
606
+ width: 100%;
607
+ height: 100%;
608
+ display: flex;
609
+ flex-direction: column;
610
+ background: #FFFFFF;
611
+ border: 1px solid #E5E9F0;
612
+ }
613
+
614
+ .chat-area-wrapper {
615
+ position: relative;
616
+ flex: 1 1 auto;
617
+ min-height: 0;
618
+ }
619
+
620
+ .chat-area {
621
+ flex: 0 1 auto;
622
+ overflow-y: auto;
623
+ padding: 16px;
624
+ width: 100%;
625
+ padding-left: 172px;
626
+ padding-right: 178px;
627
+ background: #fff;
628
+ /* 初始高度:没有内容时也保留这块区域 */
629
+ min-height: 620px;
630
+ /* 最大高度:内容超过则出现滚动条 */
631
+ max-height: 620px;
632
+ box-sizing: border-box;
633
+ }
634
+
635
+ /* 消息导航条 */
636
+ .message-nav {
637
+ position: absolute;
638
+ top: 50%;
639
+ right: 16px;
640
+ transform: translateY(-50%);
641
+ display: flex;
642
+ flex-direction: column;
643
+ align-items: center;
644
+ gap: 8px;
645
+ z-index: 10;
646
+ }
647
+
648
+ .nav-dot {
649
+ width: 8px;
650
+ height: 8px;
651
+ border-radius: 6px;
652
+ opacity: 1;
653
+ background: #3362DA;
654
+ cursor: pointer;
655
+ transition: transform 0.2s;
656
+ }
657
+
658
+ .nav-dot:hover {
659
+ transform: scale(1.2);
660
+ }
661
+
662
+ .nav-dot.active {
663
+ background: #3362DA;
664
+ transform: scale(1.3);
665
+ }
666
+
667
+ /* 消息列表:跟随 chat-area 高度 */
668
+ .dialog-area {
669
+ display: flex;
670
+ flex-direction: column;
671
+ min-height: 208px; /* 240(chat-area) - 16*2(padding) = 208 */
672
+ }
673
+
674
+ /* 日期分隔符 */
675
+ .dialog-divider {
676
+ display: flex;
677
+ align-items: center;
678
+ justify-content: center;
679
+ margin: 8px 0 16px;
680
+ }
681
+
682
+ .dialog-divider::before,
683
+ .dialog-divider::after {
684
+ content: '';
685
+ flex: 1;
686
+ height: 1px;
687
+ background: #E5E9F0;
688
+ }
689
+
690
+ .dialog-divider-text {
691
+ padding: 2px 12px;
692
+ font-size: 12px;
693
+ color: #8C8C8C;
694
+ background: #F5F7FA;
695
+ border-radius: 10px;
696
+ margin: 0 12px;
697
+ white-space: nowrap;
698
+ }
699
+
700
+ /* 底部输入框区域 */
701
+ .bottom-input-wrapper {
702
+ flex-shrink: 0;
703
+ padding: 12px 16px;
704
+ background: #fff;
705
+ }
706
+
707
+ .input-container {
708
+ width: 782px;
709
+ margin: 0 auto;
710
+ padding: 12px;
711
+ display: flex;
712
+ flex-direction: column;
713
+ border: 1px solid #E5E9F0;
714
+ border-radius: 6px;
715
+ background: #FFFFFF;
716
+ box-sizing: border-box;
717
+ }
718
+
719
+ .input-textarea-area {
720
+ flex: 1 1 auto;
721
+ min-height: 0;
722
+ margin-bottom: 8px;
723
+ }
724
+
725
+ .bottom-input {
726
+ width: 100%;
727
+ height: 100%;
728
+ border: none !important;
729
+ background: transparent;
730
+ padding: 0;
731
+ font-family: 'Source Han Sans', 'Microsoft YaHei', sans-serif;
732
+ font-size: 16px;
733
+ color: #313131;
734
+ resize: none;
735
+ outline: none;
736
+ box-shadow: none !important;
737
+ }
738
+
739
+ .bottom-input:focus,
740
+ .bottom-input:hover {
741
+ border: none !important;
742
+ box-shadow: none !important;
743
+ }
744
+
745
+ .bottom-input::placeholder {
746
+ color: #999;
747
+ }
748
+
749
+ .input-controls {
750
+ flex-shrink: 0;
751
+ display: flex;
752
+ align-items: center;
753
+ justify-content: space-between;
754
+ padding-top: 0;
755
+ border-top: none;
756
+ }
757
+
758
+ .input-controls-left {
759
+ display: flex;
760
+ align-items: center;
761
+ gap: 8px;
762
+ }
763
+
764
+ .input-controls-right {
765
+ display: flex;
766
+ align-items: center;
767
+ gap: 8px;
768
+ }
769
+
770
+ .enter-tip {
771
+ font-family: 'Inter', sans-serif;
772
+ font-size: 14px;
773
+ font-weight: 500;
774
+ color: #9E9E9E;
775
+ padding: 4px 8px;
776
+ }
777
+
778
+ .send-btn {
779
+ width: 30px;
780
+ height: 30px;
781
+ background: #0057FE;
782
+ border: none;
783
+ border-radius: 50%;
784
+ color: #fff;
785
+ font-size: 14px;
786
+ cursor: pointer;
787
+ display: flex;
788
+ align-items: center;
789
+ justify-content: center;
790
+ padding: 0;
791
+ }
792
+
793
+ .send-btn:hover {
794
+ background: #0040cc;
795
+ }
796
+
797
+ .send-icon {
798
+ font-size: 14px;
799
+ font-weight: bold;
800
+ }
801
+
802
+ /* 文件预览区域 */
803
+ .attachment-preview-area {
804
+ display: flex;
805
+ flex-wrap: wrap;
806
+ gap: 12px;
807
+ margin-bottom: 12px;
808
+ }
809
+
810
+ .preview-item {
811
+ position: relative;
812
+ width: 100px;
813
+ height: 100px;
814
+ border: 1px solid #E5E9F0;
815
+ border-radius: 6px;
816
+ opacity: 1;
817
+ background: #fafafa;
818
+ box-sizing: border-box;
819
+ }
820
+
821
+ .preview-item:hover {
822
+ border-color: #0057FE;
823
+ }
824
+
825
+ .preview-image {
826
+ width: 100%;
827
+ height: 100%;
828
+ position: relative;
829
+ }
830
+
831
+ .preview-image img {
832
+ width: 100%;
833
+ height: 100%;
834
+ object-fit: cover;
835
+ }
836
+
837
+ .preview-remove-btn {
838
+ position: absolute;
839
+ top: -10px;
840
+ right: -10px;
841
+ width: 20px;
842
+ height: 20px;
843
+ padding: 0;
844
+ font-size: 12px;
845
+ background: #E5E9F0;
846
+ border: 1px solid #5D5C5C;
847
+ border-radius: 50%;
848
+ color: #5D5C5C;
849
+ opacity: 1;
850
+ display: flex;
851
+ align-items: center;
852
+ justify-content: center;
853
+ line-height: 1;
854
+ z-index: 2;
855
+ }
856
+
857
+ .preview-remove-btn:hover,
858
+ .preview-remove-btn:active {
859
+ background: #0057FE;
860
+ border-color: #0057FE;
861
+ color: #fff;
862
+ }
863
+
864
+ .preview-file {
865
+ width: 100%;
866
+ height: 100%;
867
+ display: flex;
868
+ flex-direction: column;
869
+ align-items: center;
870
+ justify-content: center;
871
+ padding: 8px;
872
+ box-sizing: border-box;
873
+ }
874
+
875
+ .add-upload-item {
876
+ width: 100px;
877
+ height: 100px;
878
+ border-radius: 6px;
879
+ opacity: 1;
880
+ box-sizing: border-box;
881
+ border: 1px solid #E5E9F0;
882
+ display: flex;
883
+ align-items: center;
884
+ justify-content: center;
885
+ cursor: pointer;
886
+ background: #fafafa;
887
+ }
888
+
889
+ .add-upload-icon {
890
+ height: 39px;
891
+ opacity: 1;
892
+ font-family: Source Han Sans;
893
+ font-size: 36px;
894
+ font-weight: normal;
895
+ line-height: 39px;
896
+ text-align: right;
897
+ letter-spacing: 0em;
898
+ font-feature-settings: "kern" on;
899
+ color: #9E9E9E;
900
+ transition: color 0.2s;
901
+ }
902
+
903
+ .add-upload-item:hover {
904
+ background: #F4F4F4;
905
+ }
906
+
907
+ .add-upload-item:active {
908
+ background: #0057FE;
909
+ }
910
+
911
+ .add-upload-item:active .add-upload-icon {
912
+ color: #FFFFFF;
913
+ }
914
+
915
+ .preview-file .anticon {
916
+ font-size: 24px;
917
+ color: #0057FE;
918
+ margin-bottom: 4px;
919
+ }
920
+
921
+ .preview-file-name {
922
+ font-size: 11px;
923
+ color: #666;
924
+ text-align: center;
925
+ word-break: break-all;
926
+ line-height: 1.2;
927
+ max-height: 32px;
928
+ overflow: hidden;
929
+ text-overflow: ellipsis;
930
+ display: -webkit-box;
931
+ -webkit-line-clamp: 2;
932
+ -webkit-box-orient: vertical;
933
+ line-clamp: 2;
934
+ }
935
+
936
+ .preview-file .preview-remove-btn {
937
+ position: absolute;
938
+ top: 50%;
939
+ right: 50%;
940
+ transform: translate(50%, -50%);
941
+ }
942
+
943
+ /* 消息中的附件样式 */
944
+ .message-attachments {
945
+ margin-top: 8px;
946
+ display: flex;
947
+ flex-wrap: wrap;
948
+ gap: 12px;
949
+ }
950
+
951
+ .attachment-item {
952
+ position: relative;
953
+ width: 100px;
954
+ height: 100px;
955
+ border: 1px solid #E5E9F0;
956
+ border-radius: 6px;
957
+ opacity: 1;
958
+ overflow: visible;
959
+ background: #fafafa;
960
+ box-sizing: border-box;
961
+ }
962
+
963
+ .attachment-item:hover {
964
+ border-color: #0057FE;
965
+ }
966
+
967
+ .image-preview {
968
+ width: 100%;
969
+ height: 100%;
970
+ position: relative;
971
+ cursor: pointer;
972
+ }
973
+
974
+ .image-preview img {
975
+ width: 100%;
976
+ height: 100%;
977
+ object-fit: cover;
978
+ }
979
+
980
+ .image-name {
981
+ position: absolute;
982
+ bottom: 0;
983
+ left: 0;
984
+ right: 0;
985
+ padding: 4px;
986
+ background: rgba(0, 0, 0, 0.5);
987
+ color: #fff;
988
+ font-size: 11px;
989
+ text-align: center;
990
+ white-space: nowrap;
991
+ overflow: hidden;
992
+ text-overflow: ellipsis;
993
+ }
994
+
995
+ .remove-btn {
996
+ position: absolute;
997
+ top: 50%;
998
+ right: 50%;
999
+ width: 20px;
1000
+ height: 20px;
1001
+ padding: 0;
1002
+ font-size: 12px;
1003
+ background: #E5E9F0;
1004
+ border: 1px solid #5D5C5C;
1005
+ border-radius: 50%;
1006
+ color: #5D5C5C;
1007
+ opacity: 1;
1008
+ display: flex;
1009
+ align-items: center;
1010
+ justify-content: center;
1011
+ line-height: 1;
1012
+ z-index: 2;
1013
+ transform: translate(50%, -50%);
1014
+ }
1015
+
1016
+ .remove-btn:hover,
1017
+ .remove-btn:active {
1018
+ background: #0057FE;
1019
+ border-color: #0057FE;
1020
+ color: #fff;
1021
+ }
1022
+
1023
+ .file-item {
1024
+ width: 100%;
1025
+ height: 100%;
1026
+ display: flex;
1027
+ flex-direction: column;
1028
+ align-items: center;
1029
+ justify-content: center;
1030
+ padding: 8px;
1031
+ box-sizing: border-box;
1032
+ }
1033
+
1034
+ .file-icon {
1035
+ font-size: 28px;
1036
+ color: #0057FE;
1037
+ margin-bottom: 4px;
1038
+ }
1039
+
1040
+ .file-name {
1041
+ font-size: 11px;
1042
+ color: #666;
1043
+ text-align: center;
1044
+ word-break: break-all;
1045
+ line-height: 1.2;
1046
+ max-height: 32px;
1047
+ overflow: hidden;
1048
+ text-overflow: ellipsis;
1049
+ display: -webkit-box;
1050
+ -webkit-line-clamp: 2;
1051
+ -webkit-box-orient: vertical;
1052
+ line-clamp: 2;
1053
+ }
1054
+
1055
+ .file-item .remove-btn {
1056
+ position: absolute;
1057
+ top: -10px;
1058
+ right: -10px;
1059
+ }
1060
+
1061
+ /* 对话区域样式 */
1062
+ .dialog-message {
1063
+ display: flex;
1064
+ margin-bottom: 16px;
1065
+ align-items: flex-start;
1066
+ }
1067
+
1068
+ .dialog-message:last-child {
1069
+ margin-bottom: 0;
1070
+ }
1071
+
1072
+ .dialog-message.ai {
1073
+ flex-direction: row;
1074
+ }
1075
+
1076
+ .dialog-message.user {
1077
+ flex-direction: row-reverse;
1078
+ }
1079
+
1080
+ .dialog-message.user .message-content {
1081
+ display: flex;
1082
+ flex-direction: column;
1083
+ align-items: flex-end;
1084
+ }
1085
+
1086
+ .dialog-message.user .message-bubble {
1087
+ height: 32px;
1088
+ border-radius: 6px;
1089
+ opacity: 1;
1090
+ background: #F4F4F4;
1091
+ display: flex;
1092
+ align-items: center;
1093
+ padding: 0 12px;
1094
+ box-sizing: border-box;
1095
+ max-width: 100%;
1096
+ }
1097
+
1098
+ .dialog-message.user .message-bubble .message-text {
1099
+ text-align: left;
1100
+ color: #313131;
1101
+ }
1102
+
1103
+ .dialog-message.ai .message-bubble {
1104
+ display: flex;
1105
+ align-items: flex-start;
1106
+ max-width: 100%;
1107
+ }
1108
+
1109
+ .dialog-message.ai .message-bubble .message-text {
1110
+ text-align: justify;
1111
+ color: #313131;
1112
+ }
1113
+
1114
+ .message-text {
1115
+ opacity: 1;
1116
+ font-family: Source Han Sans;
1117
+ font-size: 16px;
1118
+ font-weight: normal;
1119
+ line-height: 32px;
1120
+ letter-spacing: 0em;
1121
+ font-feature-settings: "kern" on;
1122
+ max-width: 100%;
1123
+ color: #313131;
1124
+ }
1125
+
1126
+ .message-actions {
1127
+ display: flex;
1128
+ align-items: center;
1129
+ gap: 8px;
1130
+ margin-top: 6px;
1131
+ opacity: 1;
1132
+ visibility: visible;
1133
+ transition: opacity 0.2s, visibility 0.2s;
1134
+ }
1135
+
1136
+ .dialog-message.ai .message-actions {
1137
+ opacity: 1;
1138
+ visibility: visible;
1139
+ }
1140
+
1141
+ .dialog-message.user .message-actions {
1142
+ opacity: 1;
1143
+ visibility: visible;
1144
+ }
1145
+
1146
+ .action-btn {
1147
+ width: 32px;
1148
+ height: 32px;
1149
+ display: flex;
1150
+ align-items: center;
1151
+ justify-content: center;
1152
+ cursor: pointer;
1153
+ border-radius: 6px;
1154
+ transition: background 0.2s;
1155
+ }
1156
+
1157
+ .action-btn:hover {
1158
+ background: #F0F0F0;
1159
+ }
1160
+
1161
+ .action-btn svg {
1162
+ display: block;
1163
+ }
1164
+
1165
+ .typing-cursor {
1166
+ display: inline-block;
1167
+ margin-left: 2px;
1168
+ color: #0057FE;
1169
+ font-size: 18px;
1170
+ animation: blink 1s step-end infinite;
1171
+ }
1172
+
1173
+ @keyframes blink {
1174
+ 0%, 100% { opacity: 1; }
1175
+ 50% { opacity: 0; }
1176
+ }
1177
+ </style>