vue2-client 1.19.59 → 1.19.61

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.19.59",
3
+ "version": "1.19.61",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -106,7 +106,14 @@
106
106
  <div v-if="item.showAvatar" class="gender-icon">
107
107
  <img :src="maleIcon" alt="male" class="gender-img" />
108
108
  </div>
109
- <span class="label-text">{{ item.label }}<span v-if="getItemColon(item)" class="colon">:</span></span>
109
+ <span class="label-text">
110
+ <template v-if="item.type === 'list'">
111
+ <span class="list-label-text">{{ item.label }}</span>
112
+ </template>
113
+ <template v-else>
114
+ {{ item.label }}<span v-if="item.type !== 'list' && getItemColon(item)" class="colon">:</span>
115
+ </template>
116
+ </span>
110
117
  </div>
111
118
  </template>
112
119
  <a-tooltip
@@ -172,7 +179,14 @@
172
179
  <div v-if="item.showAvatar" class="gender-icon">
173
180
  <img :src="maleIcon" alt="male" class="gender-img" />
174
181
  </div>
175
- <span class="label-text">{{ item.label }}</span>
182
+ <span class="label-text">
183
+ <template v-if="item.type === 'list'">
184
+ <span class="list-label-text">{{ item.label }}</span>
185
+ </template>
186
+ <template v-else>
187
+ {{ item.label }}
188
+ </template>
189
+ </span>
176
190
  </div>
177
191
  </template>
178
192
  <div
