vue2-client 1.22.2 → 1.22.3

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 (170) hide show
  1. package/.claude/settings.local.json +30 -30
  2. package/.env.his +19 -19
  3. package/.eslintrc.js +74 -74
  4. package/.history/.eslintrc_20260521171150.js +74 -0
  5. package/.history/.eslintrc_20260521171213.js +74 -0
  6. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154443.vue +726 -0
  7. package/.history/src/base-client/components/common/HIS/HAddNativeForm/HAddNativeForm_20260601154700.vue +478 -0
  8. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175435.vue +706 -0
  9. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260512175450.vue +694 -0
  10. package/.history/src/base-client/components/common/HIS/HButtons/HButtons_20260611152602.vue +755 -0
  11. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513145941.vue +524 -0
  12. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513153133.vue +731 -0
  13. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260513160316.vue +525 -0
  14. package/.history/src/base-client/components/common/HIS/HForm/HForm_20260601144150.vue +1046 -0
  15. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310142713.vue +512 -0
  16. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260310145118.vue +511 -0
  17. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260311094834.vue +696 -0
  18. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260320143028.vue +693 -0
  19. package/.history/src/base-client/components/common/HIS/HFormTable/HFormTable_20260409101450.vue +677 -0
  20. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164645.vue +758 -0
  21. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508164714.vue +693 -0
  22. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260508171651.vue +716 -0
  23. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509133717.vue +695 -0
  24. package/.history/src/base-client/components/common/HIS/HTab/HTab_20260509171115.vue +664 -0
  25. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140637.vue +1455 -0
  26. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513140935.vue +1441 -0
  27. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513150818.vue +1441 -0
  28. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153119.vue +1442 -0
  29. package/.history/src/base-client/components/common/XAddNativeForm/XAddNativeForm_20260513153126.vue +1486 -0
  30. package/.history/src/base-client/components/common/XForm/XFormItem_20260513140854.vue +1607 -0
  31. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140403.vue +643 -0
  32. package/.history/src/base-client/components/common/XMarkdownViewer/XMarkdownViewer_20260519140829.vue +628 -0
  33. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519142824.vue +104 -0
  34. package/.history/src/base-client/components/common/XMarkdownViewer/demo_20260519143155.vue +102 -0
  35. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171231.vue +1241 -0
  36. package/.history/src/base-client/components/common/XReportGrid/XReport_20260309171441.vue +1223 -0
  37. package/.history/src/base-client/components/his/HAi/HAi_20260612174826.vue +472 -0
  38. package/.history/src/base-client/components/his/HAi/HAi_20260612175839.vue +538 -0
  39. package/.history/src/base-client/components/his/HAi/HAi_20260615103331.vue +650 -0
  40. package/.history/src/base-client/components/his/XHDescriptions/XHDescriptions_20260424134504.vue +1469 -0
  41. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171133.vue +788 -0
  42. package/.history/src/base-client/components/his/XSidebar/XSidebar_20260610171151.vue +780 -0
  43. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511170841.vue +585 -0
  44. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260511171138.vue +787 -0
  45. package/.history/src/base-client/components/his/XTransfer/XTransfer_20260512141830.vue +739 -0
  46. package/.history/src/components/STable/index_20260409155138.js +806 -0
  47. package/.history/src/components/STable/index_20260409155218.js +814 -0
  48. package/.history/src/expression/core/Expression_20260305164427.js +1371 -0
  49. package/.history/src/expression/core/Expression_20260305170258.js +1358 -0
  50. package/.history/src/expression/core/Program_20260305111830.js +944 -0
  51. package/.history/src/expression/core/Program_20260305112041.js +931 -0
  52. package/.history/src/logic/LogicRunner_20260304154306.js +170 -0
  53. package/.history/src/logic/LogicRunner_20260304155553.js +112 -0
  54. package/.history/src/logic/LogicRunner_20260305105834.js +112 -0
  55. package/.history/src/logic/LogicRunner_20260305112718.js +129 -0
  56. package/.history/src/logic/LogicRunner_20260305182436.js +133 -0
  57. package/.history/src/logic/LogicRunner_20260306151301.js +213 -0
  58. package/.history/src/logic/LogicRunner_20260306152419.js +213 -0
  59. package/.history/src/logic/plugins/common/DateTools_20260305154159.js +61 -0
  60. package/.history/src/logic/plugins/common/DateTools_20260305154217.js +44 -0
  61. package/.history/src/logic/plugins/common/DateTools_20260305161014.js +44 -0
  62. package/.history/src/logic/plugins/common/HttpTools_20260305164352.js +80 -0
  63. package/.history/src/logic/plugins/common/HttpTools_20260305170258.js +75 -0
  64. package/.history/src/logic/plugins/common/HttpTools_20260305171634.js +75 -0
  65. package/.history/src/logic/plugins/common/HttpTools_20260306152419.js +72 -0
  66. package/.history/src/services/api/restTools_20260427142149.js +245 -0
  67. package/.history/src/services/api/restTools_20260427142853.js +230 -0
  68. package/.history/src/services/api/restTools_20260519135558.js +230 -0
  69. package/.history/src/services/api/restTools_20260519140825.js +230 -0
  70. package/.history/src/services/api/restTools_20260519151223.js +230 -0
  71. package/.history/src/utils/indexedDB_20260306150918.js +593 -0
  72. package/.history/src/utils/indexedDB_20260306151301.js +586 -0
  73. package/.idea/af-vue2-client.iml +9 -0
  74. package/.idea/codeStyles/Project.xml +62 -0
  75. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  76. package/.idea/misc.xml +6 -0
  77. package/.idea/modules.xml +1 -1
  78. package/Components.md +60 -60
  79. package/index.js +31 -31
  80. package/jest-transform-stub.js +8 -8
  81. package/jest.setup.js +7 -7
  82. package/package.json +1 -1
  83. package/preview-input-box.html +180 -0
  84. package/src/assets/img/querySlotDemo.svg +15 -15
  85. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  86. package/src/base-client/components/common/CitySelect/index.js +3 -3
  87. package/src/base-client/components/common/CitySelect/index.md +109 -109
  88. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  89. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  90. package/src/base-client/components/common/HIS/HButtons/HButtons.vue +55 -1
  91. package/src/base-client/components/common/HIS/HForm/HForm.vue +1186 -1186
  92. package/src/base-client/components/common/HIS/HTab/HTab.vue +88 -1
  93. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  94. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  95. package/src/base-client/components/common/Tree/index.js +2 -2
  96. package/src/base-client/components/common/Upload/index.js +3 -3
  97. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  98. package/src/base-client/components/common/XAddReport/XAddReport.vue +16 -1
  99. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  100. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  101. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  102. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  103. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  104. package/src/base-client/components/common/XDescriptions/index.md +382 -382
  105. package/src/base-client/components/common/XForm/index.md +178 -178
  106. package/src/base-client/components/common/XInput/XInput.vue +32 -1
  107. package/src/base-client/components/common/XInspectionDetailDrawer/index.vue +1 -1
  108. package/src/base-client/components/common/XMarkdownViewer/demo.vue +102 -102
  109. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  110. package/src/base-client/components/common/XStepView/index.js +3 -3
  111. package/src/base-client/components/common/XStepView/index.md +31 -31
  112. package/src/base-client/components/common/XTable/index.md +255 -255
  113. package/src/base-client/components/his/HAi/HAi.vue +1177 -436
  114. package/src/base-client/components/his/XList/XList.vue +337 -58
  115. package/src/base-client/components/his/XSidebar/XSidebar.vue +36 -12
  116. package/src/base-client/components/his/XTransfer/index.md +327 -327
  117. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  118. package/src/base-client/plugins/Config.js +19 -19
  119. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  120. package/src/components/Charts/Bar.vue +62 -62
  121. package/src/components/Charts/ChartCard.vue +134 -134
  122. package/src/components/Charts/Liquid.vue +67 -67
  123. package/src/components/Charts/MiniArea.vue +39 -39
  124. package/src/components/Charts/MiniBar.vue +39 -39
  125. package/src/components/Charts/MiniProgress.vue +75 -75
  126. package/src/components/Charts/MiniSmoothArea.vue +40 -40
  127. package/src/components/Charts/Radar.vue +68 -68
  128. package/src/components/Charts/RankList.vue +77 -77
  129. package/src/components/Charts/TagCloud.vue +113 -113
  130. package/src/components/Charts/TransferBar.vue +64 -64
  131. package/src/components/Charts/Trend.vue +82 -82
  132. package/src/components/Charts/chart.less +12 -12
  133. package/src/components/Charts/smooth.area.less +13 -13
  134. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  135. package/src/components/NumberInfo/index.js +3 -3
  136. package/src/components/NumberInfo/index.less +54 -54
  137. package/src/components/NumberInfo/index.md +43 -43
  138. package/src/components/STable/index.js +953 -953
  139. package/src/components/card/ChartCard.vue +79 -79
  140. package/src/components/chart/Bar.vue +60 -60
  141. package/src/components/chart/MiniArea.vue +67 -67
  142. package/src/components/chart/MiniBar.vue +59 -59
  143. package/src/components/chart/MiniProgress.vue +57 -57
  144. package/src/components/chart/Radar.vue +80 -80
  145. package/src/components/chart/RankingList.vue +60 -60
  146. package/src/components/chart/Trend.vue +79 -79
  147. package/src/components/chart/index.less +9 -9
  148. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  149. package/src/components/input/IInput.vue +66 -66
  150. package/src/components/menu/SideMenu.vue +75 -75
  151. package/src/components/menu/menu.js +273 -273
  152. package/src/components/tool/AStepItem.vue +60 -60
  153. package/src/layouts/CommonLayout.vue +56 -56
  154. package/src/lib.js +1 -1
  155. package/src/mock/extend/index.js +84 -84
  156. package/src/mock/goods/index.js +108 -108
  157. package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
  158. package/src/pages/system/dictionary/index.vue +44 -44
  159. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  160. package/src/pages/system/monitor/operLog/index.vue +37 -37
  161. package/src/services/api/cas.js +79 -79
  162. package/src/store/modules/setting.js +119 -119
  163. package/src/utils/errorCode.js +6 -6
  164. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
  165. package/.idea/MarsCodeWorkspaceAppSettings.xml +0 -7
  166. package/.idea/google-java-format.xml +0 -6
  167. package/.idea/inspectionProfiles/Project_Default.xml +0 -24
  168. package/.idea/jsLinters/eslint.xml +0 -6
  169. package/.idea/vue2-client.iml +0 -12
  170. package/.vscode/settings.json +0 -28
