vue2-client 1.18.22 → 1.18.24

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 (108) hide show
  1. package/.eslintrc.js +90 -90
  2. package/Components.md +60 -60
  3. package/docs/index.md +30 -30
  4. package/index.js +31 -31
  5. package/jest-transform-stub.js +8 -8
  6. package/jest.setup.js +7 -7
  7. package/package.json +1 -1
  8. package/src/assets/img/querySlotDemo.svg +15 -15
  9. package/src/assets/svg/female.svg +1 -1
  10. package/src/assets/svg/male.svg +1 -1
  11. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  12. package/src/base-client/components/common/CitySelect/index.js +3 -3
  13. package/src/base-client/components/common/CitySelect/index.md +109 -109
  14. package/src/base-client/components/common/CreateQuery/CreateQuery.vue +669 -669
  15. package/src/base-client/components/common/CreateQuery/index.js +3 -3
  16. package/src/base-client/components/common/CreateQuery/index.md +42 -42
  17. package/src/base-client/components/common/CreateSimpleFormQuery/index.js +3 -3
  18. package/src/base-client/components/common/CreateSimpleFormQuery/index.md +42 -42
  19. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  20. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  21. package/src/base-client/components/common/FormGroupQuery/FormGroupQuery.vue +166 -166
  22. package/src/base-client/components/common/FormGroupQuery/index.js +3 -3
  23. package/src/base-client/components/common/FormGroupQuery/index.md +43 -43
  24. package/src/base-client/components/common/HIS/HButtons/HButtons.vue +491 -491
  25. package/src/base-client/components/common/HIS/HFormGroup/index.js +3 -3
  26. package/src/base-client/components/common/HIS/HTab/HTab.vue +443 -443
  27. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  28. package/src/base-client/components/common/PersonSetting/PersonSetting.vue +208 -208
  29. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  30. package/src/base-client/components/common/Tree/Tree.vue +149 -149
  31. package/src/base-client/components/common/Tree/index.js +2 -2
  32. package/src/base-client/components/common/Upload/index.js +3 -3
  33. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  34. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  35. package/src/base-client/components/common/XCollapse/XCollapse.vue +830 -830
  36. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  37. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  38. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  39. package/src/base-client/components/common/XDescriptions/XDescriptionsGroup.vue +344 -137
  40. package/src/base-client/components/common/XDescriptions/demo.vue +89 -10
  41. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  42. package/src/base-client/components/common/XDescriptions/index.md +322 -83
  43. package/src/base-client/components/common/XForm/index.md +178 -178
  44. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  45. package/src/base-client/components/common/XStepView/index.js +3 -3
  46. package/src/base-client/components/common/XStepView/index.md +31 -31
  47. package/src/base-client/components/common/XTable/index.md +255 -255
  48. package/src/base-client/components/common/XTimeline/XTimeline.vue +477 -477
  49. package/src/base-client/components/his/HChart/HChart.vue +311 -16
  50. package/src/base-client/components/his/XHisEditor/XHisEditor.vue +705 -705
  51. package/src/base-client/components/his/XList/XList.vue +938 -938
  52. package/src/base-client/components/his/XTimeSelect/XTimeSelect.vue +354 -354
  53. package/src/base-client/components/his/XTitle/XTitle.vue +314 -314
  54. package/src/base-client/components/his/XTreeRows/XTreeRows.vue +341 -341
  55. package/src/base-client/components/his/threeTestOrders/editor.vue +113 -113
  56. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  57. package/src/base-client/plugins/Config.js +19 -19
  58. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  59. package/src/components/Charts/Bar.vue +62 -62
  60. package/src/components/Charts/ChartCard.vue +134 -134
  61. package/src/components/Charts/Liquid.vue +67 -67
  62. package/src/components/Charts/MiniArea.vue +39 -39
  63. package/src/components/Charts/MiniBar.vue +39 -39
  64. package/src/components/Charts/MiniProgress.vue +75 -75
  65. package/src/components/Charts/MiniSmoothArea.vue +40 -40
  66. package/src/components/Charts/Radar.vue +68 -68
  67. package/src/components/Charts/RankList.vue +77 -77
  68. package/src/components/Charts/TagCloud.vue +113 -113
  69. package/src/components/Charts/TransferBar.vue +64 -64
  70. package/src/components/Charts/Trend.vue +82 -82
  71. package/src/components/Charts/chart.less +12 -12
  72. package/src/components/Charts/smooth.area.less +13 -13
  73. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  74. package/src/components/NumberInfo/index.js +3 -3
  75. package/src/components/NumberInfo/index.less +54 -54
  76. package/src/components/NumberInfo/index.md +43 -43
  77. package/src/components/card/ChartCard.vue +79 -79
  78. package/src/components/chart/Bar.vue +60 -60
  79. package/src/components/chart/MiniArea.vue +67 -67
  80. package/src/components/chart/MiniBar.vue +59 -59
  81. package/src/components/chart/MiniProgress.vue +57 -57
  82. package/src/components/chart/Radar.vue +80 -80
  83. package/src/components/chart/RankingList.vue +60 -60
  84. package/src/components/chart/Trend.vue +79 -79
  85. package/src/components/chart/index.less +9 -9
  86. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  87. package/src/components/input/IInput.vue +66 -66
  88. package/src/components/menu/SideMenu.vue +75 -75
  89. package/src/components/menu/menu.js +273 -273
  90. package/src/components/tool/AStepItem.vue +60 -60
  91. package/src/layouts/CommonLayout.vue +56 -56
  92. package/src/layouts/header/HeaderNotice.vue +177 -177
  93. package/src/lib.js +1 -1
  94. package/src/mock/extend/index.js +84 -84
  95. package/src/mock/goods/index.js +108 -108
  96. package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
  97. package/src/pages/system/dictionary/index.vue +44 -44
  98. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  99. package/src/pages/system/monitor/operLog/index.vue +37 -37
  100. package/src/pages/userInfoDetailManage/ExceptionRecordQuery/index.vue +45 -45
  101. package/src/router/async/router.map.js +2 -1
  102. package/src/services/api/cas.js +79 -79
  103. package/src/store/modules/setting.js +119 -119
  104. package/src/utils/authority-utils.js +85 -85
  105. package/src/utils/errorCode.js +6 -6
  106. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
  107. package/src-base-client/components/common/HIS/HForm/HForm.vue +0 -347
  108. package/src-base-client/components/common/XCollapse/XCollapse.vue +0 -0
