vue2-client 1.22.32 → 1.22.33

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.
@@ -0,0 +1,155 @@
1
+ <template>
2
+ <div class="image-report-demo">
3
+ <a-row :gutter="16">
4
+ <a-col :span="18">
5
+ <a-card title="XHisEditor 图片报告演示" style="margin-bottom: 16px;">
6
+ <template #extra>
7
+ <a-space>
8
+ <a-button type="primary" @click="loadMedicalRecord">
9
+ 加载真实病历
10
+ </a-button>
11
+ <a-button @click="refreshEditor">
12
+ 刷新编辑器
13
+ </a-button>
14
+ </a-space>
15
+ </template>
16
+
17
+ <XHisEditor
18
+ ref="hisEditorRef"
19
+ :image-report-fields="imageReportFields"
20
+ :bind-object="editorBindObject"
21
+ :save-data-logic-name="saveDataLogicName"
22
+ :logic-extra-params="logicExtraParams"
23
+ :hide-editor-toolbar="false"
24
+ service-name="af-his"
25
+ :show-mode-choose="false"
26
+ mode-type="data"
27
+ @init="onEditorInit"
28
+ @saveafter="onSaveAfter"
29
+ />
30
+ </a-card>
31
+ </a-col>
32
+
33
+ <a-col :span="6">
34
+ <a-card title="说明" style="margin-bottom: 16px;">
35
+ <p>1. 点击“加载真实病历”后会调用 <code>getFileInformation</code>。</p>
36
+ <p>2. 接口返回的 <code>bindObject</code> 若带 <code>ctImages</code>,会自动渲染。</p>
37
+ <p>3. 保存逻辑为 <code>saveMedicalRecordFile</code>。</p>
38
+ </a-card>
39
+
40
+ <a-card title="当前文书信息" style="margin-bottom: 16px;">
41
+ <pre>{{ JSON.stringify(editorInfo, null, 2) }}</pre>
42
+ </a-card>
43
+
44
+ <a-card title="当前 bindObject">
45
+ <pre>{{ JSON.stringify(editorBindObject, null, 2) }}</pre>
46
+ </a-card>
47
+ </a-col>
48
+ </a-row>
49
+ </div>
50
+ </template>
51
+
52
+ <script>
53
+ import XHisEditor from '@vue2-client/base-client/components/his/XHisEditor/XHisEditor.vue'
54
+ import { runLogic } from '@vue2-client/services/api/common'
55
+
56
+ export default {
57
+ name: 'ImageReportDemo',
58
+ components: {
59
+ XHisEditor
60
+ },
61
+ data () {
62
+ return {
63
+ editorBindObject: {},
64
+ imageReportFields: ['ctImages'],
65
+ saveDataLogicName: 'saveMedicalRecordFile',
66
+ editorInfo: {
67
+ loaded: false,
68
+ fileId: null,
69
+ templateId: 670,
70
+ registrationNumber: 1
71
+ }
72
+ }
73
+ },
74
+ computed: {
75
+ logicExtraParams () {
76
+ const user = this.$store.state.account?.user || {}
77
+ return {
78
+ description: '保存需要传递的参数',
79
+ admissionId: this.editorBindObject.id,
80
+ templateId: 670,
81
+ userInfo: user,
82
+ checkNum: this.editorInfo.registrationNumber
83
+ }
84
+ }
85
+ },
86
+ methods: {
87
+ onEditorInit (main) {
88
+ console.log('[ImageReportDemo] editor init', main)
89
+ },
90
+ onSaveAfter (dataObject) {
91
+ console.log('[ImageReportDemo] saveafter', dataObject)
92
+ },
93
+ async loadMedicalRecord () {
94
+ try {
95
+ const registrationNumber = '1'
96
+ const res = await runLogic('getFileInformation', {
97
+ RegistrationNumber: registrationNumber,
98
+ f_template_id: 670
99
+ }, 'af-his')
100
+
101
+ console.info('返回的电子病历数据:', res)
102
+
103
+ this.editorInfo = {
104
+ loaded: true,
105
+ fileId: res.id,
106
+ templateId: 670,
107
+ registrationNumber
108
+ }
109
+
110
+ const bindObject = res.bindObject || {}
111
+ this.editorBindObject = bindObject
112
+
113
+ const editorInstance = this.$refs.hisEditorRef
114
+ if (editorInstance && editorInstance.init) {
115
+ editorInstance.init({
116
+ fileUrl: res.url,
117
+ resId: res.id,
118
+ currResData: bindObject,
119
+ bindObject: bindObject,
120
+ saveDataLogicName: 'saveMedicalRecordFile',
121
+ serviceName: 'af-his',
122
+ hideToolbar: true,
123
+ treeQueryParams: { description: '查询树结构的参数' },
124
+ docQueryParams: { description: '切换文档的查询条件' },
125
+ logicExtraParams: {
126
+ description: '保存需要传递的参数',
127
+ admissionId: res.bindObject?.id,
128
+ templateId: 670,
129
+ userInfo: this.$store.state.account?.user || {},
130
+ checkNum: registrationNumber
131
+ }
132
+ })
133
+ }
134
+
135
+ this.$message.success(res.id == null ? '新建文书成功' : '加载文书完成')
136
+ } catch (error) {
137
+ console.error('加载失败:', error)
138
+ this.$message.error('加载失败: ' + (error.message || error))
139
+ }
140
+ },
141
+ refreshEditor () {
142
+ const editorInstance = this.$refs.hisEditorRef
143
+ if (editorInstance && editorInstance.refresh) {
144
+ editorInstance.refresh()
145
+ }
146
+ }
147
+ }
148
+ }
149
+ </script>
150
+
151
+ <style scoped lang="less">
152
+ .image-report-demo {
153
+ padding: 20px;
154
+ }
155
+ </style>
@@ -103,7 +103,20 @@
103
103
  <a-input v-model="modifyResModel.f_file_name" placeholder="请输入文档名"/>