@@ -0,0 +1,726 @@
1
+ <script>
2
+ import { v4 as uuidv4 } from 'uuid'
3
+ import {
4
+ FormModel,
5
+ Input,
6
+ Button,
7
+ Row,
8
+ Col,
9
+ Card,
10
+ Divider,
11
+ message,
12
+ Select,
13
+ Spin
14
+ } from 'ant-design-vue'
15
+ import { getConfigByNameAsync, runLogic } from '@vue2-client/services/api/common'
16
+ import { mapState } from 'vuex'
17
+ import { debounce } from 'lodash'
18
+
19
+ export default {
20
+ name: 'HAddNativeForm',
21
+ components: {
22
+ 'a-form-model': FormModel,
23
+ 'a-form-item': FormModel.Item,
24
+ 'a-input': Input,
25
+ 'a-button': Button,
26
+ 'a-row': Row,
27
+ 'a-col': Col,
28
+ 'a-card': Card,
29
+ 'a-divider': Divider,
30
+ 'a-select': Select,
31
+ 'a-select-option': Select.Option,
32
+ 'a-spin': Spin
33
+ },
34
+ props: {
35
+ queryParamsName: {
36
+ type: String,
37
+ required: true
38
+ },
39
+ serviceName: {
40
+ type: String,
41
+ default: process.env.VUE_APP_SYSTEM_NAME
42
+ },
43
+ // 下拉框label在内部样式
44
+ selectInsideLabelStyle: {
45
+ type: Boolean,
46
+ default: false
47
+ }
48
+ },
49
+ data () {
50
+ return {
51
+ loading: true,
52
+ config: {},
53
+ formInstances: [],
54
+ // 从配置读取的样式标识(默认值)
55
+ formStyle: 'defaultForm'
56
+ }
57
+ },
58
+ computed: {
59
+ formItemLayoutComputed () {
60
+ // 如果是 inline 布局,则不绑定 formItemLayout,让其使用 Ant Design Vue 默认的 inline 样式
61
+ if (this.config.xAddFormLayout === 'inline') {
62
+ return {}
63
+ }
64
+ if (this.config.formItemLayout) {
65
+ return {
66
+ labelCol: { span: this.config.formItemLayout.labelCol },
67
+ wrapperCol: { span: this.config.formItemLayout.wrapperCol }
68
+ }
69
+ }
70
+ // 如果是 horizontal 布局但未提供 formItemLayout,则提供一个默认值
71
+ return {
72
+ labelCol: { span: 6 }, // 默认标签宽度
73
+ wrapperCol: { span: 18 } // 默认控件宽度,确保输入框足够宽
74
+ }
75
+ },
76
+ ...mapState('account', { currUser: 'user' })
77
+ },
78
+ created () {
79
+ this.debouncedSearch = debounce(this.performSearch, 500)
80
+ this.fetchConfigAndInitializeForms()
81
+ },
82
+ mounted () {
83
+ this.$nextTick(() => {
84
+ this.injectSelectInsideLabels()
85
+ })
86
+ },
87
+ methods: {
88
+ // 注入下拉框内部 label 的方法
89
+ injectSelectInsideLabels () {
90
+ if (!this.selectInsideLabelStyle) return
91
+
92
+ this.$nextTick(() => {
93
+ setTimeout(() => {
94
+ this.doInjectLabels()
95
+ }, 500)
96
+ })
97
+ },
98
+
99
+ doInjectLabels () {
100
+ // 使用更宽松的选择器
101
+ const selects = document.querySelectorAll('.h-add-native-form-group .ant-select')
102
+ if (!selects.length) return
103
+
104
+ selects.forEach((select) => {
105
+ // 检查是否已经处理过
106
+ if (select.querySelector('.select-inside-label-span')) return
107
+
108
+ // 获取当前下拉框所属的表单项的 label
109
+ const formItem = select.closest('.ant-form-item')
110
+ if (!formItem) return
111
+
112
+ const labelElement = formItem.querySelector('.ant-form-item-label label')
113
+ if (!labelElement) return
114
+
115
+ const labelText = labelElement.textContent?.trim() || ''
116
+ if (!labelText) return
117
+
118
+ // 隐藏原有的 label
119
+ const labelContainer = formItem.querySelector('.ant-form-item-label')
120
+ if (labelContainer) {
121
+ labelContainer.style.display = 'none'
122
+ }
123
+
124
+ // 创建 label 容器,直接内联样式
125
+ const labelSpan = document.createElement('span')
126
+ labelSpan.className = 'select-inside-label-span'
127
+ labelSpan.textContent = labelText
128
+ // 直接设置样式,确保生效
129
+ Object.assign(labelSpan.style, {
130
+ fontFamily: "'Source Han Sans', sans-serif",
131
+ fontSize: '16px',
132
+ fontWeight: 'normal',
133
+ lineHeight: 'normal',
134
+ letterSpacing: '0em',
135
+ color: '#313131',
136
+ whiteSpace: 'nowrap',
137
+ flexShrink: '0'
138
+ })
139
+
140
+ // 插入到 selection__rendered 的最前面
141
+ const selectionRendered = select.querySelector('.ant-select-selection__rendered')
142
+ if (selectionRendered) {
143
+ // 移除 ant-select-selection__placeholder,避免重叠
144
+ const placeholder = select.querySelector('.ant-select-selection__placeholder')
145
+ if (placeholder) {
146
+ placeholder.style.display = 'none'
147
+ }
148
+
149
+ // 设置选中值的样式
150
+ const selectedValue = select.querySelector('.ant-select-selection-selected-value')
151
+ if (selectedValue) {
152
+ selectedValue.style.paddingLeft = '36px'
153
+ Object.assign(selectedValue.style, {
154
+ fontFamily: "'Source Han Sans', sans-serif",
155
+ fontSize: '16px',
156
+ fontWeight: 'normal',
157
+ lineHeight: 'normal',
158
+ letterSpacing: '0em',
159
+ color: '#313131'
160
+ })
161
+ }
162
+
163
+ // 在最前面插入 label
164
+ selectionRendered.insertBefore(labelSpan, selectionRendered.firstChild)
165
+ }
166
+ })
167
+ },
168
+ async fetchConfigAndInitializeForms () {
169
+ try {
170
+ this.loading = true
171
+ const res = await getConfigByNameAsync(this.queryParamsName, this.serviceName)
172
+ if (res) {
173
+ this.config = res
174
+ // 从接口配置设置样式标识
175
+ if (this.config.formStyle) {
176
+ this.formStyle = this.config.formStyle
177
+ }
178
+ if (this.config.manyForm) {
179
+ this.addFormInstance()
180
+ } else {
181
+ this.addFormInstance()
182
+ }
183
+ } else {
184
+ console.error('HAddNativeForm: 未能获取到配置内容。')
185
+ message.error('未能获取到表单配置,请检查配置名称或网络。')
186
+ }
187
+ } catch (error) {
188
+ console.error('HAddNativeForm: 获取配置时发生错误:', error)
189
+ message.error('获取表单配置时发生错误。')
190
+ } finally {
191
+ this.loading = false
192
+ this.$nextTick(() => {
193
+ this.injectSelectInsideLabels()
194
+ })
195
+ }
196
+ },
197
+ async getOptions (item, formDataContext, searchKeyword = '') {
198
+ if (!item.keyName) {
199
+ return
200
+ }
201
+
202
+ this.$set(item, 'loadingOptions', true)
203
+ let fetchedOptions = []
204
+
205
+ try {
206
+ if (item.keyName.startsWith('logic@')) {
207
+ const logicName = item.keyName.substring(6)
208
+ const result = await runLogic(logicName, { searchKeyword: searchKeyword }, this.serviceName)
209
+
210
+ if (Array.isArray(result)) {
211
+ fetchedOptions = result.map(opt => ({
212
+ label: opt.label || opt.name || opt.text,
213
+ value: (opt.value || opt.id) + '',
214
+ ...opt // 将所有原始属性也添加到选项中
215
+ }))
216
+ } else {
217
+ console.warn(`Logic '${logicName}' did not return an array for options. Result:`, result)
218
+ }
219
+ } else if (item.keyName.startsWith('config@')) {
220
+ const configName = item.keyName.substring(7)
221
+ const res = await getConfigByNameAsync(configName, this.serviceName)
222
+ if (res && res.value && Array.isArray(res.value)) {
223
+ fetchedOptions = res.value.map(opt => ({
224
+ label: opt.label || opt.name || opt.text,
225
+ value: (opt.value || opt.id) + '',
226
+ ...opt // 将所有原始属性也添加到选项中
227
+ }))
228
+ } else {
229
+ console.warn(`Config '${configName}' did not return a valid 'value' array for options. Result:`, res)
230
+ }
231
+ } else {
232
+ // 全局字典
233
+ if (this.$appdata && typeof this.$appdata.getDictByKeyAsync === 'function') {
234
+ const dictionaryList = await this.$appdata.getDictByKeyAsync(item.keyName)
235
+ if (Array.isArray(dictionaryList)) {
236
+ fetchedOptions = dictionaryList.map(opt => ({
237
+ label: opt.label,
238
+ value: opt.value + '',
239
+ ...opt // 将所有原始属性也添加到选项中
240
+ }))
241
+ } else {
242
+ console.warn(`Global dictionary '${item.keyName}' did not return an array. Result:`, dictionaryList)
243
+ }
244
+ } else {
245
+ console.error('$appdata.getDictionaryList is not available. Please ensure it\'s globally provided.')
246
+ }
247
+ }
248
+ } catch (error) {
249
+ console.error(`Error fetching options for item '${item.key}':`, error)
250
+ fetchedOptions = []
251
+ } finally {
252
+ this.$set(item, 'options', fetchedOptions)
253
+ this.$set(item, 'loadingOptions', false)
254
+ }
255
+ },
256
+ // 搜索处理函数,使用 debounce 优化性能
257
+ handleSelectSearch (value, item, formDataContext) {
258
+ // 更新搜索关键字,并触发 debouncedSearch
259
+ this.$set(item, 'searchKeyword', value)
260
+ this.debouncedSearch(item, formDataContext)
261
+ },
262
+ // 执行实际的搜索操作
263
+ performSearch (item, formDataContext) {
264
+ this.getOptions(item, formDataContext, item.searchKeyword)
265
+ },
266
+ // 当选择框获得焦点时,重新加载选项(如果没有搜索关键字)
267
+ handleSelectFocus (item, formDataContext) {
268
+ if (!item.searchKeyword || item.searchKeyword === '') {
269
+ this.getOptions(item, formDataContext)
270
+ }
271
+ },
272
+ // 批量设置所有表单值
273
+ setAllFormsData (dataList) {
274
+ // 确保有足够多的表单实例来容纳所有数据
275
+ while (this.formInstances.length < dataList.length) {
276
+ this.addFormInstance()
277
+ }
278
+ dataList.forEach((data, index) => {
279
+ if (this.formInstances[index]) {
280
+ Object.assign(this.formInstances[index].formData, data)
281
+ }
282
+ })
283
+ this.$forceUpdate()
284
+ },
285
+ addFormInstance () {
286
+ const newId = uuidv4()
287
+ const newFormData = {}
288
+ const clonedFormItems = this.config.formItem ? JSON.parse(JSON.stringify(this.config.formItem)) : []
289
+
290
+ if (clonedFormItems.length > 0) {
291
+ for (const item of clonedFormItems) {
292
+ newFormData[item.key] = undefined
293
+ if (item.formType === 'select' && item.keyName) {
294
+ this.$set(item, 'options', [])
295
+ this.$set(item, 'loadingOptions', false)
296
+ this.$set(item, 'searchKeyword', '')
297
+ this.getOptions(item, newFormData)
298
+ }
299
+ }
300
+ }
301
+
302
+ this.formInstances.push({
303
+ id: newId,
304
+ formData: newFormData,
305
+ formItems: clonedFormItems
306
+ })
307
+ },
308
+ deleteFormInstance (id) {
309
+ if (this.formInstances.length > 1) {
310
+ this.formInstances = this.formInstances.filter(instance => instance.id !== id)
311
+ } else {
312
+ message.warning('至少需要保留一个表单实例。')
313
+ }
314
+ },
315
+ getRules (item) {
316
+ const rules = []
317
+ if (item.rule && (item.rule.required === true || item.rule.required === 'true')) {
318
+ rules.push({
319
+ required: true,
320
+ message: `请输入${item.title}`,
321
+ trigger: 'blur'
322
+ })
323
+ }
324
+ return rules
325
+ },
326
+ async onSubmit () {
327
+ let allFormsValid = true
328
+ const allFormsData = []
329
+
330
+ for (const instance of this.formInstances) {
331
+ const formRef = this.$refs['formModel_' + instance.id][0]
332
+ if (formRef) {
333
+ try {
334
+ await formRef.validate()
335
+ allFormsData.push(instance.formData)
336
+ } catch (error) {
337
+ allFormsValid = false
338
+ break
339
+ }
340
+ }
341
+ }
342
+
343
+ if (allFormsValid) {
344
+ message.success('表单提交成功!')
345
+ this.$emit('submit', allFormsData)
346
+ } else {
347
+ message.error('部分表单校验失败,请检查。')
348
+ }
349
+ },
350
+ getAllFormsData () {
351
+ return this.formInstances.map(instance => {
352
+ return instance.formData
353
+ })
354
+ },
355
+ handleSelectChange (value, option, selectItem, formData, allFormItems) {
356
+ // 直接获取option.data.props中的完整数据
357
+ const selectedOptionData = option?.data?.props
358
+ if (selectedOptionData) {
359
+ for (const key in selectedOptionData) {
360
+ if (Object.prototype.hasOwnProperty.call(selectedOptionData, key) && !['label', 'value'].includes(key)) {
361
+ const targetItem = allFormItems.find(item => item.key === key)
362
+ if (targetItem) {
363
+ formData[key] = selectedOptionData[key]
364
+ this.$forceUpdate()
365
+ }
366
+ }
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+ </script>
373
+
374
+ <template>
375
+ <div class="h-add-native-form-group" :class="[`h-add-native-form-${formStyle}`, { 'select-inside-label-style': selectInsideLabelStyle }]">
376
+ <a-skeleton :loading="loading" :paragraph="{ rows: 4 }" />
377
+ <div v-if="!loading">
378
+ <div v-for="(formInstance, formIndex) in formInstances" :key="formInstance.id" class="form-instance-wrapper">
379
+ <!-- <div v-if="config.manyForm" class="form-instance-title">药品 {{ formIndex + 1 }}</div> -->
380
+ <a-form-model
381
+ :ref="'formModel_' + formInstance.id"
382
+ :model="formInstance.formData"
383
+ v-bind="formItemLayoutComputed"
384
+ :layout="config.xAddFormLayout || 'horizontal'"
385
+ >
386
+ <a-row :gutter="16">
387
+ <a-col
388
+ v-for="(item, itemIndex) in formInstance.formItems"
389
+ :key="itemIndex"
390
+ :xs="24"
391
+ :sm="12"
392
+ :md="8"
393
+ :lg="6"
394
+ :xl="6"
395
+ >
396
+ <a-form-item
397
+ :label="item.title"
398
+ :prop="item.key"
399
+ :rules="getRules(item)"
400
+ >
401
+ <a-input
402
+ v-if="item.formType === 'input'"
403
+ v-model="formInstance.formData[item.key]"
404
+ :placeholder="'请输入' + item.title"
405
+ style="width: 100%"
406
+ />
407
+ <a-select
408
+ v-else-if="item.formType === 'select'"
409
+ v-model="formInstance.formData[item.key]"
410
+ :placeholder=" '请选择' + item.title"
411
+ :options="item.options"
412
+ :loading="item.loadingOptions"
413
+ show-search
414
+ allowClear
415
+ :filter-option="false"
416
+ @search="(value) => handleSelectSearch(value, item, formInstance.formData)"
417
+ @focus="() => handleSelectFocus(item, formInstance.formData)"
418
+ @change="(value, option) => handleSelectChange(value, option, item, formInstance.formData, formInstance.formItems)"
419
+ :dropdownMatchSelectWidth="false"
420
+ :dropdownStyle="{ minWidth: '200px' }"
421
+ style="width: 100%"
422
+ >
423
+ <a-spin v-if="item.loadingOptions" slot="notFoundContent" size="small" />
424
+ </a-select>
425
+ <!-- 可以根据需要添加其他表单类型,例如 select, datePicker 等 -->
426
+ </a-form-item>
427
+ </a-col>
428
+ </a-row>
429
+ </a-form-model>
430
+ <a-divider style="margin: 10px" v-if="config.manyForm && formIndex < formInstances.length - 1" />
431
+ </div>
432
+
433
+ <!-- 全局添加/删除按钮,只在所有表单实例之后显示 -->
434
+ <a-row v-if="config.manyForm" type="flex" justify="start" style="margin-top: 20px; gap: 10px;">
435
+ <a-button v-if="config.showAddButton" class="form-action-button" icon="plus" @click="addFormInstance"></a-button>
436
+ <a-button v-if="config.showDeleteButton && formInstances.length > 1" class="form-action-button" style="margin-left: 0px" icon="minus" @click="deleteFormInstance(formInstances[formInstances.length - 1].id)"></a-button>
437
+ </a-row>
438
+
439
+ <a-row v-if="config.showSubmitBtn" type="flex" justify="start" style="margin-top: 20px;">
440
+ <a-col>
441
+ <a-button type="primary" @click="onSubmit">{{ config.btnName || '提交' }}</a-button>
442
+ </a-col>
443
+ </a-row>
444
+ </div>
445
+ </div>
446
+ </template>
447
+
448
+ <style scoped lang="less">
449
+ .h-add-native-form-group {
450
+ // 基础样式,对应 defaultForm
451
+ &.h-add-native-form-defaultForm {
452
+ padding: 0px;
453
+ // background-color: #fff;
454
+ border-radius: 8px;
455
+ }
456
+ &.h-add-native-form-medicalForm {
457
+ @media (min-width: 1200px) {
458
+ :deep(.ant-col-xl-6) {
459
+ display: block;
460
+ flex: 0 0 42%;
461
+ max-width: 42%;
462
+ width: 42%;
463
+ }
464
+ }
465
+ }
466
+ }
467
+
468
+ .form-instance-wrapper {
469
+ margin-bottom: 0px;
470
+ /* 移除边框和背景色,使其看起来像一个整体 */
471
+ /* border: 1px solid #e8e8e8;
472
+ border-radius: 4px;
473
+ background-color: #fff; */
474
+ }
475
+
476
+ .form-instance-title {
477
+ font-weight: bold;
478
+ font-size: 16px;
479
+ margin-bottom: 10px;
480
+ padding-left: 10px; /* 与表单项对齐 */
481
+ color: rgba(0, 0, 0, 0.85);
482
+ }
483
+
484
+ .form-action-button {
485
+ width: 40px;
486
+ height: 40px;
487
+ border-radius: 8px;
488
+ border: 1px solid #d9d9d9;
489
+ background-color: #fff;
490
+ color: rgba(0, 0, 0, 0.65);
491
+ display: flex;
492
+ justify-content: center;
493
+ align-items: center;
494
+ margin-left: 95px;
495
+
496
+ &:hover {
497
+ border-color: #40a9ff; /* 鼠标悬停时边框颜色 */
498
+ color: #40a9ff; /* 鼠标悬停时图标颜色 */
499
+ }
500
+ }
501
+
502
+ // 修复表单控件宽度问题
503
+ :deep(.ant-form-item-control-wrapper) {
504
+ width: 100%;
505
+ }
506
+
507
+ :deep(.ant-form-item-control) {
508
+ width: 100%;
509
+ }
510
+
511
+ :deep(.ant-input),
512
+ :deep(.ant-select) {
513
+ width: 100% !important;
514
+ }
515
+
516
+ :deep(.ant-card-extra) {
517
+ padding: 0;
518
+ }
519
+
520
+ :deep(.ant-form-item) {
521
+ margin-bottom: 5px; // 增加表单项间距
522
+ display: flex;
523
+ flex-direction: column;
524
+ margin-left: 95px;
525
+ }
526
+
527
+ :deep(.ant-form-item-label) {
528
+ text-align: left;
529
+ white-space: normal;
530
+ }
531
+
532
+ :deep(.ant-form-item-control-wrapper) {
533
+ flex: 1;
534
+ }
535
+
536
+ // 针对 inline 布局的样式调整
537
+ :deep(.ant-form-inline .ant-form-item) {
538
+ margin-right: 0;
539
+ margin-bottom: 16px;
540
+ display: flex;
541
+ flex-direction: row;
542
+ align-items: flex-start;
543
+ }
544
+
545
+ :deep(.ant-form-inline .ant-form-item-label) {
546
+ padding-right: 8px;
547
+ flex: none;
548
+ }
549
+
550
+ :deep(.ant-form-inline .ant-form-item-control-wrapper) {
551
+ flex: 1;
552
+ min-width: 0;
553
+ }
554
+
555
+ :deep(.ant-form-inline .ant-input),
556
+ :deep(.ant-form-inline .ant-select) {
557
+ width: 100% !important;
558
+ min-width: 120px; // 确保有最小宽度
559
+ }
560
+
561
+ // 响应式布局调整
562
+ @media (max-width: 768px) {
563
+ :deep(.ant-col-xs-24) {
564
+ width: 100%;
565
+ }
566
+
567
+ :deep(.ant-form-item) {
568
+ margin-bottom: 12px;
569
+ }
570
+ }
571
+
572
+ // select-inside-label-style 下拉框label在选择框内部样式
573
+ .select-inside-label-style {
574
+ // 表单项上间距 10px
575
+ :deep(.ant-form-item) {
576
+ margin-top: 10px !important;
577
+ margin-bottom: 0 !important;
578
+ }
579
+
580
+ // 隐藏原有的 label
581
+ :deep(.ant-form-item-label) {
582
+ display: none !important;
583
+ }
584
+
585
+ // 下拉框样式 - label在内部
586
+ :deep(.ant-select) {
587
+ width: 234px;
588
+
589
+ .ant-select-selector {
590
+ width: 234px !important;
591
+ height: 32px !important;
592
+ border-radius: 7px !important;
593
+ border: 1px solid #E5E9F0 !important;
594
+ background: #FFFFFF !important;
595
+ padding: 0 !important;
596
+ box-sizing: border-box !important;
597
+ display: flex !important;
598
+ align-items: center !important;
599
+
600
+ &:hover {
601
+ border-color: #0057FE !important;
602
+ }
603
+
604
+ .ant-select-selection__rendered {
605
+ width: 100% !important;
606
+ height: 32px !important;
607
+ margin: 0 !important;
608
+ padding: 0 11px !important;
609
+ display: flex !important;
610
+ align-items: center !important;
611
+ }
612
+ }
613
+
614
+ // 动态插入的 label 样式
615
+ .select-inside-label-span {
616
+ font-family: 'Source Han Sans', sans-serif;
617
+ font-size: 16px;
618
+ font-weight: normal;
619
+ line-height: normal;
620
+ letter-spacing: 0em;
621
+ color: #313131;
622
+ white-space: nowrap;
623
+ flex-shrink: 0;
624
+ }
625
+
626
+ // 选中的值样式 - padding-left 实现与 label 的 36px 间距
627
+ .ant-select-selection-selected-value {
628
+ font-family: 'Source Han Sans', sans-serif;
629
+ font-size: 16px;
630
+ font-weight: normal;
631
+ line-height: normal;
632
+ letter-spacing: 0em;
633
+ color: #313131;
634
+ padding-left: 36px !important;
635
+ }
636
+
637
+ .ant-select-arrow {
638
+ right: 11px !important;
639
+ color: #999 !important;
640
+ }
641
+ }
642
+
643
+ // 聚焦状态
644
+ :deep(.ant-select-focused) {
645
+ .ant-select-selector {
646
+ border-color: #0057FE !important;
647
+ box-shadow: none !important;
648
+ }
649
+ }
650
+
651
+ // 普通输入框样式
652
+ :deep(.ant-input:not(textarea)) {
653
+ width: 234px !important;
654
+ border-radius: 7px !important;
655
+ border: 1px solid #E5E9F0 !important;
656
+ background: #FFFFFF !important;
657
+ height: 32px !important;
658
+ line-height: 30px !important;
659
+ padding: 0 11px !important;
660
+ box-sizing: border-box !important;
661
+ font-family: 'Source Han Sans', sans-serif;
662
+ font-size: 16px;
663
+ font-weight: normal;
664
+ line-height: normal;
665
+ letter-spacing: 0em;
666
+ color: #313131;
667
+
668
+ &::placeholder {
669
+ color: #999 !important;
670
+ }
671
+
672
+ &:hover,
673
+ &:focus {
674
+ border-color: #0057FE !important;
675
+ }
676
+ }
677
+
678
+ // 文本域样式
679
+ :deep(textarea.ant-input) {
680
+ border-radius: 7px !important;
681
+ border: 1px solid #E5E9F0 !important;
682
+ min-height: 80px !important;
683
+ padding: 8px 11px !important;
684
+ font-family: 'Source Han Sans', sans-serif;
685
+ font-size: 16px;
686
+ font-weight: normal;
687
+ line-height: normal;
688
+ letter-spacing: 0em;
689
+ color: #313131;
690
+
691
+ &::placeholder {
692
+ color: #999 !important;
693
+ }
694
+ }
695
+
696
+ // 日期选择器样式
697
+ :deep(.ant-picker) {
698
+ width: 234px !important;
699
+ border-radius: 7px !important;
700
+ border: 1px solid #E5E9F0 !important;
701
+ background: #FFFFFF !important;
702
+ height: 32px !important;
703
+ box-sizing: border-box !important;
704
+
705
+ &:hover,
706
+ &:focus {
707
+ border-color: #0057FE !important;
708
+ }
709
+
710
+ .ant-picker-input {
711
+ input {
712
+ font-family: 'Source Han Sans', sans-serif;
713
+ font-size: 16px;
714
+ font-weight: normal;
715
+ line-height: normal;
716
+ letter-spacing: 0em;
717
+ color: #313131;
718
+ }
719
+
720
+ input::placeholder {
721
+ color: #999 !important;
722
+ }
723
+ }
724
+ }
725
+ }
726
+ </style>