@@ -1,63 +1,177 @@
1
1
  <template>
2
2
  <a-row id="XDescriptionGroup" :gutter="24">
3
- <a-col :span="4" v-if="showLeftTab && realData.length">
4
- <a-tabs tab-position="left" v-model="activeTab" @change="scrollToGroup">
5
- <template v-for="(item,index) in realData">
6
- <a-tab-pane
7
- :tab="item.title"
8
- :key="index"
9
- v-if="item.title">
10
- </a-tab-pane>
11
- </template>
12
- </a-tabs>
13
- </a-col>
14
- <a-col :span="showLeftTab ? 20 : 24" ref="descriptionsGroupContext" class="descriptionsGroupContext">
15
- <div
16
- class="descriptions-item"
17
- :ref="`descriptions-item-${realDataIndex}`"
18
- :key="realDataIndex"
19
- v-for="(realDataItem, realDataIndex) in realData">
20
- <template v-if="!loadError">
21
- <!-- 带有子的详情 -->
22
- <template
23
- v-if="realDataItem.title && groups[realDataIndex]?.type ==='array'"
24
- >
25
- <div class="ant-descriptions-title">{{ realDataItem.title }}</div>
26
- <div class="descriptions-array-item">
27
- <a-descriptions
28
- v-for="(arrayItem,arrayIndex) in realDataItem.column"
29
- :column="isMobile ? 1 : column"
30
- size="small"
31
- :key="arrayIndex"
32
- :title="arrayItem.title">
33
- {{ arrayItem }}
34
- <template v-for="(item, index) in arrayItem.column">
35
- <!-- 大多数情况 循环下 空值省略不展示,todo 后期可能加配置处理 -->
3
+ <!-- left 模式:左侧导航 + 右侧内容 -->
4
+ <template v-if="tabMode === 'left'">
5
+ <a-col :span="4" v-if="realData.length">
6
+ <a-tabs tab-position="left" v-model="activeTab" @change="scrollToGroup">
7
+ <template v-for="(item,index) in realData">
8
+ <a-tab-pane
9
+ :tab="item.title"
10
+ :key="index"
11
+ v-if="item.title">
12
+ </a-tab-pane>
13
+ </template>
14
+ </a-tabs>
15
+ </a-col>
16
+ <a-col :span="realData.length ? 20 : 24" ref="descriptionsGroupContext" class="descriptionsGroupContext">
17
+ <div
18
+ class="descriptions-item"
19
+ :ref="`descriptions-item-${realDataIndex}`"
20
+ :key="realDataIndex"
21
+ v-for="(realDataItem, realDataIndex) in realData">
22
+ <!-- 渲染所有分组内容 -->
23
+ <template v-if="!loadError">
24
+ <!-- 带有子的详情 -->
25
+ <template
26
+ v-if="realDataItem.title && groups[realDataIndex]?.type ==='array'"
27
+ >
28
+ <div class="ant-descriptions-title">{{ realDataItem.title }}</div>
29
+ <div class="descriptions-array-item">
30
+ <a-descriptions
31
+ v-for="(arrayItem,arrayIndex) in realDataItem.column"
32
+ :column="isMobile ? 1 : column"
33
+ size="small"
34
+ :key="arrayIndex"
35
+ :title="arrayItem.title">
36
+ <template v-for="(item, index) in arrayItem.column">
37
+ <!-- 大多数情况 循环下 空值省略不展示,todo 后期可能加配置处理 -->
38
+ <a-descriptions-item
39
+ :key="index"
40
+ v-if="item.value"
41
+ :label="item.key">
42
+ {{ formatText(item.value) }}
43
+ </a-descriptions-item>
44
+ </template>
45
+ </a-descriptions>
46
+ </div>
47
+ </template>
48
+ <a-descriptions
49
+ v-else-if="realDataItem.title"
50
+ :column="isMobile ? 1 : column"
51
+ :title="realDataItem.title">
52
+ <a-descriptions-item
53
+ v-for="(item, index) in realDataItem.column"
54
+ :key="index"
55
+ :span="item.span || 1"
56
+ v-if="shouldShowField(item, data)">
57
+ <template #label>
58
+ {{ item.key }}
59
+ <span v-if="isFieldRequired(item, data)" style="color: red;"> *</span>
60
+ </template>
61
+ <span :style="getFieldStyle(item, data)">{{ formatFieldValue(item.value, item, data) || '--' }}</span>
62
+ </a-descriptions-item>
63
+ </a-descriptions>
64
+ </template>
65
+ </div>
66
+ </a-col>
67
+ </template>
68
+
69
+ <!-- top 模式:顶部横向 tab -->
70
+ <template v-else-if="tabMode === 'top'">
71
+ <a-col :span="24" v-if="realData.length">
72
+ <a-tabs v-model="activeTab" size="small" :tabBarStyle="{ margin: 0, padding: '0 8px' }">
73
+ <a-tab-pane v-for="(item,index) in realData" :key="index" :tab="item.title">
74
+ <div class="tab-content-scroll">
75
+ <!-- 只渲染当前激活的分组内容 -->
76
+ <template v-if="!loadError && realData[activeTab]">
77
+ <!-- 带有子的详情 -->
78
+ <template
79
+ v-if="realData[activeTab].title && groups[activeTab]?.type ==='array'"
80
+ >
81
+ <div class="ant-descriptions-title" v-if="tabMode !== 'top'">{{ realData[activeTab].title }}</div>
82
+ <div class="descriptions-array-item">
83
+ <a-descriptions
84
+ v-for="(arrayItem,arrayIndex) in realData[activeTab].column"
85
+ :column="isMobile ? 1 : column"
86
+ size="small"
87
+ :key="arrayIndex"
88
+ :title="arrayItem.title">
89
+ <template v-for="(fieldItem, fieldIndex) in arrayItem.column">
90
+ <a-descriptions-item
91
+ :key="fieldIndex"
92
+ v-if="fieldItem.value"
93
+ :label="fieldItem.key">
94
+ {{ formatText(fieldItem.value) }}
95
+ </a-descriptions-item>
96
+ </template>
97
+ </a-descriptions>
98
+ </div>
99
+ </template>
100
+ <a-descriptions
101
+ v-else-if="realData[activeTab].title"
102
+ :column="isMobile ? 1 : column"
103
+ :title="tabMode === 'top' ? undefined : realData[activeTab].title">
36
104
  <a-descriptions-item