104
104
  </a-form-model-item>
105
105
  </a-form-model>
106
- </a-modal></div>
106
+ </a-modal>
107
+
108
+ <!-- 编辑器内部图片预览 -->
109
+ <ImagePreview
110
+ :visible="imagePreview.visible"
111
+ :imgList="imagePreview.imgList"
112
+ :compareList="imagePreview.compareList"
113
+ :initialIndex="imagePreview.index"
114
+ :currentLeftItem="imagePreview.currentLeftItem"
115
+ :currentRightItem="imagePreview.currentRightItem"
116
+ @close="imagePreview.visible = false"
117
+ @pacs-sync-view="handlePacsSync"
118
+ />
119
+ </div>
107
120
  </template>
108
121
 
109
122
  <script>
@@ -111,16 +124,22 @@
111
124
  import { runLogic } from '@vue2-client/services/api/common'
112
125
  import { initDiagnosisDropdown } from './diagnosisAutocomplete'
113
126
  import XDocTree from './XDocTree.vue'
127
+ import ImagePreview from '@vue2-client/base-client/components/his/XImageReport/ImagePreview.vue'
114
128
 
115
129
  export default {
116
130
  name: 'XHisEditor',
117
131
  components: {
118
- XDocTree
132
+ XDocTree,
133
+ ImagePreview
119
134
  },
120
135
  props: {
121
136
  hideEditorToolbar: {
122
137
  type: Boolean,
123
138
  default: true
139
+ },
140
+ imageReportFields: {
141
+ type: Array,
142
+ default: () => []
124
143
  }
125
144
  },
126
145
  computed: {
@@ -182,6 +201,8 @@ export default {
182
201
  loading: false,
183
202
  resDataModalMode: 'modify',
184
203
  resDataModalVisible: false,
204
+ // imageReportFields 支持通过 init() 参数动态覆盖
205
+ mergedImageReportFields: this.imageReportFields || [],
185
206
  // 使用按钮显隐控制
186
207
  // userTemplateVisible: false,
187
208
  objectOfAttrs: {
@@ -248,11 +269,18 @@ export default {
248
269
  fieldFilter: undefined,
249
270
  debounceTimer: null,
250
271
  inputListenerSetup: false,
251
- isComposing: false // 标记是否正在输入中文(拼音输入中)
272
+ isComposing: false, // 标记是否正在输入中文(拼音输入中)
273
+ // 编辑器内部图片预览
274
+ imagePreview: {
275
+ visible: false,
276
+ compareList: [],
277
+ imgList: [],
278
+ index: 0
279
+ }
252
280
  }
253
281
  },
254
282
  // 初始化 保存后 加载文件后 诊断选择
255
- emits: ['init', 'saveafter', 'afterLoadFile', 'selected', 'inputEnd'],
283
+ emits: ['init', 'saveafter', 'afterLoadFile', 'selected', 'inputEnd', 'pacs-sync-view'],
256
284
  methods: {
257
285
  // 获取编辑器绑定数据 - 辅助方法
258
286
  getEditorData () {
@@ -275,6 +303,8 @@ export default {
275
303
  // 更新本地数据
276
304
  this.bindObject = bindObject
277
305
  this.codeData = {}
306
+ // 重新渲染图片报告
307
+ this.renderImageReport()
278
308
  return true
279
309
  }
280
310
  return false
@@ -306,6 +336,8 @@ export default {
306
336
  this.editorRef.setBindObject(currentData)
307
337
  // 更新本地数据
308
338
  this.bindObject = currentData
339
+ // 重新渲染图片报告
340
+ this.renderImageReport()
309
341
 
310
342
  return true
311
343
  },
@@ -433,6 +465,7 @@ export default {
433
465
  docQueryParams,
434
466
  storedInitParams, // 新增
435
467
  mergeStrategy = 'specify', // 模板数据合并策略
468
+ imageReportFields,
436
469
  } = params
437
470
 
438
471
  this.resId = resId
@@ -455,6 +488,9 @@ export default {
455
488
  this.modeType = (modeType === "readonly!" ? "readonly" : modeType)
456
489
  this.readonly = (modeType !== "readonly!")
457
490
  this.fieldFilter = fieldFilter || this.$attrs.fieldFilter
491
+ if (imageReportFields !== undefined) {
492
+ this.mergedImageReportFields = imageReportFields
493
+ }
458
494
 
459
495
  if (loadResList) {
460
496
  this.treeQueryParams = treeQueryParams ? { ...treeQueryParams } : (logicExtraParams ? { ...logicExtraParams } : {})
@@ -514,12 +550,19 @@ export default {
514
550
  this.editorRef.loadUrl(fileUrl).then(() => {
515
551
  if (bindObject) {
516
552
  this.editorRef.setBindObject(bindObject)
553
+ this.bindObject = bindObject // 同步 this.bindObject,供 renderImageReport 使用
517
554
  if (bindObject.template) {
518
555
  for (const key of Object.keys(bindObject.template)) {
519
556
  this.editorRef.bindDataList(key, bindObject.template[key])
520
557
  }
521
558
  }
522
559
  }
560
+
561
+ // 渲染编辑器内部图片报告
562
+ // 等 DOM 渲染完成后再执行
563
+ this.$nextTick(() => {
564
+ this.renderImageReport()
565
+ })
523
566
  // 拿取多于模板中的数据
524
567
  const diff = this.bindObject? Object.fromEntries(
525
568
  Object.entries(this.bindObject)
@@ -1043,6 +1086,14 @@ export default {
1043
1086
  close () {
1044
1087
  this.ready = false
1045
1088
  },
1089
+ handlePacsSync (payload) {
1090
+ const eventName = 'pacs-sync-view'
1091
+ if (this.$listeners[eventName]) {
1092
+ this.$emit(eventName, payload)
1093
+ } else {
1094
+ this.$message?.warn?.(`未实现事件函数 [${eventName}]`)
1095
+ }
1096
+ },
1046
1097
  // 刷新文档
1047
1098
  refresh () {
1048
1099
  this.loadFile(this.fileUrl, this.bindObject, this.currResData)
@@ -1079,6 +1130,99 @@ export default {
1079
1130
  } catch (error) {
1080
1131
  // 静默失败
1081
1132
  }
1133
+ },
1134
+
1135
+ /**
1136
+ * 动态图片使用格式,在将设计好的文书导出html格式,在html种加入图片渲染锚点,id作为后端返回则字段名称:<div id="ctImages" class="x-image-report-root"></div><br>
1137
+ * init的时候增加属性imageReportFields: ['ctImages'],告诉组件这个字段需要渲染为图片 可以是数组字符串或者数组对象 如果是对象则{url:"图片地址",f_upload_date:“对比模式下时间字段”}
1138
+ *
1139
+ * 渲染编辑器内部的图片报告
1140
+ * 根据 imageReportFields 配置,在编辑器 iframe 中查找对应 ID 的容器并注入图片缩略图
1141
+ * 字段名即为容器 ID,模板设计师可在模板 HTML 中预留容器位置
1142
+ */
1143
+ renderImageReport () {
1144
+ if (!this.mergedImageReportFields || !this.mergedImageReportFields.length) {
1145
+ console.log('[XHisEditor] renderImageReport: 没有配置 imageReportFields,跳过')
1146
+ return
1147
+ }
1148
+ if (!this.editorRef) {
1149
+ console.log('[XHisEditor] renderImageReport: editorRef 未就绪,等待...')
1150
+ setTimeout(() => this.renderImageReport(), 200)
1151
+ return
1152
+ }
1153
+ if (!this.editorRef.document) {
1154
+ console.log('[XHisEditor] renderImageReport: iframe document 未就绪,等待...')
1155
+ setTimeout(() => this.renderImageReport(), 200)
1156
+ return
1157
+ }
1158
+
1159
+ const doc = this.editorRef.document
1160
+ const bindObject = this.bindObject || {}
1161
+
1162
+ console.log('[XHisEditor] renderImageReport 开始:', { imageReportFields: this.mergedImageReportFields, bindObject })
1163
+
1164
+ this.mergedImageReportFields.forEach(field => {
1165
+ const imageList = bindObject[field]
1166
+ const compareList = bindObject[`compare_${field}`]
1167
+ console.log(`[XHisEditor] 字段 ${field}:`, imageList)
1168
+
1169
+ let container = doc.getElementById(field)
1170
+ if (!container) {
1171
+ container = doc.createElement('div')
1172
+ container.id = field
1173
+ if (doc.body) {
1174
+ doc.body.appendChild(container)
1175
+ }
1176
+ }
1177
+ container.innerHTML = ''
1178
+
1179
+ if (!Array.isArray(imageList) || imageList.length === 0) {
1180
+ const empty = doc.createElement('div')
1181
+ empty.textContent = '暂无图片'
1182
+ container.appendChild(empty)
1183
+ return
1184
+ }
1185
+
1186
+ const grid = doc.createElement('div')
1187
+ grid.style.cssText = 'display:grid;grid-template-columns:repeat(3,1fr);gap:8px;'
1188
+
1189
+ imageList.forEach((item, index) => {
1190
+ const url = typeof item === 'string' ? item : item?.url || ''
1191
+ const el = doc.createElement('div')
1192
+ el.style.cssText = 'aspect-ratio:1;border-radius:4px;overflow:hidden;cursor:pointer;border:2px solid transparent;transition:all 0.3s;'
1193
+
1194
+ const img = doc.createElement('img')
1195
+ img.src = url
1196
+ img.style.cssText = 'width:100%;height:100%;object-fit:cover;'
1197
+ img.alt = `${field} ${index + 1}`
1198
+
1199
+ el.appendChild(img)
1200
+ grid.appendChild(el)
1201
+
1202
+ el.addEventListener('click', () => {
1203
+ this.openEditorImagePreview(url, imageList, compareList, index, item)
1204
+ })
1205
+ })
1206
+
1207
+ container.appendChild(grid)
1208
+ })
1209
+ },
1210
+
1211
+ /**
1212
+ * 打开编辑器内部图片预览
1213
+ * 直接更新 imagePreview 状态,显示 ImagePreview 组件
1214
+ */
1215
+ openEditorImagePreview (currentUrl, imgList, compareList, index, currentItem) {
1216
+ const leftItem = typeof currentItem === 'object' ? currentItem : (imgList[index] || null)
1217
+ const rightItem = typeof currentItem === 'object' ? null : (compareList[index] || null)
1218
+ this.imagePreview = {
1219
+ visible: true,
1220
+ imgList,
1221
+ compareList,
1222
+ index,
1223
+ currentLeftItem: leftItem,
1224
+ currentRightItem: rightItem
1225
+ }
1082
1226
  }
1083
1227
  }
1084
1228
  }