vue2-client 1.22.5 → 1.22.7

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 (100) hide show
  1. package/.env.his +19 -19
  2. package/.history/.eslintrc_20260521171150.js +74 -0
  3. package/.history/.eslintrc_20260521171213.js +74 -0
  4. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154443.vue +726 -0
  5. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154700.vue +478 -0
  6. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175435.vue +706 -0
  7. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175450.vue +694 -0
  8. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260611152602.vue +755 -0
  9. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513145941.vue +524 -0
  10. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513153133.vue +731 -0
  11. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513160316.vue +525 -0
  12. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260601144150.vue +1046 -0
  13. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310142713.vue +512 -0
  14. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310145118.vue +511 -0
  15. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260311094834.vue +696 -0
  16. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260320143028.vue +693 -0
  17. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260409101450.vue +677 -0
  18. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164645.vue +758 -0
  19. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164714.vue +693 -0
  20. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508171651.vue +716 -0
  21. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509133717.vue +695 -0
  22. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509171115.vue +664 -0
  23. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140637.vue +1455 -0
  24. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140935.vue +1441 -0
  25. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513150818.vue +1441 -0
  26. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153119.vue +1442 -0
  27. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153126.vue +1486 -0
  28. package/.history/src/base-client/components/common/XForm/XFormItem_20260513140854.vue +1607 -0
  29. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140403.vue +643 -0
  30. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140829.vue +628 -0
  31. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519142824.vue +104 -0
  32. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519143155.vue +102 -0
  33. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171231.vue +1241 -0
  34. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171441.vue +1223 -0
  35. package/.history/src/base-client/components/his/HAi/HAi_20260612174826.vue +472 -0
  36. package/.history/src/base-client/components/his/HAi/HAi_20260612175839.vue +538 -0
  37. package/.history/src/base-client/components/his/HAi/HAi_20260615103331.vue +650 -0
  38. package/.history/src/base-client/components/his/XHDescriptions/XHDescriptions_20260424134504.vue +1469 -0
  39. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171133.vue +788 -0
  40. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171151.vue +780 -0
  41. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511170841.vue +585 -0
  42. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511171138.vue +787 -0
  43. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260512141830.vue +739 -0
  44. package/.history/src/components/STable/index_20260409155138.js +806 -0
  45. package/.history/src/components/STable/index_20260409155218.js +814 -0
  46. package/.history/src/expression/core/Expression_20260305164427.js +1371 -0
  47. package/.history/src/expression/core/Expression_20260305170258.js +1358 -0
  48. package/.history/src/expression/core/Program_20260305111830.js +944 -0
  49. package/.history/src/expression/core/Program_20260305112041.js +931 -0
  50. package/.history/src/logic/LogicRunner_20260304154306.js +170 -0
  51. package/.history/src/logic/LogicRunner_20260304155553.js +112 -0
  52. package/.history/src/logic/LogicRunner_20260305105834.js +112 -0
  53. package/.history/src/logic/LogicRunner_20260305112718.js +129 -0
  54. package/.history/src/logic/LogicRunner_20260305182436.js +133 -0
  55. package/.history/src/logic/LogicRunner_20260306151301.js +213 -0
  56. package/.history/src/logic/LogicRunner_20260306152419.js +213 -0
  57. package/.history/src/logic/plugins/common/DateTools_20260305154159.js +61 -0
  58. package/.history/src/logic/plugins/common/DateTools_20260305154217.js +44 -0
  59. package/.history/src/logic/plugins/common/DateTools_20260305161014.js +44 -0
  60. package/.history/src/logic/plugins/common/HttpTools_20260305164352.js +80 -0
  61. package/.history/src/logic/plugins/common/HttpTools_20260305170258.js +75 -0
  62. package/.history/src/logic/plugins/common/HttpTools_20260305171634.js +75 -0
  63. package/.history/src/logic/plugins/common/HttpTools_20260306152419.js +72 -0
  64. package/.history/src/services/api/restTools_20260427142149.js +245 -0
  65. package/.history/src/services/api/restTools_20260427142853.js +230 -0
  66. package/.history/src/services/api/restTools_20260519135558.js +230 -0
  67. package/.history/src/services/api/restTools_20260519140825.js +230 -0
  68. package/.history/src/services/api/restTools_20260519151223.js +230 -0
  69. package/.history/src/utils/indexedDB_20260306150918.js +593 -0
  70. package/.history/src/utils/indexedDB_20260306151301.js +586 -0
  71. package/.idea/codeStyles/Project.xml +62 -0
  72. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  73. package/.idea/misc.xml +5 -87
  74. package/package.json +1 -1
  75. package/preview-input-box.html +180 -0
  76. package/src/base-client/components/common/HIS/HForm/HForm.vue +1186 -1186
  77. package/src/base-client/components/common/XMarkdownViewer/demo.vue +102 -102
  78. package/src/base-client/components/his/HAi/HAi.vue +349 -141
  79. package/src/base-client/components/his/XList/XList.vue +130 -17
  80. package/src/base-client/components/his/XTransfer/index.md +327 -327
  81. package/src/pages/userInfoDetailManage/ApplySystemQuery/index.vue +18 -15
  82. package/src/pages/userInfoDetailManage/ArchiveMaintainQuery/index.vue +9 -23
  83. package/src/pages/userInfoDetailManage/CallSystemQuery/index.vue +9 -23
  84. package/src/pages/userInfoDetailManage/HandplanSystemQuery/index.vue +32 -18
  85. package/src/pages/userInfoDetailManage/RevenueSystemQuery/index.vue +18 -45
  86. package/src/pages/userInfoDetailManage/SafeCheckSystemQuery/index.vue +9 -23
  87. package/src/pages/userInfoDetailManage/WorkOrderSystemQuery/index.vue +9 -22
  88. package/src/pages/userInfoDetailManage/index.vue +14 -2
  89. package/src/pages/userInfoDetailManage/userInfoDetailQueryTabs.vue +289 -297
  90. package/.idea/.name +0 -1
  91. package/.idea/MarsCodeWorkspaceAppSettings.xml +0 -8
  92. package/.idea/deployment.xml +0 -14
  93. package/.idea/gradle.xml +0 -7
  94. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  95. package/.idea/libraries/contour_plot.xml +0 -9
  96. package/.idea/material_theme_project_new.xml +0 -18
  97. package/src/pages/userInfoDetailManage/ApplySystemQuery/applySystemConfig.js +0 -4
  98. package/src/pages/userInfoDetailManage/HandplanSystemQuery/handplanSystemConfig.js +0 -6
  99. package/src/pages/userInfoDetailManage/RevenueSystemQuery/revenueSystemConfig.js +0 -4
  100. package/src/pages/userInfoDetailManage/queryTabConfig.js +0 -353