37
- :key="index"
38
- v-if="item.value"
39
- :label="item.key">
40
- {{ formatText(item.value) }}
105
+ v-for="(fieldItem, fieldIndex) in realData[activeTab].column"
106
+ :key="fieldIndex"
107
+ :span="fieldItem.span || 1"
108
+ v-if="shouldShowField(fieldItem, data)">
109
+ <template #label>
110
+ {{ fieldItem.key }}
111
+ <span v-if="isFieldRequired(fieldItem, data)" style="color: red;"> *</span>
112
+ </template>
113
+ <span :style="getFieldStyle(fieldItem, fieldItem.value, data)">{{ formatFieldValue(fieldItem.value, fieldItem, data) || '--' }}</span>
41
114
  </a-descriptions-item>
42
- </template>
43
- </a-descriptions>
115
+ </a-descriptions>
116
+ </template>
44
117
  </div>
118
+ </a-tab-pane>
119
+ </a-tabs>
120
+ </a-col>
121
+ </template>
122
+
123
+ <!-- none 模式:无 tab,直接展示所有内容 -->
124
+ <template v-else>
125
+ <a-col :span="24" class="descriptionsGroupContext">
126
+ <div
127
+ class="descriptions-item"
128
+ :key="realDataIndex"
129
+ v-for="(realDataItem, realDataIndex) in realData">
130
+ <!-- 渲染所有分组内容 -->
131
+ <template v-if="!loadError">
132
+ <!-- 带有子的详情 -->
133
+ <template
134
+ v-if="realDataItem.title && groups[realDataIndex]?.type ==='array'"
135
+ >
136
+ <div class="ant-descriptions-title">{{ realDataItem.title }}</div>
137
+ <div class="descriptions-array-item">
138
+ <a-descriptions
139
+ v-for="(arrayItem,arrayIndex) in realDataItem.column"
140
+ :column="isMobile ? 1 : column"
141
+ size="small"
142
+ :key="arrayIndex"
143
+ :title="arrayItem.title">
144
+ <template v-for="(item, index) in arrayItem.column">
145
+ <a-descriptions-item
146
+ :key="index"
147
+ v-if="item.value"
148
+ :label="item.key">
149
+ {{ formatText(item.value) }}
150
+ </a-descriptions-item>
151
+ </template>
152
+ </a-descriptions>
153
+ </div>
154
+ </template>
155
+ <a-descriptions
156
+ v-else-if="realDataItem.title"
157
+ :column="isMobile ? 1 : column"
158
+ :title="realDataItem.title">
159
+ <a-descriptions-item
160
+ v-for="(item, index) in realDataItem.column"
161
+ :key="index"
162
+ :span="item.span || 1"
163
+ v-if="shouldShowField(item, data)">
164
+ <template #label>
165
+ {{ item.key }}
166
+ <span v-if="isFieldRequired(item, data)" style="color: red;"> *</span>
167
+ </template>
168
+ <span :style="getFieldStyle(item, item.value, data)">{{ formatFieldValue(item.value, item, data) || '--' }}</span>
169
+ </a-descriptions-item>
170
+ </a-descriptions>
45
171
  </template>
