vue2-client 1.19.2 → 1.19.4

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.2",
3
+ "version": "1.19.4",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -1,3 +1,3 @@
1
- import AmapPointRendering from './AmapPointRendering'
2
-
3
- export default AmapPointRendering
1
+ import AmapPointRendering from './AmapPointRendering'
2
+
3
+ export default AmapPointRendering
@@ -136,7 +136,21 @@ export default {
136
136
  console.warn(`Config '${configName}' did not return a valid 'value' array for options. Result:`, res)
137
137
  }
138
138
  } else {
139
- // 移除对旧字典的解析
139
+ // 全局字典
140
+ if (this.$appdata && typeof this.$appdata.getDictByKeyAsync === 'function') {
141
+ const dictionaryList = await this.$appdata.getDictByKeyAsync(item.keyName)
142
+ if (Array.isArray(dictionaryList)) {
143
+ fetchedOptions = dictionaryList.map(opt => ({
144
+ label: opt.label,
145
+ value: opt.value + '',
146
+ ...opt // 将所有原始属性也添加到选项中
147
+ }))
148
+ } else {
149
+ console.warn(`Global dictionary '${item.keyName}' did not return an array. Result:`, dictionaryList)
150
+ }
151
+ } else {
152
+ console.error('$appdata.getDictionaryList is not available. Please ensure it\'s globally provided.')
153
+ }
140
154
  }