@@ -0,0 +1,472 @@
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
+ <input
32
+ ref="uploadInput"
33
+ type="file"
34
+ style="display: none"
35
+ @change="handleFileChange"
36
+ multiple
37
+ accept="image/*,.pdf,.doc,.docx"
38
+ />
39
+
40
+ <div class="input-controls">
41
+ <div class="input-controls-left">
42
+ <a-button class="upload-btn" @click="triggerUpload">
43
+ <a-icon type="plus" class="upload-icon" />
44
+ <span class="upload-text">上传(报告、图片)</span>
45
+ </a-button>
46
+ </div>
47
+
48
+ <div class="input-controls-right">
49
+ <span class="enter-tip">Enter</span>
50
+ <a-button
51
+ type="primary"
52
+ shape="circle"
53
+ class="send-btn"
54
+ @click="handleSendMessage"
55
+ :disabled="!doctorInputText.trim()"
56
+ >
57
+ <span class="send-icon">↑</span>
58
+ </a-button>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </template>
66
+
67
+ <script>
68
+ import { startEventStreamPOST } from '@vue2-client/services/api/restTools'
69
+ import { marked } from 'marked'
70
+ import moment from 'moment/moment'
71
+ import { mapState } from 'vuex'
72
+
73
+ export default {
74
+ name: 'AIConsultation',
75
+ data() {
76
+ return {
77
+ currentDialogId: null,
78
+ doctorInputText: '',
79
+ isPlaying: false,
80
+ isRecording: false,
81
+ patientComplaint: '',
82
+ doctorQuestions: [],
83
+ examinationOrder: null,
84
+ aiDiagnosis: null,
85
+ dialogMessages: [],
86
+ currentStreamConnection: null,
87
+ isAiStreaming: false,
88
+ resizeTimeout: null
89
+ }
90
+ },
91
+ computed: {
92
+ ...mapState('account', {currUser: 'user'})
93
+ },
94
+ mounted() {
95
+ this.$nextTick(() => {
96
+ this.autoResizeTextarea()
97
+ })
98
+ },
99
+ beforeDestroy() {
100
+ // 组件销毁时关闭流式连接
101
+ if (this.currentStreamConnection) {
102
+ this.currentStreamConnection()
103
+ this.currentStreamConnection = null
104
+ }
105
+ if (this.resizeTimeout) {
106
+ clearTimeout(this.resizeTimeout)
107
+ }
108
+ },
109
+ methods: {
110
+ autoResizeTextarea() {
111
+ this.$nextTick(() => {
112
+ const textarea = this.$refs.consultTextarea?.$el || this.$refs.consultTextarea
113
+ if (!textarea) return
114
+
115
+ textarea.style.height = 'auto'
116
+ const scrollHeight = textarea.scrollHeight
117
+ textarea.style.height = `${Math.min(Math.max(scrollHeight, 120), 250)}px`
118
+ })
119
+ },
120
+
121
+ handleInput() {
122
+ if (this.resizeTimeout) clearTimeout(this.resizeTimeout)
123
+ this.resizeTimeout = setTimeout(() => {
124
+ this.autoResizeTextarea()
125
+ }, 16)
126
+ },
127
+
128
+ renderMd(text) {
129
+ if (!text) return ''
130
+ try {
131
+ return marked.parse(text, { breaks: true, gfm: true, headerIds: false, mangle: false })
132
+ } catch {
133
+ return text
134
+ }
135
+ },
136
+
137
+ handleKeydown(event) {
138
+ if (event.key === 'Enter' && !event.shiftKey) {
139
+ event.preventDefault()
140
+ this.handleSendMessage()
141
+ }
142
+ },
143
+
144
+ initDialog() {
145
+ if (!this.currentDialogId) {
146
+ this.currentDialogId = moment().format('YYYYMMDDHHmmss')
147
+ }
148
+ },
149
+
150
+ clearDialog() {
151
+ this.currentDialogId = moment().format('YYYYMMDDHHmmss')
152
+ this.dialogMessages = []
153
+ },
154
+
155
+ handleSendMessage() {
156
+ if (!this.doctorInputText.trim()) return
157
+
158
+ // 确保有dialogId
159
+ if (!this.currentDialogId) {
160
+ this.initDialog()
161
+ }
162
+
163
+ const messageContent = this.doctorInputText.trim()
164
+ const doctorMessage = {
165
+ type: 'user',
166
+ content: messageContent,
167
+ time: new Date().toLocaleTimeString(),
168
+ timestamp: Date.now()
169
+ }
170
+ this.dialogMessages.push(doctorMessage)
171
+ this.scrollToBottom()
172
+
173
+ this.doctorInputText = ''
174
+ this.autoResizeTextarea()
175
+
176
+ const chatId = this.currentDialogId
177
+ let aiContent = ''
178
+ const aiMsgIndex = this.dialogMessages.length
179
+ this.dialogMessages.push({
180
+ type: 'ai',
181
+ content: '',
182
+ time: new Date().toLocaleTimeString(),
183
+ timestamp: Date.now()
184
+ })
185
+ this.scrollToBottom()
186
+
187
+ this.isAiStreaming = true
188
+
189
+ this.currentStreamConnection = startEventStreamPOST(
190
+ '/his-web/api/af-his/ai/chat/stream',
191
+ { userMessage: messageContent, chatId, model: '', prompt: '', useContext: true, user: this.currUser.operInfo },
192
+ {'Content-Type': 'application/json'},
193
+ (data, type) => {
194
+ if (type === 'additionalInfo' || type === 'sourceInfo') return
195
+
196
+ let textChunk = ''
197
+ if (typeof data === 'object' && data !== null) {
198
+ const choices = data.choices
199
+ if (Array.isArray(choices) && choices.length > 0) {
200
+ const delta = choices[0].delta
201
+
202
+ // 优先取 delta.content(标准 OpenAI 格式)
203
+ if (delta && typeof delta.content === 'string' && delta.content) {
204
+ textChunk = delta.content
205
+ }
206
+
207
+ // 兼容百川模型的 thinking 字段
208
+ if (!textChunk && delta && delta.thinking) {
209
+ const thinking = delta.thinking
210
+ // 取 summary 描述
211
+ if (thinking.summary && typeof thinking.summary === 'string') {
212
+ textChunk = `[思考中] ${thinking.summary}`
213
+ }
214
+ // 取 reasoning steps
215
+ if (Array.isArray(thinking.steps)) {
216
+ const activeStep = thinking.steps.find(s => s.status === 'in_progress')
217
+ if (activeStep && activeStep.label) {
218
+ textChunk = `[思考中] ${activeStep.label}`
219
+ }
220
+ }
221
+ }
222
+
223
+ // 检测模型拒答
224
+ const finishReason = choices[0].finish_reason
225
+ if (finishReason === 'refuse_answer') {
226
+ const refuseTip = '\n\n> ⚠️ 很抱歉,当前问题我无法回答,请尝试调整提问方式或联系管理员。'
227
+ if (!this.dialogMessages[aiMsgIndex].content.includes('无法回答')) {
228
+ this.dialogMessages[aiMsgIndex].content += refuseTip
229
+ this.isAiStreaming = false
230
+ this.scrollToBottom()
231
+ }
232
+ }
233
+ }
234
+ } else if (typeof data === 'string') {
235
+ textChunk = data
236
+ }
237
+
238
+ if (textChunk) {
239
+ aiContent += textChunk
240
+ this.dialogMessages[aiMsgIndex].content = aiContent
241
+ this.scrollToBottom()
242
+ }
243
+ },
244
+ (error) => {
245
+ this.isAiStreaming = false
246
+ this.dialogMessages[aiMsgIndex].content += `\n\n[错误: ${error.message || '请求失败'}]`
247
+ this.scrollToBottom()
248
+ },
249
+ () => {
250
+ this.isAiStreaming = false
251
+ this.scrollToBottom()
252
+ }
253
+ )
254
+ },
255
+
256
+ setPatientComplaint(complaint) {
257
+ this.patientComplaint = complaint
258
+ },
259
+
260
+ scrollToBottom(delay = 0) {
261
+ this.$nextTick(() => {
262
+ setTimeout(() => {
263
+ const chatArea = document.querySelector('.chat-area')
264
+ if (chatArea) {
265
+ chatArea.scrollTop = chatArea.scrollHeight
266
+ }
267
+ }, delay)
268
+ })
269
+ },
270
+
271
+ reset() {
272
+ if (this.currentStreamConnection) {
273
+ this.currentStreamConnection()
274
+ this.currentStreamConnection = null
275
+ }
276
+ this.isAiStreaming = false
277
+ this.patientComplaint = ''
278
+ this.doctorQuestions = []
279
+ this.examinationOrder = null
280
+ this.aiDiagnosis = null
281
+ this.doctorInputText = ''
282
+ this.isPlaying = false
283
+ this.isRecording = false
284
+ this.dialogMessages = []
285
+ this.$nextTick(() => {
286
+ this.autoResizeTextarea()
287
+ const chatArea = document.querySelector('.chat-area')
288
+ if (chatArea) {
289
+ chatArea.scrollTop = 0
290
+ }
291
+ })
292
+ },
293
+
294
+ triggerUpload() {
295
+ this.$refs.uploadInput.click()
296
+ },
297
+
298
+ handleFileChange(event) {
299
+ const files = Array.from(event.target.files || [])
300
+ if (!files.length) return
301
+
302
+ this.dialogMessages.push({
303
+ type: 'user',
304
+ content: `已上传文件:${files.map(f => f.name).join('、')}`,
305
+ time: new Date().toLocaleTimeString(),
306
+ timestamp: Date.now()
307
+ })
308
+ this.scrollToBottom()
309
+ event.target.value = ''
310
+ }
311
+ }
312
+ }
313
+ </script>
314
+
315
+ <style scoped>
316
+ .ai-consultation-outer {
317
+ box-sizing: border-box;
318
+ margin: 0;
319
+ padding: 0;
320
+ width: 100%;
321
+ height: 860px;
322
+ }
323
+
324
+ .ai-consultation-container {
325
+ width: 100%;
326
+ height: 100%;
327
+ display: flex;
328
+ flex-direction: column;
329
+ background: #FFFFFF;
330
+ border: 1px solid #E5E9F0;
331
+ }
332
+
333
+ .chat-area {
334
+ flex: 1;
335
+ overflow-y: auto;
336
+ padding: 16px;
337
+ background: #fff;
338
+ min-height: 690px;
339
+ }
340
+
341
+ .dialog-area {
342
+ display: flex;
343
+ flex-direction: column;
344
+ }
345
+
346
+ /* 底部输入框区域 */
347
+ .bottom-input-wrapper {
348
+ flex-shrink: 0;
349
+ padding: 15px 11px 0 11px;
350
+ background: #fff;
351
+ }
352
+
353
+ .input-container {
354
+ width: 100%;
355
+ height: 249px;
356
+ margin: 0 auto;
357
+ display: flex;
358
+ flex-direction: column;
359
+ border: 1px solid #E5E9F0;
360
+ border-radius: 6px;
361
+ background: #FFFFFF;
362
+ box-sizing: border-box;
363
+ padding: 12px;
364
+ }
365
+
366
+ .bottom-input {
367
+ flex: 1 1 auto;
368
+ min-height: 0;
369
+ width: 100%;
370
+ border: none;
371
+ padding: 0;
372
+ font-family: 'Source Han Sans', 'Microsoft YaHei', sans-serif;
373
+ font-size: 16px;
374
+ color: #313131;
375
+ resize: none;
376
+ outline: none;
377
+ background: transparent;
378
+ }
379
+
380
+ .bottom-input::placeholder {
381
+ color: #999;
382
+ }
383
+
384
+ .input-controls {
385
+ flex-shrink: 0;
386
+ display: flex;
387
+ align-items: center;
388
+ justify-content: space-between;
389
+ padding: 8px 0;
390
+ }
391
+
392
+ .enter-tip {
393
+ font-family: 'Inter', sans-serif;
394
+ font-size: 14px;
395
+ font-weight: 500;
396
+ color: #9E9E9E;
397
+ padding: 4px 8px;
398
+ }
399
+
400
+ .send-btn {
401
+ width: 30px;
402
+ height: 30px;
403
+ background: #0057FE;
404
+ border: none;
405
+ border-radius: 50%;
406
+ color: #fff;
407
+ font-size: 14px;
408
+ cursor: pointer;
409
+ display: flex;
410
+ align-items: center;
411
+ justify-content: center;
412
+ padding: 0;
413
+ }
414
+
415
+ .send-btn:hover {
416
+ background: #0040cc;
417
+ }
418
+
419
+ .send-icon {
420
+ font-size: 14px;
421
+ font-weight: bold;
422
+ }
423
+
424
+ /* 对话区域样式 */
425
+ .dialog-message {
426
+ display: flex;
427
+ margin-bottom: 16px;
428
+ align-items: flex-start;
429
+ }
430
+
431
+ .dialog-message:last-child {
432
+ margin-bottom: 0;
433
+ }
434
+
435
+ .dialog-message.ai {
436
+ flex-direction: row;
437
+ }
438
+
439
+ .dialog-message.user {
440
+ flex-direction: row-reverse;
441
+ }
442
+
443
+ .dialog-message.user .message-text {
444
+ text-align: right;
445
+ }
446
+
447
+ .message-text {
448
+ opacity: 1;
449
+ font-family: Source Han Sans;
450
+ font-size: 16px;
451
+ font-weight: normal;
452
+ line-height: normal;
453
+ text-align: justify;
454
+ letter-spacing: 0em;
455
+ font-feature-settings: "kern" on;
456
+ max-width: 100%;
457
+ color: #313131;
458
+ }
459
+
460
+ .typing-cursor {
461
+ display: inline-block;
462
+ margin-left: 2px;
463
+ color: #0057FE;
464
+ font-size: 18px;
465
+ animation: blink 1s step-end infinite;
466
+ }
467
+
468
+ @keyframes blink {
469
+ 0%, 100% { opacity: 1; }
470
+ 50% { opacity: 0; }
471
+ }
472
+ </style>