46
- <a-descriptions
47
- v-else-if="realDataItem.title"
48
- :column="isMobile ? 1 : column"
49
- :title="realDataItem.title">
50
- <a-descriptions-item
51
- v-for="(item, index) in realDataItem.column"
52
- :key="index"
53
- :span="item.span || 1"
54
- :label="item.key">
55
- <nobr>{{ item.value || '--' }}</nobr>
56
- </a-descriptions-item>
57
- </a-descriptions>
58
- </template>
59
- </div>
60
- </a-col>
172
+ </div>
173
+ </a-col>
174
+ </template>
61
175
  </a-row>
62
176
  </template>
63
177
  <script>
@@ -65,6 +179,7 @@
65
179
  import { mapState } from 'vuex'
66
180
  import { getRealKeyData } from '@vue2-client/utils/formatter'
67
181
  import { getConfigByName } from '@vue2-client/services/api/common'
182
+ import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
68
183
  import XAddNativeForm from '@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'
69
184
 
70
185
  export default {
@@ -79,40 +194,6 @@ export default {
79
194
  required: true,
80
195
  default: undefined
81
196
  },
82
- // 展示列配置 格式 {title:[{key,name}]} {描述列表标题:[{字段名,字段中文名}]}
83
- // {
84
- // "groups": {
85
- // "表具信息": {
86
- // "f_gasbrand": "气表品牌"
87
- // },
88
- // "客户信息": {
89
- // "f_userinfo_code": "用户编号"
90
- // },
91
- // "设备信息":{
92
- // "type": "array",
93
- // "value": {
94
- // "f_devices_num": "设备数量",
95
- // "f_devices_type": "设备类型",
96
- // },
97
- // "key": "devices"
98
- // }
99
- // }
100
- // }
101
- // 数据模式结构
102
- // "groups": [{
103
- // "name": "客户信息",
104
- // "fields": [
105
- // {
106
- // "name": "备注",
107
- // "key": "f_comments",
108
- // "span": 3
109
- // },
110
- // {
111
- // "name": "地址",
112
- // "key": "f_address",
113
- // "span": 3
114
- // }]
115
- // }]
116
197
  configName: {
117
198
  type: String,
118
199
  required: true,
@@ -123,22 +204,7 @@ export default {
123
204
  type: String,
124
205
  default: process.env.VUE_APP_SYSTEM_NAME
125
206
  },
126
- // 每列显示数量
127
- column: {
128
- type: Number,
129
- default: 3
130
- },
131
- // 处理 key tuf_f_userinfo_id -> f_userinfo_id
132
- getRealData: {
133
- type: Boolean,
134
- default: false
135
- },
136
- // 是否展示左侧tab
137
- showLeftTab: {
138
- type: Boolean,
139
- default: false
140
- }
141
- },
207
+ },
142
208
  mounted () {
143
209
  },