141
155
  } catch (error) {
142
156
  console.error(`Error fetching options for item '${item.key}':`, error)
@@ -110,14 +110,13 @@ defineExpose({
110
110
  :deep(.ant-row-flex) {
111
111
  .x-form-col-wrapper {
112
112
  .ant-form-item {
113
- display: flex;
113
+ display: flex !important;
114
114
  width: 100%;
115
115
  height: 100%;
116
116
  margin-bottom: 0px;
117
117
  justify-content: space-between;
118
118
 
119
119
  .ant-form-item-label {
120
- width: 100%;
121
120
  display: flex;
122
121
  align-items: center;
123
122
  height: 100%;
@@ -11,7 +11,7 @@ export default {
11
11
  }
12
12
  },
13
13
  mounted() {
14
- getConfigByNameAsync('测试Form', 'af-safecheck').then(res => {
14
+ getConfigByNameAsync('CardSellGasForm', 'af-revenue').then(res => {
15
15
  this.$refs.xAddFrom.init(
16
16
  Object.assign(res, {
17
17
  modifyModelData: {
@@ -1,3 +1,3 @@
1
- import XDetailsView from './XDetailsView'
2
-
3
- export default XDetailsView
1
+ import XDetailsView from './XDetailsView'
2
+
3
+ export default XDetailsView
@@ -144,6 +144,22 @@
144
144
  </template>
145
145
  </a-select-option>
146
146
  </template>
147
+ <template v-else>
148
+ <a-select-option
149
+ v-for="item in $appdata.getDictByKeyAsync(attr.keyName)"
150
+ :key="item.value"
151
+ :value="item.value + ''"
152
+ >
153
+ <!-- 徽标(badge) -->
154
+ <x-badge
155
+ :badge-key="attr.keyName"
156
+ :replaceText="item.label"
157
+ :value="item.value"
158
+ :service-name="serviceName"
159
+ :env="env"
160
+ />
161
+ </a-select-option>
162
+ </template>
147
163
  </template>
148
164
  </a-select>
149
165
  <a-select
@@ -243,6 +259,15 @@
243
259
  </template>
244
260
  </a-select-option>
245
261
  </template>
262
+ <template v-else>
263
+ <a-select-option
264
+ v-for="item in $appdata.getDictByKeyAsync(attr.keyName)"
265
+ :key="item.value"
266
+ :value="item.value + ''"
267
+ >
268
+ {{ item.label }}
269
+ </a-select-option>
270
+ </template>
246
271
  </template>
247
272
  </a-select>
248
273
  <a-select
@@ -308,6 +333,11 @@
308
333
  {{ item.label }}
309
334
  </a-radio>
310
335
  </template>
336
+ <template v-else>
337
+ <a-radio v-for="(item, index) in $appdata.getDictByKeyAsync(attr.keyName)" :key="index" :value="item.value">
338
+ {{ item.label }}
339
+ </a-radio>
340
+ </template>
311
341
  </template>
312
342
  </a-radio-group>
313
343
  </a-form-model-item>
@@ -1,3 +1,3 @@
1
- import XFormGroupDetails from './XFormGroupDetails'
2
-
3
- export default XFormGroupDetails
1
+ import XFormGroupDetails from './XFormGroupDetails'
2
+
3
+ export default XFormGroupDetails
@@ -64,7 +64,8 @@
64
64
  'x-import-excel-button',
65
65
  'x-chart',
66
66
  'h-chart',
67
- 'x-simple-table'
67
+ 'x-simple-table',
68
+ 'x-workflow-progress'
68
69
  ].includes(cell.slotType)">
69
70
  <component
70
71
  :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
@@ -143,7 +144,8 @@
143
144
  'x-import-excel-button',
144
145
  'x-chart',
145
146
  'h-chart',
146
- 'x-simple-table'
147
+ 'x-simple-table',
148
+ 'x-workflow-progress'
147
149
  ].includes(cell.slotType)">
148
150
  <component
149
151
  :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
@@ -219,7 +221,8 @@ export default {
219
221
  XImportExcelButton: () => import('@vue2-client/base-client/components/his/XImportExcelButton/XImportExcelButton.vue'),
220
222
  XChart: () => import('@vue2-client/base-client/components/his/XChart/XChart.vue'),
221
223
  HChart: () => import('@vue2-client/base-client/components/his/HChart/HChart.vue'),
222
- XSimpleTable: () => import('@vue2-client/base-client/components/his/XSimpleTable/XSimpleTable.vue')
224
+ XSimpleTable: () => import('@vue2-client/base-client/components/his/XSimpleTable/XSimpleTable.vue'),
225
+ XWorkflowProgress: () => import('@vue2-client/base-client/components/his/XWorkflowProgress/XWorkflowProgress.vue')
223
226
  },
224
227
  props: {
225
228
  // 每一行的配置
@@ -12,6 +12,7 @@
12
12
  :key="index"
13
13
  :fill="path.fill || 'currentColor'"
14
14
  :d="path.d"
15
+ :transform="path.transform"
15
16
  />
16
17
  </svg>
17
18
  </template>
@@ -35,6 +36,33 @@ const iconConfigs = {
35
36
  d: 'M0.72589612,0C0.32499826,0,0,0.34822667,0,0.77777773L0,13.222221C0,13.651789,0.32499826,14,0.72589612,14L12.340235,14C12.741146,14,13.066131,13.651789,13.066131,13.222221L13.066131,0.77777773C13.066131,0.34822667,12.741146,0,12.340235,0L0.72589612,0ZM2.9035845,4.6666665L2.9035845,3.1111109L10.162547,3.1111109L10.162547,4.6666665L2.9035845,4.6666665ZM2.9035845,7.7777777L2.9035845,6.2222219L10.162547,6.2222219L10.162547,7.7777777L2.9035845,7.7777777ZM10.162547,10.888889L2.9035845,10.888889L2.9035845,9.333333L10.162547,9.333333L10.162547,10.888889Z',
36
37
  fill: 'currentColor'
37
38
  }]
39
+ },
40
+ 'executed': {
41
+ viewBox: '0 0 24 24',
42
+ paths: [
43
+ {
44
+ d: 'M12,2C6.4758101,2,2,6.4758101,2,12C2,17.5242,6.4758101,22,12,22C17.5242,22,22,17.5242,22,12C22,6.4758101,17.5242,2,12,2C12,2,12,2,12,2ZM12,20.064501C7.5443501,20.064501,3.93548,16.4556,3.93548,12C3.93548,7.5443501,7.5443501,3.93548,12,3.93548C16.4556,3.93548,20.064501,7.5443501,20.064501,12C20.064501,16.4556,16.4556,20.064501,12,20.064501C12,20.064501,12,20.064501,12,20.064501Z',
45
+ fill: 'currentColor'
46
+ },
47
+ {
48
+ d: 'M17.739441,8.59375C18.091259,8.2243509,18.086147,7.63233471,17.727966000000002,7.26953125C17.369604000000002,6.906727791,16.794123,6.911850929,16.442322,7.28125C16.442322,7.28125,17.739441,8.59375,17.739441,8.59375C17.739441,8.59375,17.739441,8.59375,17.739441,8.59375ZM9.5908961,16.057060200000002C9.5908961,16.057060200000002,8.9423146,16.7139664,8.9423146,16.7139664C9.1132417,16.8934593,9.3469505,16.994560200000002,9.5908961,16.994560200000002C9.8348408,16.994560200000002,10.0685496,16.8934593,10.2394772,16.7139664C10.2394772,16.7139664,9.5908961,16.057060200000002,9.5908961,16.057060200000002C9.5908961,16.057060200000002,9.5908961,16.057060200000002,9.5908961,16.057060200000002ZM6.5576743,11.4328156C6.2058653,11.0634031,5.63029587,11.0582848,5.27209082,11.4210968C4.913885564,11.7838917,4.908685297,12.3798094,5.26049414,12.7492218C5.26049414,12.7492218,6.5576743,11.4328156,6.5576743,11.4328156C6.5576743,11.4328156,6.5576743,11.4328156,6.5576743,11.4328156ZM16.442322,7.28125C16.442322,7.28125,8.9423146,15.4001532,8.9423146,15.4001532C8.9423146,15.4001532,10.2394772,16.7139664,10.2394772,16.7139664C10.2394772,16.7139664,17.739441,8.59375,17.739441,8.59375C17.739441,8.59375,16.442322,7.28125,16.442322,7.28125C16.442322,7.28125,16.442322,7.28125,16.442322,7.28125ZM10.2394772,15.4001532C10.2394772,15.4001532,6.5576743,11.4328156,6.5576743,11.4328156C6.5576743,11.4328156,5.26049414,12.7492218,5.26049414,12.7492218C5.26049414,12.7492218,8.9423146,16.7139664,8.9423146,16.7139664C8.9423146,16.7139664,10.2394772,15.4001532,10.2394772,15.4001532C10.2394772,15.4001532,10.2394772,15.4001532,10.2394772,15.4001532Z',
49
+ fill: 'currentColor'
50
+ }
51
+ ]
52
+ },
53
+ 'not-executed': {
54
+ viewBox: '0 0 24 24',
55
+ paths: [
56
+ {
57
+ d: 'M12,2C6.4758101,2,2,6.4758101,2,12C2,17.5242,6.4758101,22,12,22C17.5242,22,22,17.5242,22,12C22,6.4758101,17.5242,2,12,2C12,2,12,2,12,2ZM12,20.064501C7.5443501,20.064501,3.93548,16.4556,3.93548,12C3.93548,7.5443501,7.5443501,3.93548,12,3.93548C16.4556,3.93548,20.064501,7.5443501,20.064501,12C20.064501,16.4556,16.4556,20.064501,12,20.064501C12,20.064501,12,20.064501,12,20.064501Z',
58
+ fill: 'currentColor'
59
+ },
60
+ {
61
+ d: 'M14.999481933624267,13.09568884321289C15.351299933624267,12.72628974321289,15.365474933624268,12.122554783212891,15.007293933624268,11.759751353212891C14.648931933624267,11.396947893212891,14.046595133624267,11.421602279212891,13.694794133624267,11.791001353212891C13.694794133624267,11.791001353212891,14.999481933624267,13.09568884321289,14.999481933624267,13.09568884321289C14.999481933624267,13.09568884321289,14.999481933624267,13.09568884321289,14.999481933624267,13.09568884321289ZM8.777585033624268,16.71524434321289C8.777585033624268,16.71524434321289,8.777464833624268,18.02806854321289,8.777464833624268,18.02806854321289C8.948391933624269,18.20756194321289,9.181957233624267,18.30541274321289,9.425902333624268,18.30541274321289C9.669847533624267,18.30541274321289,9.903412833624268,18.19584324321289,10.074339833624268,18.016349743212892C10.074339833624268,18.016349743212892,8.777585033624268,16.71524434321289,8.777585033624268,16.71524434321289C8.777585033624268,16.71524434321289,8.777585033624268,16.71524434321289,8.777585033624268,16.71524434321289ZM6.074460133624267,12.71133804321289C5.722651133624268,12.34192562321289,5.127977733624268,12.344619753212891,4.769772653624267,12.70743174321289C4.411567389624268,13.07022694321289,4.410151362624267,13.66223814321289,4.761960153624267,14.03165054321289C4.761960153624267,14.03165054321289,6.074460133624267,12.71133804321289,6.074460133624267,12.71133804321289C6.074460133624267,12.71133804321289,6.074460133624267,12.71133804321289,6.074460133624267,12.71133804321289ZM13.694794133624267,11.791001353212891C13.694794133624267,11.791001353212891,8.176022533624268,17.30118174321289,8.176022533624268,17.30118174321289C8.176022533624268,17.30118174321289,10.074339833624268,18.016349743212892,10.074339833624268,18.016349743212892C10.074339833624268,18.016349743212892,14.999481933624267,13.09568884321289,14.999481933624267,13.09568884321289C14.999481933624267,13.09568884321289,13.694794133624267,11.791001353212891,13.694794133624267,11.791001353212891C13.694794133624267,11.791001353212891,13.694794133624267,11.791001353212891,13.694794133624267,11.791001353212891ZM10.074339833624268,16.703849743212892C10.074339833624268,16.703849743212892,6.074460133624267,12.71133804321289,6.074460133624267,12.71133804321289C6.074460133624267,12.71133804321289,4.761960153624267,14.03165054321289,4.761960153624267,14.03165054321289C4.761960153624267,14.03165054321289,8.777464833624268,18.02806854321289,8.777464833624268,18.02806854321289C8.777464833624268,18.02806854321289,10.074339833624268,16.703849743212892,10.074339833624268,16.703849743212892C10.074339833624268,16.703849743212892,10.074339833624268,16.703849743212892,10.074339833624268,16.703849743212892Z',
62
+ fill: 'currentColor',
63
+ transform: 'matrix(0.7071067690849304,-0.7071067690849304,0.7071067690849304,0.7071067690849304,-6.8141087089094015,6.550087043158868)'
64
+ }
65
+ ]
38
66
  }
39
67
  }
40
68
 
@@ -0,0 +1,536 @@
1
+ <template>
2
+ <div class="x-workflow-progress">
3
+ <div class="workflow-steps-wrapper">
4
+ <div :class="['workflow-steps', { center: isCentered }]" ref="workflowSteps">
5
+ <div
6
+ v-for="(step, index) in displaySteps"
7
+ :key="index"
8
+ class="workflow-step"
9
+ :class="{ 'is-completed': step.status === 'executed', 'is-pending': step.status === 'not-executed' }"
10
+ >
11
+ <!-- 直接显示图标(去掉外层圆圈),标签在图标后面 -->
12
+ <div class="step-circle">
13
+ <x-icon
14
+ :name="getIconName(step)"
15
+ class="step-icon"
16
+ :style="{ fontSize: '20px' }"
17
+ />
18
+ </div>
19
+
20
+ <!-- 步骤名称(在图标后面) -->
21
+ <div class="step-label">{{ step.label }}</div>
22
+
23
+ <!-- 连接线 -->
24
+ <div
25
+ v-if="index < displaySteps.length - 1"
26
+ class="step-connector"
27
+ ></div>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </template>
33
+
34
+ <script>
35
+ import { getConfigByName } from '@vue2-client/services/api/common'
36
+ import XIcon from '@vue2-client/base-client/components/his/XIcon'
37
+
38
+ export default {
39
+ name: 'XWorkflowProgress',
40
+ components: {
41
+ XIcon
42
+ },
43
+ props: {
44
+ // 配置对象,用于通过 runLogic 获取步骤数据
45
+ queryParamsName: {
46
+ type: Object,
47
+ default: null
48
+ },
49
+ // 服务名称,默认为 af-his
50
+ serviceName: {
51
+ type: String,
52
+ default: 'af-his'
53
+ },
54
+ // 步骤数据(直接传入,优先级高于 queryParamsName)
55
+ steps: {
56
+ type: Array,
57
+ required: false,
58
+ default: () => []
59
+ },
60
+ // (图标名称已固定为 executed / not-executed,移除可配置 props)
61
+ },
62
+ data() {
63
+ return {
64
+ internalSteps: [],
65
+ // 拖拽滚动状态
66
+ isDown: false,
67
+ startX: 0,
68
+ startScrollLeft: 0,
69
+ // 是否显示为居中(当内容不溢出)
70
+ isCentered: false,
71
+ // 当前步骤索引(从0开始)
72
+ currentStepIndex: -1
73
+ }
74
+ },
75
+ computed: {
76
+ displaySteps() {
77
+ // 如果直接传入了 steps,优先使用
78
+ if (this.steps && this.steps.length > 0) {
79
+ return this.steps
80
+ }
81
+ // 否则使用从配置获取的数据
82
+ return this.internalSteps
83
+ }
84
+ },
85
+ created() {
86
+ // 如果没有直接传入 steps,且配置了 queryParamsName,则通过配置获取数据
87
+ if ((!this.steps || this.steps.length === 0) && this.queryParamsName) {
88
+ this.getData(this.queryParamsName)
89
+ } else if (this.steps && this.steps.length > 0) {
90
+ // 如果直接传入了 steps,直接使用
91
+ this.internalSteps = this.steps
92
+ }
93
+ },
94
+ mounted() {
95
+ this.$nextTick(() => {
96
+ const el = this.$refs.workflowSteps
97
+ if (el) {
98
+ this.addDragListeners(el)
99
+ this.checkOverflow()
100
+ }
101
+ window.addEventListener('resize', this.checkOverflow)
102
+ })
103
+ },
104
+ beforeDestroy() {
105
+ const el = this.$refs.workflowSteps
106
+ if (el) this.removeDragListeners(el)
107
+ window.removeEventListener('resize', this.checkOverflow)
108
+ },
109
+ methods: {
110
+ getData(config) {
111
+ // 如果config是字符串,直接使用;如果是对象,提取配置名称
112
+ const configName = typeof config === 'string' ? config : config?.configName || config?.name
113
+ if (!configName) {
114
+ console.warn('配置名称不能为空')
115
+ this.internalSteps = []
116
+ return
117
+ }
118
+
119
+ getConfigByName(configName, this.serviceName, (res) => {
120
+ // 处理返回的数据格式
121
+ // 支持 res.data.value, res.data, 或直接返回数组
122
+ const rawData = res?.data || res
123
+ let data = null
124
+
125
+ if (rawData && Array.isArray(rawData)) {
126
+ // 直接是数组格式
127
+ data = rawData
128
+ } else if (rawData && rawData.value && Array.isArray(rawData.value)) {
129
+ // {value: [...]} 格式
130
+ data = rawData.value
131
+ }
132
+
133
+ if (data && Array.isArray(data)) {
134
+ // 返回字段固定,直接使用 label/value/status
135
+ this.internalSteps = data.map(item => ({
136
+ label: item.label,
137
+ value: item.value,
138
+ status: item.status
139
+ }))
140
+ // 初始化当前步骤索引
141
+ this.updateCurrentStepIndex()
142
+ } else {
143
+ this.internalSteps = []
144
+ }
145
+ })
146
+ },
147
+ // 仅根据新状态判断:执行 -> executed,否则 -> not-executed
148
+ getIconName(step) {
149
+ return step && step.status === 'executed' ? 'executed' : 'not-executed'
150
+ },
151
+ /**
152
+ * 添加拖拽滚动监听
153
+ */
154
+ addDragListeners(el) {
155
+ // 鼠标
156
+ el.addEventListener('mousedown', this.onDragStart)
157
+ el.addEventListener('mousemove', this.onDragMove)
158
+ el.addEventListener('mouseup', this.onDragEnd)
159
+ el.addEventListener('mouseleave', this.onDragEnd)
160
+ // 触摸
161
+ el.addEventListener('touchstart', this.onDragStart, { passive: false })
162
+ el.addEventListener('touchmove', this.onDragMove, { passive: false })
163
+ el.addEventListener('touchend', this.onDragEnd)
164
+ },
165
+ removeDragListeners(el) {
166
+ el.removeEventListener('mousedown', this.onDragStart)
167
+ el.removeEventListener('mousemove', this.onDragMove)
168
+ el.removeEventListener('mouseup', this.onDragEnd)
169
+ el.removeEventListener('mouseleave', this.onDragEnd)
170
+ el.removeEventListener('touchstart', this.onDragStart)
171
+ el.removeEventListener('touchmove', this.onDragMove)
172
+ el.removeEventListener('touchend', this.onDragEnd)
173
+ },
174
+ /**
175
+ * 检查是否溢出;未溢出时将内容居中
176
+ */
177
+ checkOverflow() {
178
+ const el = this.$refs.workflowSteps
179
+ if (!el) {
180
+ this.isCentered = false
181
+ return
182
+ }
183
+ // 如果实际宽度 <= 可见宽度,则居中显示
184
+ this.isCentered = el.scrollWidth <= el.clientWidth + 4
185
+ },
186
+ onDragStart(e) {
187
+ const el = this.$refs.workflowSteps
188
+ if (!el) return
189
+ this.isDown = true
190
+ el.classList.add('dragging')
191
+ const pageX = e.touches ? e.touches[0].pageX : e.pageX
192
+ this.startX = pageX - el.getBoundingClientRect().left
193
+ this.startScrollLeft = el.scrollLeft
194
+ },
195
+ onDragMove(e) {
196
+ if (!this.isDown) return
197
+ const el = this.$refs.workflowSteps
198
+ if (!el) return
199
+ e.preventDefault()
200
+ const pageX = e.touches ? e.touches[0].pageX : e.pageX
201
+ const x = pageX - el.getBoundingClientRect().left
202
+ const walk = x - this.startX
203
+ el.scrollLeft = this.startScrollLeft - walk
204
+ },
205
+ onDragEnd() {
206
+ const el = this.$refs.workflowSteps
207
+ if (el) el.classList.remove('dragging')
208
+ this.isDown = false
209
+ },
210
+ // scrollPrev/Next & old overflow logic removed (use drag + isCentered)
211
+ /**
212
+ * 更新当前步骤索引(根据已完成步骤数量)
213
+ */
214
+ updateCurrentStepIndex() {
215
+ const steps = this.displaySteps
216
+ // 以 executed 作为已完成判断
217
+ const executedCount = steps.filter(step => step.status === 'executed').length
218
+ this.currentStepIndex = executedCount > 0 ? executedCount - 1 : -1
219
+ },
220
+ /**
221
+ * 按 value 设置指定步骤的状态(只按 value 匹配)
222
+ * @param {String|Number} stepValue - 步骤的 value 字段
223
+ * @param {String} status - 状态:'executed' 或 'not-executed'
224
+ */
225
+ setStepStatus(stepValue, status) {
226
+ const steps = this.displaySteps
227
+ if (!steps || steps.length === 0) {
228
+ console.warn('步骤数据为空,无法设置状态')
229
+ return
230
+ }
231
+
232
+ const asString = `${stepValue}`
233
+ const targetIndex = steps.findIndex(step => `${step.value}` === asString)
234
+ if (targetIndex < 0) {
235
+ console.warn(`未找到对应 value 的步骤: ${stepValue}`)
236
+ return
237
+ }
238
+
239
+ // 仅允许 executed / not-executed
240
+ if (!['executed', 'not-executed'].includes(status)) {
241
+ console.warn(`状态值无效: ${status},应为 'executed' 或 'not-executed'`)
242
+ return
243
+ }
244
+
245
+ // 更新步骤状态
246
+ const step = steps[targetIndex]
247
+ this.$set(step, 'status', status)
248
+
249
+ // 更新当前步骤索引
250
+ this.updateCurrentStepIndex()
251
+
252
+ // 触发状态变更事件
253
+ this.$emit('statusChange', {
254
+ index: targetIndex,
255
+ value: step.value,
256
+ label: step.label,
257
+ status: status,
258
+ steps: [...steps]
259
+ })
260
+ },
261
+ /**
262
+ * 设置当前步骤(自动将之前的步骤设为已完成,当前及之后的设为待处理)
263
+ * @param {Number|String} stepIndexOrLabel - 步骤索引(从0开始)或步骤标签
264
+ */
265
+ /**
266
+ * 以 value 设置当前步骤:指定 value 及之前设为 executed,之后设为 not-executed
267
+ * @param {String|Number} stepValue
268
+ */
269
+ setCurrentStep(stepValue) {
270
+ const steps = this.displaySteps
271
+ if (!steps || steps.length === 0) {
272
+ console.warn('步骤数据为空,无法设置当前步骤')
273
+ return
274
+ }
275
+
276
+ const asString = `${stepValue}`
277
+ const targetIndex = steps.findIndex(step => `${step.value}` === asString)
278
+ if (targetIndex < 0) {
279
+ console.warn(`未找到对应 value 的步骤: ${stepValue}`)
280
+ return
281
+ }
282
+
283
+ // 更新所有步骤状态
284
+ steps.forEach((step, index) => {
285
+ if (index <= targetIndex) {
286
+ // 当前及之前设为 executed
287
+ this.$set(step, 'status', 'executed')
288
+ } else {
289
+ // 之后的设为 not-executed
290
+ this.$set(step, 'status', 'not-executed')
291
+ }
292
+ })
293
+
294
+ // 更新当前步骤索引
295
+ this.currentStepIndex = targetIndex
296
+
297
+ // 触发状态变更事件(已执行)
298
+ this.$emit('statusChange', {
299
+ index: targetIndex,
300
+ label: steps[targetIndex].label,
301
+ status: 'executed',
302
+ steps: [...steps]
303
+ })
304
+ },
305
+ /**
306
+ * 完成下一步(将下一个待处理步骤设为已完成)
307
+ */
308
+ completeNextStep() {
309
+ const steps = this.displaySteps
310
+ if (!steps || steps.length === 0) {
311
+ console.warn('步骤数据为空,无法完成下一步')
312
+ return
313
+ }
314
+
315
+ const nextIndex = steps.findIndex(step => step.status !== 'executed')
316
+ if (nextIndex === -1) {
317
+ console.warn('没有待执行的步骤')
318
+ return
319
+ }
320
+
321
+ this.setCurrentStep(nextIndex)
322
+ },
323
+ /**
324
+ * 重置所有步骤为待处理状态
325
+ */
326
+ resetAllSteps() {
327
+ const steps = this.displaySteps
328
+ if (!steps || steps.length === 0) {
329
+ return
330
+ }
331
+
332
+ steps.forEach(step => {
333
+ this.$set(step, 'status', 'not-executed')
334
+ })
335
+
336
+ this.currentStepIndex = -1
337
+
338
+ // 触发状态变更事件(全部未执行)
339
+ this.$emit('statusChange', {
340
+ index: -1,
341
+ label: '',
342
+ status: 'not-executed',
343
+ steps: [...steps]
344
+ })
345
+ },
346
+ /**
347
+ * 获取当前步骤信息
348
+ * @returns {Object} 当前步骤信息
349
+ */
350
+ getCurrentStep() {
351
+ const steps = this.displaySteps
352
+ if (this.currentStepIndex >= 0 && this.currentStepIndex < steps.length) {
353
+ return {
354
+ index: this.currentStepIndex,
355
+ label: steps[this.currentStepIndex].label,
356
+ status: steps[this.currentStepIndex].status
357
+ }
358
+ }
359
+ return null
360
+ },
361
+ /**
362
+ * 获取所有步骤数据
363
+ * @returns {Array} 步骤数组
364
+ */
365
+ getSteps() {
366
+ return [...this.displaySteps]
367
+ }
368
+ },
369
+ watch: {
370
+ queryParamsName: {
371
+ handler(newVal) {
372
+ if (newVal) {
373
+ this.getData(newVal)
374
+ }
375
+ },
376
+ deep: true
377
+ },
378
+ steps: {
379
+ handler(newVal) {
380
+ if (newVal && newVal.length > 0) {
381
+ this.internalSteps = newVal
382
+ // 更新当前步骤索引
383
+ this.updateCurrentStepIndex()
384
+ }
385
+ },
386
+ deep: true,
387
+ immediate: true
388
+ },
389
+ displaySteps: {
390
+ handler() {
391
+ // 当显示步骤变化时,更新当前步骤索引
392
+ this.updateCurrentStepIndex()
393
+ this.$nextTick(() => {
394
+ if (typeof this.checkOverflow === 'function') this.checkOverflow()
395
+ })
396
+ },
397
+ deep: true
398
+ }
399
+ }
400
+ }
401
+ </script>
402
+
403
+ <style lang="less" scoped>
404
+ .x-workflow-progress {
405
+ width: 100%;
406
+ padding: 0px 0;
407
+
408
+ .workflow-steps-wrapper {
409
+ position: relative;
410
+ display: flex;
411
+ justify-content: center;
412
+ align-items: center;
413
+ }
414
+
415
+ .workflow-steps {
416
+ display: flex;
417
+ align-items: center;
418
+ justify-content: flex-start;
419
+ position: relative;
420
+ overflow-x: auto;
421
+ -webkit-overflow-scrolling: touch;
422
+ white-space: nowrap;
423
+ flex-wrap: nowrap;
424
+ scrollbar-width: none;
425
+ cursor: grab;
426
+ }
427
+ .workflow-steps::-webkit-scrollbar { display: none; }
428
+ .workflow-steps.center {
429
+ justify-content: center;
430
+ }
431
+ .workflow-steps.dragging { cursor: grabbing; user-select: none; }
432
+
433
+ .workflow-step {
434
+ display: flex;
435
+ flex-direction: row;
436
+ align-items: center;
437
+ position: relative;
438
+ flex: 0 0 auto;
439
+ min-width: 0;
440
+
441
+ /* 只保留图标(去掉外层圆圈样式) */
442
+ .step-circle {
443
+ display: flex;
444
+ align-items: center;
445
+ justify-content: center;
446
+ position: relative;
447
+ z-index: 2;
448
+ padding: 0;
449
+ background: transparent;
450
+ border: none;
451
+ transition: all 0.2s;
452
+
453
+ .step-icon {
454
+ font-size: 18px;
455
+ transition: color 0.2s;
456
+ /* 默认灰色,具体颜色由状态覆盖 */
457
+ color: #D8D8D8;
458
+ }
459
+ }
460
+
461
+ /* 完成状态:图标蓝色 */
462
+ &.is-completed {
463
+ .step-circle {
464
+ .step-icon {
465
+ color: #0057FE;
466
+ }
467
+ }
468
+ }
469
+
470
+ /* 待处理状态:图标灰色(继承默认) */
471
+ &.is-pending {
472
+ .step-circle {
473
+ .step-icon {
474
+ color: #D8D8D8;
475
+ }
476
+ }
477
+ }
478
+
479
+ .step-label {
480
+ margin-left: 8px;
481
+ font-size: 16px;
482
+ color: #333;
483
+ text-align: left;
484
+ white-space: nowrap;
485
+ overflow: hidden;
486
+ text-overflow: ellipsis;
487
+ max-width: 160px;
488
+ }
489
+
490
+ /* 连接线:短线,位于徽章右侧,状态完成时变蓝 */
491
+ .step-connector {
492
+ top: 50%;
493
+ margin-left: 10px;
494
+ margin-right: 10px;
495
+ width: 30px;
496
+ height: 1px;
497
+ background: #d9d9d9;
498
+ transform: translateY(-50%);
499
+ transition: background 0.3s;
500
+
501
+ &.is-completed {
502
+ background: #0057FE;
503
+ }
504
+ }
505
+
506
+ // 最后一个步骤不需要连接线
507
+ &:last-child {
508
+ margin-right: 0;
509
+ .step-connector {
510
+ display: none;
511
+ }
512
+ }
513
+ }
514
+ /* (移除导航按钮,支持直接拖动滑动) */
515
+ }
516
+
517
+ // 响应式设计
518
+ @media (max-width: 768px) {
519
+ .x-workflow-progress {
520
+ .workflow-step {
521
+ .step-label {
522
+ font-size: 12px;
523
+ }
524
+
525
+ .step-circle {
526
+ padding: 0 2px;
527
+
528
+ .step-icon {
529
+ font-size: 18px;
530
+ }
531
+ }
532
+ }
533
+ }
534
+ }
535
+ </style>
536
+
@@ -6,7 +6,7 @@ export default {
6
6
  components: { WorkflowDetail },
7
7
  mounted () {
8
8
  this.$refs.workFlow.init({
9
- workflowId: 5958
9
+ workflowId: 4640
10
10
  })
11
11
  },
12
12
  methods: {
@@ -1125,7 +1125,7 @@ export default {
1125
1125
  if (stepDefine.formType === 'select') {
1126
1126
  let dictList
1127
1127
  if (stepDefine.selectType === 'key') {
1128
- dictList = []
1128
+ dictList = await this.$appdata.getDictByKeyAsync(stepDefine.selectKey)
1129
1129
  } else if (stepDefine.selectType === 'config') {
1130
1130
  const configName = stepDefine.selectKey.substring(7)
1131
1131
  dictList = await this.$appdata.getDictByKeyAsync(configName)
@@ -787,7 +787,7 @@ export default {
787
787
  if (stepDefine.formType === 'select') {
788
788
  let dictList
789
789
  if (stepDefine.selectType === 'key') {
790
- dictList = []
790
+ dictList = await this.$appdata.getDictByKeyAsync(stepDefine.selectKey)
791
791
  } else if (stepDefine.selectType === 'config') {
792
792
  const configName = stepDefine.selectKey.substring(7)
793
793
  dictList = await this.$appdata.getDictByKeyAsync(configName)
@@ -61,8 +61,8 @@ routerResource.example = {
61
61
  // component: () => import('@vue2-client/pages/WorkflowDetail/WorkFlowDemo.vue'),
62
62
  // component: () => import('@vue2-client/pages/addressSelect/addressDemo.vue'),
63
63
  // component: () => import('@vue2-client/base-client/components/common/XDescriptions/demo.vue'),
64
- component: () => import('@vue2-client/base-client/components/common/XAddNativeForm/demo.vue')
65
- // component: () => import('@vue2-client/base-client/components/common/XFormGroup/demo.vue')
64
+ // component: () => import('@vue2-client/base-client/components/common/XAddNativeForm/demo.vue')
65
+ component: () => import('@vue2-client/base-client/components/common/XFormGroup/demo.vue')
66
66
  // component: () => import('@vue2-client/base-client/components/common/XReport/XReportDemo.vue'),
67
67
  // component: () => import('@vue2-client/base-client/components/common/XReportGrid/XReportDemo.vue'),
68
68
  // component: () => import('@vue2-client/base-client/components/common/HIS/demo.vue'),
package/tests/unit/a.log DELETED
File without changes