@@ -458,6 +472,7 @@ export default {
458
472
  return {
459
473
  hiddenConfig: '-1^',
460
474
  data: null,
475
+ rawData: null,
461
476
  config: null,
462
477
  showAllItems: false,
463
478
  maleIcon: require('@vue2-client/assets/svg/male.svg')
@@ -606,20 +621,62 @@ export default {
606
621
  methods: {
607
622
  async getData (data, parameterData) {
608
623
  this.data = null
624
+ this.config = null
609
625
  this.showAllItems = false
610
626
  getConfigByName(data, 'af-his', res => {
611
627
  this.config = res
612
628
  const hiddenConfig = (this.config && this.config.hiddenConfig) || (0 === 1)
613
629
  const parameter = { ...res.parameter, ...this.parameter, ...parameterData }
614
630
  runLogic(res.logicName, parameter, 'af-his').then(result => {
615
- if (hiddenConfig) {
616
- for (const key in result) {
617
- if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
618
- delete result[key]
631
+ // 如果配置启用 parseList(或 expandList),将 type=list 的父项展开为父项 + 子项(子项来自 result 中对应的数组)
632
+ const expandFlag = Boolean(res.expandList || res.parseList)
633
+ // 不用展开则直接将结果赋值给augmented
634
+ if(!expandFlag){
635
+ if (hiddenConfig) {
636
+ for (const key in result) {
637
+ if (Object.prototype.hasOwnProperty.call(result, key) && result[key] === this.hiddenConfig) {
638
+ delete result[key]
639
+ }
619
640
  }
620
641
  }
642
+ this.data = result
643
+ }
644
+ const augmented = {}
645
+ if (expandFlag && Array.isArray(res.items)) {
646
+ // 在 expandFlag && Array.isArray(res.items) 的分支内
647
+ const expandedItems = []
648
+ // 用快照遍历,避免遍历被修改过的 res.items
649
+ const originalItems = Array.isArray(res.items) ? res.items.slice() : []
650
+ originalItems.forEach(parentItem => {
651
+ if (!parentItem) return
652
+ if (parentItem.type === 'list') {
653
+ expandedItems.push(parentItem)
654
+ const arr = result ? result[parentItem.field] : null
655
+ if (Array.isArray(arr)) {
656
+ augmented[parentItem.field] = ''
657
+ arr.forEach((sub, idx) => {
658
+ const childItem = {
659
+ field: sub.field || `${parentItem.field}_${idx + 1}`,
660
+ label: sub.label ?? '',
661
+ colon: sub.colon ? sub.colon : parentItem.colon,
662
+ style: parentItem.style ? { ...parentItem.style } : undefined,
663
+ showAvatar: parentItem.showAvatar,
664
+ unit: parentItem.unit,
665
+ }
666
+ if (sub && sub.value !== undefined) augmented[childItem.field] = sub.value
667
+ expandedItems.push(childItem)
668
+ })
669
+ }
670
+ } else {
671
+ // 普通项直接加入
672
+ expandedItems.push(parentItem)
673
+ }
674
+ })
675
+ // 不要改原 res,创建新 config
676
+ this.rawData = result
677
+ this.config = { ...res, items: expandedItems }
678
+ this.data = augmented
621
679
  }
622
- this.data = result
623
680
  })
624
681
  })
625
682
  },
@@ -797,6 +854,10 @@ export default {
797
854
  text-decoration: none !important;
798
855
  }
799
856
 
857
+ .list-label-text{
858
+ font-weight: bold;
859
+ }
860
+
800
861
  .content-wrapper {
801
862
  display: inline-flex;
802
863
  align-items: center;
@@ -80,9 +80,12 @@
80
80
  slot="extraBeforeTabs"
81
81
  key="workFlowTab"
82
82
  tab="表单"
83
- >
84
- <work-flow-preview v-if="historyFormCompletedDataPreview" :form-completed-data-preview="historyFormCompletedDataPreview" :showTitle="false"/>
85
- <a-divider/>
83
+ >
84
+ <work-flow-step-files-preview
85
+ v-if="historyFormCompletedDataPreview"
86
+ :preview="historyFormCompletedDataPreview"
87
+ />
88
+ <a-divider/>
86
89
  <x-add-native-form
87
90
  ref="xAddForm"
88
91
  @x-form-item-emit-func="formItemEmitFunc"
@@ -90,8 +93,11 @@
90
93
  </a-tab-pane>
91
94
  </x-tab>
92
95
  <div v-else>
93
- <work-flow-preview v-if="historyFormCompletedDataPreview" :form-completed-data-preview="historyFormCompletedDataPreview" :showTitle="false"/>
94
- <a-divider/>
96
+ <work-flow-step-files-preview
97
+ v-if="historyFormCompletedDataPreview"
98
+ :preview="historyFormCompletedDataPreview"
99
+ />
100
+ <a-divider/>
95
101
  <x-add-native-form
96
102
  ref="xAddForm"
97
103
  @x-form-item-emit-func="formItemEmitFunc"
@@ -287,6 +293,7 @@ import { getConfigByNameAsync, runLogic } from '@vue2-client/services/api/common
287
293
  import LogicRunner from '@vue2-client/logic/LogicRunner'
288
294
  import XTab from '@vue2-client/base-client/components/common/XTab/XTab.vue'
289
295
  import WorkFlowPreview from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowPreview'
296
+ import WorkFlowStepFilesPreview from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowStepFilesPreview.vue'
290
297
  import WorkflowPersonSelector from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/components/WorkflowPersonSelector.vue'
291
298
 
292
299
  export default {
@@ -308,6 +315,7 @@ export default {
308
315
  FileItem,
309
316
  ImageItem,
310
317
  WorkFlowPreview,
318
+ WorkFlowStepFilesPreview,
311
319
  WorkflowPersonSelector
312
320
  },
313
321
  computed: {
@@ -962,73 +970,82 @@ export default {
962
970
  this.historyFormCompletedDataPreview = null
963
971
  // 表单的渲染
964
972
  if (properties.form && properties.form.formJson) {
973
+
974
+ // 当前处理环节 是否展示历史数据配置
965
975
  if (properties.otherProperty && properties.otherProperty.historyFormData) {
966
976
  const historyFormDataConfig = properties.otherProperty.historyFormData
967
977
 
968
- // 收集所有需要查询的步骤和字段映射关系
969
- const configItems = []
970
- const stepIdSet = new Set()
978
+ // 预处理
979
+ const stepIdByName = new Map(this.stepsForChild.map(step => [step.name, step.id]))
980
+ const stepFormJsonByStepId = new Map(
981
+ this.stepsDefine.map(step => [step.id, step?.properties?.form?.formJson])
982
+ )
971
983
 
984
+ const stepIdSet = new Set()
972
985
  for (const historyFormConfig of historyFormDataConfig) {
973
- const stepConfig = this.stepsDefine.find(item => item.name === historyFormConfig.stepName)
974
- if (!stepConfig) {
975
- continue
976
- }
986
+ const targetStepId = stepIdByName.get(historyFormConfig.stepName)
987
+ if (targetStepId == null) continue
988
+ stepIdSet.add(targetStepId)
989
+ }
977
990
 
978
- const stepId = stepConfig.id
979
- const stepFormJson = stepConfig?.properties?.form?.formJson
980
- if (!stepFormJson) {
981
- continue
982
- }
991
+ const stepIdS = Array.from(stepIdSet)
992
+ if (stepIdS.length > 0) {
993
+ const allStepData = await postByServiceName('/logic/geWorkFlowCompletedStepDataBySteps', {
994
+ workflowId: this.workflowId,
995
+ stepIdS
996
+ })
983
997
 
984
- const formItem = stepFormJson.find(item => item.name === historyFormConfig.formLabel)
985
- const model = formItem?.model
998
+ // 组装历史表单数据(data 部分)和按步骤分组的附件
999
+ const historyFormData = []
1000
+ const stepAttachmentsMap = new Map()
986
1001
 
987
- if (!model) {
988
- continue
989
- }
1002
+ for (const historyFormConfig of historyFormDataConfig) {
1003
+ const targetStepId = stepIdByName.get(historyFormConfig.stepName)
1004
+ if (targetStepId == null) continue
990
1005
 
991
- // 收集配置项和需要查询的 stepId
992
- configItems.push({
993
- stepId,
994
- model,
995
- displayLabel: historyFormConfig.displayLabel
996
- })
997
- stepIdSet.add(stepId)
998
- }
1006
+ const stepFormJson = stepFormJsonByStepId.get(targetStepId)
1007
+ if (!stepFormJson) continue
999
1008
 
1000
- // 批量查询:每个 stepId 只查询一次,并行执行
1001
- const formDataCache = new Map()
1002
- const queryPromises = Array.from(stepIdSet).map(async stepId => {
1003
- try {
1004
- const formData = await postByServiceName(
1005
- workFlowViewApi.getWorkFlowCompletedStepData,
1006
- { workflowId: this.workflowId, stepId }
1007
- )
1008
- formDataCache.set(stepId, formData.data || {})
1009
- } catch (error) {
1010
- console.error(`查询步骤 ${stepId} 的数据失败:`, error)
1011
- formDataCache.set(stepId, {})
1012
- }
1013
- })
1009
+ const stepDataRaw = allStepData?.[targetStepId] || allStepData?.[String(targetStepId)]
1010
+ if (!stepDataRaw) continue
1014
1011
 
1015
- // 等待所有查询完成
1016
- await Promise.all(queryPromises)
1012
+ const isAttachment = historyFormConfig.displayLabel === '附件' && historyFormConfig.formLabel === '附件'
1017
1013
 
1018
- // 组装历史表单数据
1019
- const historyFormData = configItems.map(configItem => {
1020
- const cachedFormData = formDataCache.get(configItem.stepId)
1021
- return {
1022
- label: configItem.displayLabel,
1023
- value: cachedFormData?.[configItem.model]
1014
+ if (isAttachment) {
1015
+ // 仅在配置了附件时才收集对应步骤的附件
1016
+ if (!stepAttachmentsMap.has(targetStepId)) {
1017
+ stepAttachmentsMap.set(targetStepId, {
1018
+ stepId: targetStepId,
1019
+ stepName: historyFormConfig.stepName,
1020
+ data: [],
1021
+ images: [],
1022
+ files: []
1023
+ })
1024
+ }
1025
+ const attachment = stepAttachmentsMap.get(targetStepId)
1026
+ attachment.images = Array.isArray(stepDataRaw.images) ? stepDataRaw.images : []
1027
+ attachment.files = Array.isArray(stepDataRaw.files) ? stepDataRaw.files : []
1028
+ } else {
1029
+ const formItem = stepFormJson.find(item => item.name === historyFormConfig.formLabel)
1030
+ const model = formItem?.model
1031
+ if (!model) continue
1032
+ // 普通字段:从 data 中取值,并按 displayLabel 组织
1033
+ const value = stepDataRaw.data ? stepDataRaw.data[model] : undefined
1034
+ if (value === undefined || value === null) continue
1035
+ historyFormData.push({
1036
+ label: historyFormConfig.displayLabel,
1037
+ value
1038
+ })
1039
+ }
1024
1040
  }
1025
- })
1026
1041
 
1027
- this.historyFormCompletedDataPreview = {
1028
- data: historyFormData,
1029
- images: [],
1030
- files: [],
1031
- note: ''
1042
+ // 聚合所有步骤的附件到统一的 images/files,同时保留按步骤分组的数据
1043
+ const stepAttachments = Array.from(stepAttachmentsMap.values())
1044
+
1045
+ this.historyFormCompletedDataPreview = {
1046
+ data: historyFormData,
1047
+ stepAttachments,
1048
+ }
1032
1049
  }
1033
1050
  }
1034
1051
  this.stepDefine = properties.form.formJson
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <div class="workflow-step-preview">
3
+ <!-- data:不分步骤,直接展示(有就展示,没有就不展示) -->
4
+ <a-descriptions
5
+ v-if="previewData && previewData.length"
6
+ :column="{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }"
7
+ bordered
8
+ size="small"
9
+ class="descriptionPreviewItem"
10
+ >
11
+ <p slot="title" class="descriptionTitle">
12
+ 填写历史
13
+ </p>
14
+ <a-descriptions-item
15
+ v-for="(item, idx) in previewData"
16
+ :key="item.label || idx"
17
+ v-if="item.label !== '附件上传' && item.label !== '__expressionRs'"
18
+ >
19
+ <span slot="label" class="label">{{ item.label }}</span>
20
+ <span v-if="(item.type ?? 'default') === 'image'">
21
+ <div class="value">
22
+ <image-item :images="item.value" :width="70" :padding="0"/>
23
+ </div>
24
+ </span>
25
+ <span v-else>
26
+ <div class="value">{{ item.value }}</div>
27
+ </span>
28
+ </a-descriptions-item>
29
+ </a-descriptions>
30
+
31
+ <!-- 附件:按步骤分组展示(有就展示,没有就不展示) -->
32
+ <a-card
33
+ v-for="step in normalizedAttachmentSteps"
34
+ :key="step.stepId"
35
+ size="small"
36
+ class="step-card"
37
+ :bordered="false"
38
+ >
39
+ <template slot="title">
40
+ <span class="step-title">{{ step.stepName }}</span>
41
+ </template>
42
+
43
+ <div v-if="Array.isArray(step.images) && step.images.length" class="attachment-block">
44
+ <image-item :images="step.images" :width="70" :padding="0"/>
45
+ </div>
46
+
47
+ <div v-if="Array.isArray(step.files) && step.files.length" class="attachment-block">
48
+ <file-item :files="step.files" />
49
+ </div>
50
+ </a-card>
51
+ </div>
52
+ </template>
53
+
54
+ <script>
55
+ import { FileItem, ImageItem } from '@vue2-client/components/FileImageItem'
56
+
57
+ export default {
58
+ name: 'WorkFlowStepFilesPreview',
59
+ components: {
60
+ FileItem,
61
+ ImageItem
62
+ },
63
+ props: {
64
+ preview: {
65
+ type: Object,
66
+ default: null
67
+ },
68
+ stepAttachments: {
69
+ type: Array,
70
+ default: () => []
71
+ },
72
+ },
73
+ computed: {
74
+ previewData () {
75
+ const data = this.preview?.data
76
+ return Array.isArray(data) ? data : null
77
+ },
78
+ normalizedAttachmentSteps () {
79
+ const steps = (this.preview && Array.isArray(this.preview.stepAttachments))
80
+ ? this.preview.stepAttachments
81
+ : this.stepAttachments
82
+
83
+ return (steps || [])
84
+ .filter(step => step && step.stepId != null)
85
+ .map(step => ({
86
+ stepId: step.stepId,
87
+ stepName: step.stepName || `步骤 ${step.stepId}`,
88
+ images: Array.isArray(step.images) ? step.images : [],
89
+ files: Array.isArray(step.files) ? step.files : []
90
+ }))
91
+ .filter(step => step.images.length || step.files.length)
92
+ }
93
+ },
94
+ }
95
+ </script>
96
+
97
+ <style lang="less" scoped>
98
+ .workflow-step-preview {
99
+ padding: 4px 0;
100
+ }
101
+
102
+ .step-card {
103
+ margin-bottom: 14px;
104
+ border-radius: 10px;
105
+ border: 1px solid #f0f0f0;
106
+ box-shadow: 0 4px 10px -6px rgba(0, 0, 0, 0.05);
107
+
108
+ :deep(.ant-card-body) {
109
+ padding: 12px 16px 10px;
110
+ }
111
+ }
112
+
113
+ .step-title {
114
+ font-weight: 600;
115
+ color: rgba(0, 0, 0, 0.85);
116
+ }
117
+
118
+ .label {
119
+ color: rgba(0, 0, 0, 0.85);
120
+ }
121
+
122
+ .value {
123
+ white-space: pre-wrap;
124
+ word-break: break-word;
125
+ color: rgba(0, 0, 0, 0.65);
126
+ }
127
+
128
+ .attachment-block {
129
+ padding: 8px 0;
130
+
131
+ & + & {
132
+ margin-top: 8px;
133
+ }
134
+
135
+ :deep(.file-item),
136
+ :deep(.image-item) {
137
+ margin: 0;
138
+ }
139
+ }
140
+
141
+ .descriptionPreviewItem {
142
+ margin-bottom: 22px;
143
+ border-radius: 10px;
144
+ overflow: hidden;
145
+ }
146
+
147
+ .descriptionTitle {
148
+ position: relative;
149
+ padding-left: 12px;
150
+
151
+ &::before {
152
+ content: '';
153
+ position: absolute;
154
+ left: 0;
155
+ top: 50%;
156
+ transform: translateY(-50%);
157
+ width: 4px;
158
+ height: 16px;
159
+ background-color: #1890ff;
160
+ border-radius: 2px;
161
+ }
162
+ }
163
+ </style>
164
+
165
+