144
210
  beforeDestroy () {
@@ -158,7 +224,11 @@ export default {
158
224
  realData: [],
159
225
  // 获取到的配置组
160
226
  groups: {},
161
- activeTab: 0
227
+ activeTab: 0,
228
+ // 从配置中获取的值
229
+ column: 3, // 默认值
230
+ getRealData: false, // 默认值
231
+ tabMode: 'left', // 默认值
162
232
  }
163
233
  },
164
234
  computed: {
@@ -169,12 +239,15 @@ export default {
169
239
  this.loading = true
170
240
  if (this.configName) {
171
241
  this.getConfig()
172
- this.$nextTick(() => {
173
- const formGroupContext = this.$refs.descriptionsGroupContext?.$el
174
- if (formGroupContext && formGroupContext.addEventListener) {
175
- formGroupContext.addEventListener('scroll', this.onScroll)
176
- }
177
- })
242
+ // 只在 left 模式启用滚动监听
243
+ if (this.tabMode === 'left') {
244
+ this.$nextTick(() => {
245
+ const formGroupContext = this.$refs.descriptionsGroupContext?.$el
246
+ if (formGroupContext && formGroupContext.addEventListener) {
247
+ formGroupContext.addEventListener('scroll', this.onScroll)
248
+ }
249
+ })
250
+ }
178
251
  } else {
179
252
  this.loading = false
180
253
  this.loadError = true
@@ -189,32 +262,13 @@ export default {
189
262
  getConfig () {
190
263
  getConfigByName(this.configName, this.serviceName, (res) => {
191
264
  if (res.groups) {
192
- const groups = Array.isArray(res.groups)
193
- ? res.groups
194
- : Object.entries(res.groups).map(([groupName, groupConfig]) => {
195
- if (groupConfig.type === 'array') {
196
- return {
197
- name: groupName,
198
- type: 'array',
199
- key: groupConfig.key,
200
- fields: Object.entries(groupConfig.value || {}).map(([k, v]) => ({
201
- key: k,
202
- name: v
203
- }))
204
- }
205
- }
206
-
207
- // 处理普通旧格式配置
208
- return {
209
- name: groupName,
210
- fields: Object.entries(groupConfig).map(([fieldKey, fieldValue]) => ({
211
- key: fieldKey,
212
- name: typeof fieldValue === 'string' ? fieldValue : fieldValue.name,
213
- ...(typeof fieldValue === 'object' ? fieldValue : {})
214
- }))
215
- }
216
- })
265
+ // 从配置中获取 column、getRealData 和 tabMode
266
+ this.column = res.column !== undefined ? res.column : 3
267
+ this.getRealData = res.getRealData !== undefined ? res.getRealData : false
268
+ this.tabMode = res.tabMode !== undefined ? res.tabMode : 'left'
217
269
 
270
+ // 解析分组配置
271
+ const groups = this.parseGroupsConfig(res.groups)
218
272
  this.groups = groups
219
273
  this.realData = groups.map(group => {
220
274
  const dataItem = { title: group.name }
@@ -233,7 +287,12 @@ export default {
233
287
  dataItem.column = group.fields.map(field => ({
234
288
  key: field.name,
235
289
  value: this.getRealKeyData(this.data, field.key),
236
- span: field.span
290
+ span: field.span,
291
+ // 存储字段函数配置
292
+ showIf: field.showIf,
293
+ styleFunc: field.styleFunc,
294
+ formatFunc: field.formatFunc,
295
+ requireFunc: field.requireFunc
237
296
  }))
238
297
  }
239
298
 
@@ -242,10 +301,142 @@ export default {
242
301
  }
243
302
  })
244
303
  },
304
+ /**
305
+ * 解析分组配置数据,支持新旧两种配置格式
306
+ * @param {Object|Array} groupsConfig - 分组配置对象或数组
307
+ * @returns {Array} 解析后的分组数组
308
+ *
309
+ * 配置格式说明:
310
+ *
311
+ * 旧模式 - 对象格式 (Object):
312
+ * {
313
+ * "表具信息": {
314
+ * "f_gasbrand": "气表品牌", // 简单字段配置
315
+ * "f_meter_type": "表具类型"
316
+ * },
317
+ * "设备信息": {
318
+ * "type": "array", // 数组类型标识
319
+ * "key": "devices", // type为array时必填:数据源key
320
+ * "value": { // type为array时的字段配置
321
+ * "f_devices_num": "设备数量",
322
+ * "f_devices_type": "设备类型"
323
+ * }
324
+ * },
325
+ * "客户信息": {
326
+ * "f_user_code": { // 字段可配置为对象
327
+ * "name": "用户编号",
328
+ * "span": 2 // 可选:列跨度
329
+ * },
330
+ * "f_user_name": "用户姓名" // 简单字段配置
331
+ * }
332
+ * }
333
+ *
334
+ * 新模式 - 数组格式 (Array):
335
+ * [{
336
+ * "name": "客户信息",
337
+ * "fields": [
338
+ * {
339
+ * "name": "用户编号",
340
+ * "key": "f_user_code",
341
+ * "span": 3
342
+ * }
343
+ * ]
344
+ * }, {
345
+ * "name": "设备信息",
346
+ * "type": "array", // 数组类型标识
347
+ * "key": "devices", // type为array时必填:数据源key
348
+ * "fields": [
349
+ * {
350
+ * "name": "设备数量",
351
+ * "key": "f_devices_num"
352
+ * },
353
+ * {
354
+ * "name": "设备类型",
355
+ * "key": "f_devices_type"
356
+ * }
357
+ * ]
358
+ * }]
359
+ */
360
+ parseGroupsConfig (groupsConfig) {
361
+ // 如果已经是数组格式,直接返回
362
+ if (Array.isArray(groupsConfig)) {
363
+ return groupsConfig
364
+ }
365
+
366
+ // 解析对象格式配置
367
+ return Object.entries(groupsConfig).map(([groupName, groupConfig]) => {
368
+ // 处理数组类型的配置
369
+ if (groupConfig.type === 'array') {
370
+ return {
371
+ name: groupName,
372
+ type: 'array',
373
+ key: groupConfig.key,
374
+ fields: Object.entries(groupConfig.value || {}).map(([k, v]) => ({
375
+ key: k,
376
+ name: v
377
+ }))
378
+ }
379
+ }
380
+
381
+ // 处理普通配置(支持新旧格式)
382
+ return {
383
+ name: groupName,
384
+ fields: Object.entries(groupConfig).map(([fieldKey, fieldValue]) => ({
385
+ key: fieldKey,
386
+ name: typeof fieldValue === 'string' ? fieldValue : fieldValue.name,
387
+ showIf: typeof fieldValue === 'object' ? fieldValue.showIf : undefined,
388
+ styleFunc: typeof fieldValue === 'object' ? fieldValue.styleFunc : undefined,
389
+ formatFunc: typeof fieldValue === 'object' ? fieldValue.formatFunc : undefined,
390
+ requireFunc: typeof fieldValue === 'object' ? fieldValue.requireFunc : undefined,
391
+ ...(typeof fieldValue === 'object' ? fieldValue : {})
392
+ }))
393
+ }
394
+ })
395
+ },
245
396
  // 文字格式化
246
397
  formatText (value) {
247
398
  return value ?? '--'
248
399
  },
400
+ // 执行字段展示函数
401
+ shouldShowField (field, data) {
402
+ if (!field.showIf) return true
403
+ try {
404
+ return executeStrFunctionByContext(this, field.showIf, [data, field.key])
405
+ } catch (error) {
406
+ console.warn('showIf 函数执行错误:', error)
407
+ return true
408
+ }
409
+ },
410
+ // 获取字段样式
411
+ getFieldStyle (field, data) {
412
+ if (!field.styleFunc) return {}
413
+ try {
414
+ return executeStrFunctionByContext(this, field.styleFunc, [data, field.key])
415
+ } catch (error) {
416
+ console.warn('styleFunc 函数执行错误:', error)
417
+ return {}
418
+ }
419
+ },
420
+ // 格式化字段值
421
+ formatFieldValue (value, field, data) {
422
+ if (!field.formatFunc) return value
423
+ try {
424
+ return executeStrFunctionByContext(this, field.formatFunc, [data, field.key])
425
+ } catch (error) {
426
+ console.warn('formatFunc 函数执行错误:', error)
427
+ return value
428
+ }
429
+ },
430
+ // 判断字段是否必填(显示红色星号)
431
+ isFieldRequired (field, data) {
432
+ if (!field.requireFunc) return false
433
+ try {
434
+ return executeStrFunctionByContext(this, field.requireFunc, [data, field.key])
435
+ } catch (error) {
436
+ console.warn('requireFunc 函数执行错误:', error)
437
+ return false
438
+ }
439
+ },
249
440
  getRealKeyData (data, key) {
250
441
  if (this.getRealData) {
251
442
  return getRealKeyData(data)[key] || ''
@@ -254,6 +445,9 @@ export default {
254
445
  }
255
446
  },
256
447
  onScroll () {
448
+ // 只在 left 模式启用滚动联动
449
+ if (this.tabMode !== 'left') return
450
+
257
451
  const formGroupContext = this.$refs.descriptionsGroupContext.$el
258
452
  let groupItems = []
259
453
  if (formGroupContext && formGroupContext.querySelectorAll) {
@@ -310,5 +504,18 @@ export default {
310
504
  height: 100%;
311
505
  overflow-y: scroll;
312
506
  }
507
+
508
+ // top 模式样式
509
+ .tab-content-scroll {
510
+ overflow-y: auto;
511
+ padding: 8px;
512
+ }
513
+
514
+ // none 模式:移除分组间距
515
+ &:has(.tabMode-none) {
516
+ .descriptions-item {
517
+ margin-bottom: 4px;
518
+ }
519
+ }
313
520
  }
314
521
  </style>
@@ -8,10 +8,73 @@ export default {
8
8
  return {
9
9
  visible: false,
10
10
  userinfo: {
11
- f_userinfo_code: '143400000003',
12
- f_gasbrand: '测试表品牌',
13
- f_address: '11'
14
- }
11
+ f_userinfo_id: '1003',
12
+ f_user_id: 'U20230003',
13
+ f_userfiles_id: 'F20230003',
14
+
15
+ f_userinfo_code: '2023001236',
16
+ f_user_name: '王五',
17
+ f_name_pinyin: 'WW',
18
+ f_user_type: '商业用户',
19
+ f_balance: -250.00,
20
+ f_project_money: 0,
21
+ f_gas_type: '',
22
+ f_sys_balance: 0,
23
+ f_idnumber: '610104197801011234',
24
+ f_user_phone: '13500135000',
25
+ f_rent_phone: '',
26
+ f_user_state: '欠费',
27
+ f_comments: '欠费待催缴',
28
+ f_address: '陕西省西安市碑林区南关正街88号1层商铺',
29
+ f_open_date: '2015-09-20 14:00:00',
30
+ f_install_date: '2015-09-25 10:30:00',
31
+ f_people_num: 0,
32
+ f_user_level: 'C级',
33
+ f_olduserinfo_code: 'OLD2010001236',
34
+ f_contract_id: 'HT2015092000136',
35
+
36
+ f_customer: '',
37
+ f_meter_type: '机表',
38
+ f_meter_brand: '威星智能',
39
+ f_meter_style: 'WX-G10',
40
+ f_calculation: '',
41
+ f_collection_type: '',
42
+ f_table_state: '正常',
43
+ f_balance_amount: 0,
44
+ f_balance_gas: 0,
45
+ f_jval: 0,
46
+ f_arrears_fee: 250.00,
47
+ f_initial_base: 0,
48
+ f_meter_base: 15680.5,
49
+ f_times: 0,
50
+ f_iot_times: 0,
51
+ f_total_fee: 0,
52
+ f_total_fee_all: 0,
53
+ f_deduction_gas: 50.5,
54
+ f_total_gas_all: 0,
55
+ f_total_gas: 0,
56
+ f_write_totalfee: 0,
57
+ f_meternumber: 'WX2015090012345',
58
+ f_card_id: '',
59
+ f_hascard: '否',
60
+ f_metertitles: 'BF2015001236',
61
+ f_gasproperties: '商业用气',
62
+ f_price_name: '商业用气价格',
63
+ f_remanent_money: 150.00,
64
+ f_remanent_gas: 0,
65
+ f_aroundmeter: '南向',
66
+ f_book_name: '碑林区商业册',
67
+ f_book_code: 'BL-SY-01',
68
+ f_meter_book_sort: '45',
69
+ f_position: '门面房',
70
+ f_gas_person: '赵师傅',
71
+ f_gas_date: '2015-09-25 11:00:00',
72
+ f_inputtor: '孙抄表',
73
+ f_hand_date: '2024-01-10 09:00:00',
74
+ f_input_date: '2015-09-20 14:00:00',
75
+ comments: '商业用户,需要定期催缴'
76
+ }
77
+
15
78
  }
16
79
  },
17
80
  methods: {
@@ -30,18 +93,34 @@ export default {
30
93
 
31
94
  <template>
32
95
  <div>
33
- <a-button @click="open">
34
- 展开详情
35
- </a-button>
96
+ <a-space style="margin-bottom: 16px;">
97
+ <a-button @click="open">
98
+ 弹出式展示
99
+ </a-button>
100
+ </a-space>
101
+
102
+ <!-- 卡片展示 -->
103
+ <a-card title="卡片展示" style="width: 300px;" size="small">
104
+ <x-descriptions-group
105
+ config-name="ChargeCenterUserDetailConfig"
106
+ :data="userinfo"
107
+ service-name="af-revenue"
108
+ />
109
+ </a-card>
110
+
111
+ <!-- 弹出式展示 -->
36
112
  <a-drawer
37
- title="描述列表详情"
113
+ title="弹出式展示"
38
114
  placement="right"
39
115
  width="65vw"
40
- :body-style="{height:'92%'}"
41
116
  :visible="visible"
42
117
  @close="()=>{visible = false}"
43
118
  >
44
- <x-descriptions-group config-name="测试Config" :showLeftTab="true" :data="userinfo" service-name="af-system"/>
119
+ <x-descriptions-group
120
+ config-name="ChargeCenterUserDetailConfig"
121
+ :data="userinfo"
122
+ service-name="af-revenue"
123
+ />
45
124
  </a-drawer>
46
125
  </div>
47
126
  </template>