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,1455 @@
1
+ <template>
2
+ <div id="XAddNativeForm">
3
+ <!-- 骨架屏 -->
4
+ <a-skeleton v-if="!loaded" active :paragraph="{ rows: 3 }" />
5
+ <a-form-model v-else ref="selectForm" :zIndex="1001" :model="form" v-bind="formItemLayoutGen" :layout="layout">
6
+ <template v-for="(item, key) in childTableData">
7
+ <a-row v-if="childTablePriority" :gutter="16" :key="'childTableRow' + key">
8
+ <a-card :title="item.name" :bordered="false" size="small">
9
+ <x-form-table
10
+ :key="'childTable_' + item.model"
11
+ :title="item.name"
12
+ :queryParamsName="item.childTableConfigName"
13
+ :localEditMode="true"
14
+ :fixed-query-form="childTableFixedQueryForm(item)"
15
+ :service-name="serviceName"
16
+ @innerXFormTableEmit="innerXFormTableEmit"
17
+ @afterTableInit="childTableMounted(item)"
18
+ :ref="'childXFormTable_' + item.model"
19
+ ></x-form-table>
20
+ </a-card>
21
+ </a-row>
22
+ </template>
23
+ <template v-if="isSimpleInlineMode">
24
+ <a-row v-for="(row, rowIndex) in simpleInlineRows" :key="'simple-row-' + rowIndex" :gutter="0" type="flex">
25
+ <a-col v-for="(item, itemIndex) in row.items" :key="'simple-item-' + itemIndex" :span="item.span">
26
+ <x-form-item
27
+ class="simple-inline-item"
28
+ :class="{ 'show-label': showSimpleInlineLabel }"
29
+ :attr="item.formItem"
30
+ :disabled="itemDisabled(item.formItem)"
31
+ :read-only="readonly(item.formItem)"
32
+ :files="files"
33
+ :signs="signs"
34
+ :form="form"
35
+ :images="images"
36
+ :service-name="serviceName"
37
+ mode="新增/修改"
38
+ layout="simple-inline"
39
+ :rules="rules[`${item.formItem.name}${item.formItem.model}`]"
40
+ :get-data-params="getDataParams"
41
+ :env="env"
42
+ :enablePopupToBody="enablePopupToBody"
43
+ :label-col="simpleInlineLabelCol"
44
+ :show-label="showSimpleInlineLabel"
45
+ @x-form-item-emit-func="emitFunc"
46
+ @rowChoose="rowChoose"
47
+ :setForm="setForm"
48
+ :style="{ margin: 0, padding: '2px' }"
49
+ />
50
+ </a-col>
51
+ </a-row>
52
+ </template>
53
+ <a-row ref="GroupItemRow" v-if="!isSimpleInlineMode">
54
+ <a-col :span="3" v-if="!inXFormGroup && !(groups[0].groupName === DEFAULT_GROUP_NAME)">
55
+ <a-tabs tab-position="left" v-model="activeTab" @change="scrollToGroup">
56
+ <a-tab-pane
57
+ v-for="(groupsItem, groupsIndex) in groups"
58
+ :tab="groupsItem.groupName"
59
+ :key="groupsIndex"
60
+ ></a-tab-pane>
61
+ </a-tabs>
62
+ </a-col>
63
+ <a-col :span="!inXFormGroup && !(groups[0].groupName === DEFAULT_GROUP_NAME) ? 21 : 24">
64
+ <a-row :gutter="16" type="flex" :key="groupsIndex" v-for="(groupsItem, groupsIndex) in groups">
65
+ <a-col
66
+ :span="24"
67
+ :style="{
68
+ marginTop: groupsIndex === 0 && !inXFormGroup ? '' : '8px',
69
+ fontSize: '14px'
70
+ }"
71
+ v-if="groupsItem.groupName !== DEFAULT_GROUP_NAME"
72
+ >
73
+ <span
74
+ class="xFormGroupTitle"
75
+ :style="{
76
+ paddingLeft: inXFormGroup ? '14px' : '-5px'
77
+ }"
78
+ :ref="`group-title-${groupsIndex}`"
79
+ >
80
+ {{ groupsItem.groupName }}
81
+ </span>
82
+ </a-col>
83
+ <x-form-item
84
+ v-for="(item, index) in groupsItem.realJsonData"
85
+ :key="index"
86
+ :attr="item"
87
+ :disabled="itemDisabled(item)"
88
+ :read-only="readonly(item)"
89
+ :files="files"
90
+ :signs="signs"
91
+ v-bind="formItemLayoutGen"
92
+ :style="layout === 'inline' ? { marginTop: '5px' } : undefined"
93
+ :form="form"
94
+ :images="images"
95
+ :enablePopupToBody="enablePopupToBody"
96
+ :service-name="serviceName"
97
+ mode="新增/修改"
98
+ :layout="layout"
99
+ :rules="rules[`${item.name}${item.model}`]"
100
+ :get-data-params="getDataParams"
101
+ :env="env"
102
+ @x-form-item-emit-func="emitFunc"
103
+ @rowChoose="rowChoose"
104
+ :setForm="setForm"
105
+ />
106
+ </a-row>
107
+ </a-col>
108
+ </a-row>
109
+ <template v-if="!isSimpleInlineMode">
110
+ <a-row :gutter="16" v-for="(groupItem, groupIndex) in groupJsonData" :key="groupIndex">
111
+ <a-card v-if="groupItem.groupItems.length > 0" :title="groupItem.name" :bordered="false" size="small">
112
+ <x-form-item
113
+ v-for="(item, index) in groupItem.groupItems"
114
+ :key="index"
115
+ :attr="item"
116
+ :disabled="itemDisabled(item)"
117
+ :readonly="readonly(item)"
118
+ :files="files"
119
+ :signs="signs"
120
+ v-bind="formItemLayoutGen"
121
+ :style="layout === 'inline' ? { marginTop: '5px' } : undefined"
122
+ :form="form[groupItem.model]"
123
+ :images="images"
124
+ :service-name="serviceName"
125
+ mode="新增/修改"
126
+ :rules="rules[`${item.name}${item.model}`]"
127
+ :get-data-params="getDataParams"
128
+ :env="env"
129
+ :setForm="setForm"
130
+ @rowChoose="rowChoose"
131
+ />
132
+ </a-card>
133
+ <template v-else>
134
+ <slot
135
+ name="groupFormItems"
136
+ :form="form"
137
+ :model="groupItem.model"
138
+ :rules="rules"
139
+ :modifyModelData="modifyModelData"
140
+ ></slot>
141
+ </template>
142
+ </a-row>
143
+ </template>
144
+ <template v-if="!isSimpleInlineMode">
145
+ <a-row :gutter="16" v-for="(item, key) in simpleFormJsonData" :key="'row' + key">
146
+ <a-card v-if="item.value.length > 0" :title="item.name" :bordered="false" size="small">
147
+ <x-form-item
148
+ v-for="(formItem, formItemIndex) in item.value"
149
+ :key="key + formItemIndex"
150
+ :attr="formItem"
151
+ :disabled="itemDisabled(formItem)"
152
+ :readonly="readonly(formItem)"
153
+ :files="files"
154
+ :signs="signs"
155
+ :enablePopupToBody="enablePopupToBody"
156
+ v-bind="formItemLayoutGen"
157
+ :style="layout === 'inline' ? { marginTop: '5px' } : undefined"
158
+ :form="form[groupItem.model]"
159
+ :images="images"
160
+ :service-name="serviceName"
161
+ mode="新增/修改"
162
+ :rules="rules[`${item.name}${item.model}`]"
163
+ :get-data-params="getDataParams"
164
+ :env="env"
165
+ :setForm="setForm"
166
+ @rowChoose="rowChoose"
167
+ />
168
+ </a-card>
169
+ </a-row>
170
+ </template>
171
+ <template v-for="(item, key) in childTableData">
172
+ <a-row v-if="!childTablePriority" :gutter="16" :key="'childTableRow' + key">
173
+ <a-card :title="item.name" :bordered="false" size="small">
174
+ <x-form-table
175
+ :key="'childTable_' + item.model"
176
+ :title="item.name"
177
+ :queryParamsName="item.childTableConfigName"
178
+ :localEditMode="true"
179
+ @innerXFormTableEmit="innerXFormTableEmit"
180
+ :fixed-query-form="childTableFixedQueryForm(item)"
181
+ :service-name="serviceName"
182
+ @afterTableInit="childTableMounted(item)"
183
+ :ref="'childXFormTable_' + item.model"
184
+ ></x-form-table>
185
+ </a-card>
186
+ </a-row>
187
+ </template>
188
+ <a-row type="flex" :justify="btnPlace" v-if="showSubmitBtn" class="form-footer-row" :style="{ paddingLeft: '16px', paddingRight: '16px' }">
189
+ <slot name="footer" :loading="loading">
190
+ <a-button :loading="loading" type="primary" @click="onSubmit()">
191
+ {{ btnName }}
192
+ </a-button>
193
+ </slot>
194
+ </a-row>
195
+ </a-form-model>
196
+ </div>
197
+ </template>
198
+ <script>
199
+ import XFormItem from '@vue2-client/base-client/components/common/XForm/XFormItem'
200
+ import { formatDate, setDataByRealKey } from '@vue2-client/utils/util'
201
+ import * as util from '@vue2-client/utils/util'
202
+ import { mapState } from 'vuex'
203
+ import { addOrModify, getConfigByName, getConfigByNameAsync, runLogic } from '@vue2-client/services/api/common'
204
+ import { checkIdNumber, REG_EMAIL, REG_LANDLINE, REG_PHONE } from '@vue2-client/utils/reg'
205
+ import moment from 'moment/moment'
206
+ import { executeStrFunction, executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
207
+ import formValidationMixin from '@vue2-client/mixins/formValidationMixin'
208
+ import { debounce } from 'lodash'
209
+
210
+ const DEFAULT_GROUP_NAME = '__default__'
211
+ export default {
212
+ name: 'XAddNativeForm',
213
+ components: {
214
+ XFormItem,
215
+ XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable.vue')
216
+ },
217
+ inject: {
218
+ inXFormGroup: {
219
+ default: false
220
+ },
221
+ formGroupContext: {
222
+ default: null
223
+ },
224
+ formDataChange: {
225
+ default: null
226
+ }
227
+ },
228
+ props: {
229
+ // 是否启用 horizontal 模式的自定义配置
230
+ enableHorizontalCustom: {
231
+ type: Boolean,
232
+ default: false
233
+ },
234
+ // 是否启用时间弹出到最外层
235
+ enablePopupToBody: {
236
+ type: Boolean,
237
+ default: false
238
+ }
239
+ },
240
+ data() {
241
+ return {
242
+ DEFAULT_GROUP_NAME,
243
+ // 预览模式
244
+ viewMode: false,
245
+ // 是否处理表单Key值
246
+ isHandleFormKey: true,
247
+ // 内容加载是否完成
248
+ loaded: false,
249
+ // 业务类型
250
+ businessType: '',
251
+ // 业务标题
252
+ title: '',
253
+ // 新增或修改业务是否执行中
254
+ loading: false,
255
+ // 表单Model
256
+ form: {},
257
+ // 配置名称
258
+ configName: undefined,
259
+ // 配置内容,用于查询配置生成器的预览
260
+ configContent: undefined,
261
+ // 表单项集合
262
+ formItems: [],
263
+ // 服务名称
264
+ serviceName: undefined,
265
+ // 是否显示提交按钮
266
+ showSubmitBtn: true,
267
+ // 修改有文件的表单时使用
268
+ files: [],
269
+ images: [],
270
+ // 签名
271
+ signs: [],
272
+ // 校验
273
+ rules: {},
274
+ // 调用logic获取数据源的追加参数
275
+ getDataParams: {},
276
+ // 外部数据(通过 XFormGroup 或直接传入)
277
+ externalData: {},
278
+ // 动态简易表单集合
279
+ simpleFormJsonData: {},
280
+ // 待修改的数据集
281
+ modifyModelData: {},
282
+ // 当前环境
283
+ env: 'prod',
284
+ // 表单主键
285
+ primaryKey: null,
286
+ // 表单模式 horizontal | vertical | inline
287
+ layout: 'horizontal',
288
+ // 提交按钮名称
289
+ btnName: '提交',
290
+ // 提交按钮位置 start / center / end
291
+ btnPlace: 'end',
292
+ // 子表是否排在前面
293
+ childTablePriority: false,
294
+ // simple-inline布局配置
295
+ simpleInline: null,
296
+ // simple-inline模式下是否显示label,默认不显示
297
+ showSimpleInlineLabel: false,
298
+ // 表单组名称(用于 XFormGroup 场景)
299
+ groupName: null,
300
+ // 是否正在刷新表单项(用于避免死循环)
301
+ isRefreshing: false
302
+ }
303
+ },
304
+ computed: {
305
+ // 过滤出用于新增/修改场景的表单项
306
+ realJsonData: function () {
307
+ return this.formItems.filter(item => {
308
+ return (
309
+ item.addOrEdit &&
310
+ item.addOrEdit !== 'no' &&
311
+ item.addOrEdit !== 'silenceAdd' &&
312
+ item.addOrEdit !== 'version' &&
313
+ !this.itemDisabled(item)
314
+ )
315
+ })
316
+ },
317
+ // 表单项组 / 不是 数据组
318
+ groups: function () {
319
+ if (!this.realJsonData || this.realJsonData.length === 0) {
320
+ return [
321
+ {
322
+ groupName: DEFAULT_GROUP_NAME,
323
+ realJsonData: this.realJsonData,
324
+ xAddFormLayout: 'horizontal'
325
+ }
326
+ ]
327
+ }
328
+ const uniqueGroups = new Set(this.realJsonData.map(item => item.group).filter(Boolean))
329
+ const allGroup = Array.from(uniqueGroups).map(group => {
330
+ return {
331
+ groupName: group,
332
+ realJsonData: this.realJsonData.filter(item => item.group === group),
333
+ xAddFormLayout: 'horizontal'
334
+ }
335
+ })
336
+ // 判断每一组得formJson 长度相加是否等于 realJsonData 长度 避免错误数据
337
+ if (allGroup.reduce((total, item) => total + item.realJsonData.length, 0) === this.realJsonData.length) {
338
+ return allGroup
339
+ } else {
340
+ return [
341
+ {
342
+ groupName: DEFAULT_GROUP_NAME,
343
+ realJsonData: this.realJsonData,
344
+ xAddFormLayout: 'horizontal'
345
+ }
346
+ ]
347
+ }
348
+ },
349
+ // 拥有自定义校验函数得表单项
350
+ customValidateItems: function () {
351
+ return this.formItems.filter(item => {
352
+ return item?.rule?.type === 'customJs'
353
+ })
354
+ },
355
+ // 过滤出用于新增/修改场景的表单项
356
+ groupJsonData: function () {
357
+ return this.formItems
358
+ .filter(item => {
359
+ return item.type === 'group'
360
+ })
361
+ .map(item => {
362
+ item.groupItems = item.groupItems
363
+ .filter(item => {
364
+ return (
365
+ item.addOrEdit &&
366
+ item.addOrEdit !== 'no' &&
367
+ item.addOrEdit !== 'silenceAdd' &&
368
+ item.addOrEdit !== 'version' &&
369
+ !this.itemDisabled(item)
370
+ )
371
+ })
372
+ .map(groupItem => {
373
+ // 只保留第一个下划线后面的内容
374
+ // 多层校验规则需要将prop设置为 key1.key2.....
375
+ groupItem.prop = `${item.model}.${groupItem.model.substring(groupItem.model.indexOf('_') + 1)}`
376
+ groupItem.model = groupItem.model.substring(groupItem.model.indexOf('_') + 1)
377
+ return groupItem
378
+ })
379
+ return item
380
+ })
381
+ },
382
+ // 过滤出用于子表数据新增/修改场景的表单项
383
+ childTableData: function () {
384
+ return this.formItems.filter(item => {
385
+ return item.type === 'childTable'
386
+ })
387
+ },
388
+ // 过滤出用于form子表数据新增/修改场景的表单项
389
+ childFormData: function () {
390
+ return this.formItems.filter(item => {
391
+ return item.type === 'rowEdit'
392
+ })
393
+ },
394
+ // 过滤出用于静默新增场景的表单项
395
+ silenceAddJsonData: function () {
396
+ return this.formItems.filter(function (item) {
397
+ return item.addOrEdit === 'silenceAdd'
398
+ })
399
+ },
400
+ // 过滤出版本号表单项
401
+ versionJsonData: function () {
402
+ return this.formItems.filter(function (item) {
403
+ return item.addOrEdit === 'version'
404
+ })
405
+ },
406
+ formItemLayoutGen() {
407
+ if (this.layout === 'simple-inline') {
408
+ // showSimpleInlineLabel: simple-inline模式下是否显示label,默认不显示
409
+ if (this.showSimpleInlineLabel) {
410
+ return {
411
+ labelCol: { span: 4 },
412
+ wrapperCol: { span: 20 }
413
+ }
414
+ }
415
+ return {
416
+ labelCol: { span: 0 },
417
+ wrapperCol: { span: 24 }
418
+ }
419
+ }
420
+ if (this.layout === 'horizontal') {
421
+ // 如果启用了自定义配置,从 formItemLayout 读取(支持 0 值)
422
+ if (this.enableHorizontalCustom && this.formItemLayout) {
423
+ return {
424
+ labelCol: {
425
+ span: this.formItemLayout.labelCol ?? 4,
426
+ offset: this.formItemLayout.offset ?? 2
427
+ },
428
+ wrapperCol: { span: this.formItemLayout.wrapperCol ?? 14 }
429
+ }
430
+ }
431
+ // 默认配置
432
+ return {
433
+ labelCol: { span: 4, offset: 2 },
434
+ wrapperCol: { span: 14 }
435
+ }
436
+ } else if (this.layout === 'vertical') {
437
+ return {}
438
+ } else {
439
+ if (!this.formItemLayout.labelCol || !this.formItemLayout.wrapperCol) {
440
+ return {
441
+ labelCol: { span: 8 },
442
+ wrapperCol: { span: 16 }
443
+ }
444
+ }
445
+ return {
446
+ labelCol: { span: this.formItemLayout.labelCol },
447
+ wrapperCol: { span: this.formItemLayout.wrapperCol }
448
+ }
449
+ }
450
+ },
451
+ // simple-inline模式判断
452
+ isSimpleInlineMode() {
453
+ return this.layout === 'simple-inline' && this.simpleInline
454
+ },
455
+ // simple-inline布局行数据
456
+ simpleInlineRows() {
457
+ if (!this.isSimpleInlineMode) return []
458
+ return this.simpleInline.rows.map(row => ({
459
+ ...row,
460
+ items: row.items
461
+ .map(item => ({
462
+ ...item,
463
+ formItem: this.realJsonData.find(f => f.model === item.key && f.name === item.title)
464
+ }))
465
+ .filter(item => item.formItem)
466
+ }))
467
+ },
468
+ // simple-inline模式下的labelCol配置
469
+ simpleInlineLabelCol() {
470
+ if (this.showSimpleInlineLabel) {
471
+ return { span: 4 }
472
+ }
473
+ return { span: 0 }
474
+ },
475
+ ...mapState('account', { currUser: 'user' })
476
+ },
477
+ provide() {
478
+ return {
479
+ getComponentByName: this.getComponentByName,
480
+ registerComponent: this.registerComponent,
481
+ XFormContext: this,
482
+ // 移除必填项
483
+ removeRequired: this.removeRequired,
484
+ // 设置必填项
485
+ setRequired: this.setRequired,
486
+ getSelf: () => this,
487
+ // 传递 formGroupContext 给子组件
488
+ formGroupContext: this.formGroupContext,
489
+ // 传递外部数据给子组件
490
+ _getExtData: this.getExtData
491
+ }
492
+ },
493
+ watch: {
494
+ form: {
495
+ handler(val) {
496
+ // 如果是 refreshShowFunc 触发的变化,不调用 formDataChange,避免死循环
497
+ if (this.isRefreshing) {
498
+ return
499
+ }
500
+ if (this.formDataChange && typeof this.formDataChange === 'function') {
501
+ // 如果存在 groupName,则传递 groupName 和 formData(用于 XFormGroup 场景)
502
+ if (this.groupName) {
503
+ // 使用防抖避免频繁触发
504
+ if (!this.debouncedFormDataChange) {
505
+ this.debouncedFormDataChange = debounce(() => {
506
+ if (this.formDataChange && typeof this.formDataChange === 'function') {
507
+ this.formDataChange(this.groupName, this.form)
508
+ }
509
+ }, 150)
510
+ }
511
+ this.debouncedFormDataChange()
512
+ } else {
513
+ // 兼容非 XFormGroup 场景
514
+ this.formDataChange(val)
515
+ }
516
+ }
517
+ // 自定义校验红星:本组 form 变化时更新 tempRequired
518
+ if (this.customValidateItems.length > 0) {
519
+ if (!this.debouncedRunCustomValidation) {
520
+ this.debouncedRunCustomValidation = debounce(() => this.runCustomValidationForDisplay(), 150)
521
+ }
522
+ this.debouncedRunCustomValidation()
523
+ }
524
+ },
525
+ deep: true
526
+ }
527
+ },
528
+ mixins: [formValidationMixin],
529
+ methods: {
530
+ runLogic,
531
+ getConfigByNameAsync,
532
+ getConfigByName,
533
+ init(params) {
534
+ this._configEndEmitted = false
535
+ this._configEndPromise = new Promise(resolve => { this._configEndResolve = resolve })
536
+ const {
537
+ configName,
538
+ configContent,
539
+ formItems,
540
+ formJson,
541
+ viewMode,
542
+ isHandleFormKey,
543
+ isKeyHandle = true,
544
+ showSubmitBtn = true,
545
+ serviceName,
546
+ primaryKey,
547
+ modifyModelData = {},
548
+ businessType,
549
+ title,
550
+ fixedAddForm = {},
551
+ getDataParams = {},
552
+ extData = {},
553
+ simpleFormJsonData = {},
554
+ env = 'prod',
555
+ layout,
556
+ xAddFormLayout = 'horizontal',
557
+ formItemLayout = {},
558
+ btnName = '提交',
559
+ childTablePriority = false,
560
+ btnPlace = 'end',
561
+ simpleInline = null,
562
+ showSimpleInlineLabel = false,
563
+ paramLogicName,
564
+ paramLogicServiceName,
565
+ paramLogicNameParam
566
+ } = params
567
+ this.loaded = false
568
+ // 保存表单组名称(用于 XFormGroup 场景)
569
+ this.groupName = params.groupName || null
570
+ // 兼容需要省略 传递 layout: res.xAddFormLayout 可以使用 ...res 展开运算符 直接转递
571
+ if (xAddFormLayout && layout === undefined) {
572
+ this.layout = xAddFormLayout
573
+ } else {
574
+ this.layout = layout
575
+ }
576
+ this.formItemLayout = formItemLayout
577
+ if ((isHandleFormKey === null || isHandleFormKey === undefined) && !isKeyHandle) {
578
+ this.isHandleFormKey = isKeyHandle
579
+ } else if (isHandleFormKey) {
580
+ this.isHandleFormKey = isHandleFormKey
581
+ } else {
582
+ this.isHandleFormKey = isKeyHandle
583
+ }
584
+ this.childTablePriority = childTablePriority
585
+ this.configName = configName
586
+ this.configContent = configContent
587
+ this.formItems = this.getFromItem(formItems, formJson)
588
+ this.viewMode = viewMode
589
+ this.showSubmitBtn = showSubmitBtn
590
+ this.primaryKey = primaryKey
591
+ this.serviceName = serviceName
592
+ this.businessType = businessType
593
+ this.title = title
594
+ this.getDataParams = getDataParams
595
+ this.extData = extData
596
+ this.simpleFormJsonData = simpleFormJsonData
597
+ this.env = env
598
+ this.btnName = btnName
599
+ this.btnPlace = btnPlace
600
+ this.simpleInline = simpleInline
601
+ this.showSimpleInlineLabel = showSimpleInlineLabel
602
+ // 如果 fixedAddForm 有 selected_id 值,并且设置了处理表单key值,则多给 selected_id 加前缀 避免处理错误
603
+ if (fixedAddForm.selected_id && this.isHandleFormKey) {
604
+ fixedAddForm._selected_id = fixedAddForm.selected_id
605
+ delete fixedAddForm.selected_id
606
+ }
607
+ // 设置普通表单项的相关参数
608
+ const formData = Object.assign({}, fixedAddForm)
609
+ if (paramLogicName) {
610
+ // console.warn('2paramLogicServiceName', paramLogicServiceName)
611
+ runLogic(paramLogicName, paramLogicNameParam, (typeof paramLogicServiceName === 'string' && paramLogicServiceName.trim()) || this.serviceName).then(res => {
612
+ Object.assign(formData, res)
613
+ })
614
+ }
615
+ for (let i = 0; i < this.realJsonData.length; i++) {
616
+ const item = this.realJsonData[i]
617
+ this.setFormProps(formData, item, null)
618
+ }
619
+ // 设置表单分组项目相关参数
620
+ for (let i = 0; i < this.groupJsonData.length; i++) {
621
+ const groupItem = this.groupJsonData[i]
622
+ formData[groupItem.model] = {}
623
+ for (let j = 0; j < groupItem.groupItems.length; j++) {
624
+ const item = groupItem.groupItems[j]
625
+ this.setFormProps(formData[groupItem.model], item, item.prop)
626
+ }
627
+ }
628
+ // 设置动态简易表单项的相关参数
629
+ for (const key in this.simpleFormJsonData) {
630
+ for (const item of this.simpleFormJsonData[key].value) {
631
+ item.model = key + '@' + item.model
632
+ this.setFormProps(formData, item, null)
633
+ }
634
+ }
635
+
636
+ // 修改场景下对表单项赋值
637
+ this.form = formData
638
+ if (modifyModelData && modifyModelData.data) {
639
+ this.modifyModelData = modifyModelData
640
+ if (Object.keys(modifyModelData.data).length > 0) {
641
+ this.getModifyModelData(modifyModelData)
642
+ }
643
+ }
644
+ // 处理表单得附件
645
+ if (modifyModelData && modifyModelData.files) {
646
+ this.files = modifyModelData.files
647
+ }
648
+ if (modifyModelData && modifyModelData.images) {
649
+ this.images = modifyModelData.images
650
+ }
651
+ if (modifyModelData && modifyModelData.signs) {
652
+ this.signs = modifyModelData.signs
653
+ }
654
+ this.loaded = true
655
+ this._emitConfigEnd()
656
+ },
657
+ /** 配置加载/应用结束后发出,供 XReport 判断「所有 slot 配置结束」;每次 init 仅发出一次 */
658
+ _emitConfigEnd() {
659
+ if (this._configEndEmitted) return
660
+ this._configEndEmitted = true
661
+ if (this._configEndResolve) {
662
+ this._configEndResolve()
663
+ this._configEndResolve = null
664
+ }
665
+ this.$emit('configEnd')
666
+ },
667
+ /**
668
+ * 等待配置结束的异步方法。配置已结束则立即 resolve,否则在 configEnd 时 resolve。
669
+ * @returns {Promise<void>}
670
+ */
671
+ waitConfigEnd() {
672
+ if (this._configEndEmitted) return Promise.resolve()
673
+ return this._configEndPromise || Promise.resolve()
674
+ },
675
+ getExtData() {
676
+ return this.extData
677
+ },
678
+ scrollToGroup(index) {
679
+ const groupElement = this.$refs[`group-title-${index}`][0]
680
+ if (groupElement) {
681
+ groupElement.scrollIntoView({ behavior: 'smooth' })
682
+ }
683
+ },
684
+ registerComponent(componentName, component) {
685
+ console.log('内部注册', this.$options.name, componentName)
686
+ this.$refs[componentName] = component
687
+ console.log('内部注册完成', this.$refs)
688
+ },
689
+ // 根据名字从注册到组件中获取组件
690
+ getComponentByName(componentName) {
691
+ console.log('内部取组件', this.$options.name, componentName)
692
+ console.log('内部组件内容', this.$refs)
693
+ return this.$refs[componentName]
694
+ },
695
+ // 兼容需要省略 传递 [formItems: res.formJson ] 可以使用 ...res 展开运算符 直接转递
696
+ getFromItem(formItems, formJson) {
697
+ const _formItems = formItems || formJson
698
+ if (typeof formItems === 'string') {
699
+ return JSON.parse(_formItems)
700
+ } else {
701
+ return JSON.parse(JSON.stringify(_formItems))
702
+ }
703
+ },
704
+ innerXFormTableEmit(fun, record, id, actionType, index) {
705
+ this.$emit(fun, record, id, actionType, index)
706
+ },
707
+ // 时间组件赋默认值
708
+ // .type, item.formDefault
709
+ getDateRange({ type, formDefault: defaultValue, formValueFormat }) {
710
+ // const format = type === 'datePicker' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'
711
+ let format = 'YYYY-MM-DD HH:mm:ss'
712
+ if (formValueFormat) {
713
+ format = formValueFormat
714
+ }
715
+ let start
716
+ switch (defaultValue) {
717
+ case 'curYear':
718
+ start = moment().startOf('year').format(format)
719
+ break
720
+ case 'curMonth':
721
+ start = moment().startOf('month').format(format)
722
+ break
723
+ case 'curDay':
724
+ start = moment().startOf('day').format(format)
725
+ break
726
+ case 'curTime':
727
+ start = moment().format(format)
728
+ break
729
+ default:
730
+ return defaultValue
731
+ }
732
+ return start
733
+ },
734
+ setFormProps(formData, item, groupItem) {
735
+ const rulesKey = `${item.name}${item.model}`
736
+ if (formData[item.model] === undefined || formData[item.model] === null) {
737
+ formData[item.model] = undefined
738
+ }
739
+ if (!formData[item.model] && item.formDefault) {
740
+ if (
741
+ ['datePicker', 'rangePicker', 'yearPicker', 'monthPicker', 'yearRangePicker', 'monthRangePicker'].includes(
742
+ item.type
743
+ )
744
+ ) {
745
+ formData[item.model] = this.getDateRange(item)
746
+ } else if (
747
+ ['treeSelect', 'select', 'checkbox'].includes(item.type) &&
748
+ ['curOrgId', 'curDepId', 'curUserId'].includes(item.formDefault)
749
+ ) {
750
+ if (item.formDefault === 'curOrgId') {
751
+ formData[item.model] = item.type === 'select' ? this.currUser.orgid : [this.currUser.orgid]
752
+ }
753
+ if (item.formDefault === 'curDepId') {
754
+ formData[item.model] = item.type === 'select' ? this.currUser.depids : [this.currUser.depids]
755
+ }
756
+ if (item.formDefault === 'curUserId') {
757
+ formData[item.model] = item.type === 'select' ? this.currUser.id : [this.currUser.id]
758
+ }
759
+ } else if (['addressSearch'].includes(item.type)) {
760
+ formData[item.model] = item.formDefault
761
+ formData[`${item.model}_lng_lat`] = item.formDefault_lng_lat
762
+ } else {
763
+ formData[item.model] = item.formDefault
764
+ }
765
+ }
766
+ // 处理表单校验情况
767
+ if (item.rule) {
768
+ const rulesArrayKey = groupItem || rulesKey
769
+ this.rules[rulesArrayKey] = []
770
+ const required = item.rule.required ? item.rule.required === true || item.rule.required === 'true' : false
771
+ let trigger
772
+ let message
773
+ if (required) {
774
+ switch (item.type) {
775
+ case 'select':
776
+ case 'checkbox':
777
+ case 'radio':
778
+ case 'treeSelect':
779
+ case 'rangePicker':
780
+ case 'monthPicker':
781
+ case 'yearPicker':
782
+ case 'datePicker':
783
+ case 'file':
784
+ case 'image':
785
+ case 'citySelect':
786
+ case 'addressSearch':
787
+ case 'personSetting':
788
+ message = '请选择' + item.name
789
+ trigger = 'change'
790
+ break
791
+ default:
792
+ message = '请输入' + item.name
793
+ trigger = 'blur'
794
+ }
795
+ this.rules[rulesArrayKey].push({
796
+ required: true,
797
+ message: message,
798
+ trigger: trigger
799
+ })
800
+ }
801
+ // 文件/图片上传最小数量校验:必填时强制校验;非必填但已上传时也需校验
802
+ if (['file', 'image'].includes(item.type) && item.minAcceptCount) {
803
+ const minCount = Number(item.minAcceptCount)
804
+ this.rules[rulesArrayKey].push({
805
+ validator: (rule, value, callback) => {
806
+ const count = Array.isArray(value) ? value.length : value ? 1 : 0
807
+ if ((required || count > 0) && count < minCount) {
808
+ callback(new Error(`请至少上传${minCount}个${item.name}`))
809
+ } else {
810
+ callback()
811
+ }
812
+ },
813
+ trigger: 'change'
814
+ })
815
+ }
816
+
817
+ switch (item.rule.type) {
818
+ case 'number':
819
+ case 'integer':
820
+ case 'float':
821
+ // eslint-disable-next-line no-case-declarations
822
+ let defaultValue
823
+ // eslint-disable-next-line no-case-declarations
824
+ let message
825
+ switch (item.rule.type) {
826
+ case 'number':
827
+ item.numberInput = true
828
+ message = '数字'
829
+ defaultValue = 0
830
+ break
831
+ case 'integer':
832
+ item.numberInput = true
833
+ message = '整数'
834
+ defaultValue = 0
835
+ break
836
+ case 'float':
837
+ item.numberInput = true
838
+ message = '小数'
839
+ defaultValue = 0.0
840
+ break
841
+ }
842
+ this.rules[rulesArrayKey].push({
843
+ type: item.rule.type,
844
+ message: item.name + '必须为' + message,
845
+ transform: value => {
846
+ if (value && value.length !== 0) {
847
+ return Number(value)
848
+ } else {
849
+ return defaultValue
850
+ }
851
+ },
852
+ trigger: 'blur'
853
+ })
854
+ break
855
+ case 'email': {
856
+ const validator = (rule, value, callback) => {
857
+ if (value && !REG_EMAIL.test(value)) {
858
+ callback(new Error('请输入正确的邮箱地址'))
859
+ } else {
860
+ callback()
861
+ }
862
+ }
863
+ this.rules[rulesArrayKey].push({
864
+ type: 'email',
865
+ validator: validator,
866
+ message: '请输入正确的邮箱地址',
867
+ trigger: 'blur'
868
+ })
869
+ break
870
+ }
871
+ case 'userPhone': {
872
+ this.rules[rulesArrayKey].push({
873
+ type: 'userPhone',
874
+ validator: (rule, value, callback) => {
875
+ if (value && !REG_PHONE.test(value)) {
876
+ callback(new Error('请输入正确的手机号码'))
877
+ } else {
878
+ callback()
879
+ }
880
+ },
881
+ message: '请输入正确的手机号码',
882
+ trigger: 'blur'
883
+ })
884
+ break
885
+ }
886
+ case 'idNumber': {
887
+ this.rules[rulesArrayKey].push({
888
+ validator: (rule, value, callback) => {
889
+ if (value && !checkIdNumber(value)) {
890
+ callback(new Error('请输入正确的身份证号码'))
891
+ } else {
892
+ callback()
893
+ }
894
+ },
895
+ trigger: 'blur'
896
+ })
897
+ break
898
+ }
899
+ case 'landlineNumber': {
900
+ this.rules[rulesArrayKey].push({
901
+ validator: (rule, value, callback) => {
902
+ if (value && !REG_LANDLINE.test(value)) {
903
+ callback(new Error('请输入正确的座机号码'))
904
+ } else {
905
+ callback()
906
+ }
907
+ },
908
+ trigger: 'blur'
909
+ })
910
+ break
911
+ }
912
+ // 大于0
913
+ case 'greaterThanZero': {
914
+ item.numberInput = true
915
+ this.rules[rulesArrayKey].push({
916
+ validator: (rule, value, callback) => {
917
+ if (isNaN(value) || value <= 0) {
918
+ callback(new Error('请输入一个大于0的数字'))
919
+ } else {
920
+ callback()
921
+ }
922
+ },
923
+ trigger: 'blur'
924
+ })
925
+ break
926
+ }
927
+ // 大于等于0
928
+ case 'greaterThanOrEqualZero': {
929
+ item.numberInput = true
930
+ this.rules[rulesArrayKey].push({
931
+ validator: (rule, value, callback) => {
932
+ if (isNaN(value) || value < 0) {
933
+ callback(new Error('请输入一个大于等于0的数字'))
934
+ } else {
935
+ callback()
936
+ }
937
+ },
938
+ trigger: 'blur'
939
+ })
940
+ break
941
+ }
942
+ case 'stringLength': {
943
+ this.rules[rulesArrayKey].push({
944
+ validator: (rule, value, callback) => {
945
+ if (value && value.length < item.rule.minLen) {
946
+ callback(new Error('长度不能少于' + item.rule.minLen + '个字符'))
947
+ } else if (value && value.length > item.rule.maxLen) {
948
+ callback(new Error('长度不能超过' + item.rule.maxLen + '个字符'))
949
+ } else {
950
+ callback()
951
+ }
952
+ },
953
+ trigger: 'blur'
954
+ })
955
+ break
956
+ }
957
+ case 'customJs': {
958
+ this.rules[rulesArrayKey].push({
959
+ validator: (rule, value, callback) => {
960
+ this.customJsValidate(rule, value, callback, item)
961
+ },
962
+ trigger: 'blur'
963
+ })
964
+ break
965
+ }
966
+ }
967
+ }
968
+ },
969
+ childTableMounted(item) {
970
+ // 子表初始化时,设置表格数据
971
+ if (this.form[item.model] && this.form[item.model].length > 0) {
972
+ this.$refs[`childXFormTable_${item.model}`][0].setTableData(this.form[item.model])
973
+ }
974
+ },
975
+ customJsValidate(rule, value, callback, item) {
976
+ if (item.rule.customValidatorFunc) {
977
+ executeStrFunctionByContext(this, item.rule.customValidatorFunc, [
978
+ rule,
979
+ value,
980
+ callback,
981
+ this.form,
982
+ item,
983
+ this.util,
984
+ runLogic,
985
+ getConfigByNameAsync
986
+ ])
987
+ } else {
988
+ callback()
989
+ }
990
+ },
991
+ /**
992
+ * 根据自定义校验函数更新表单项红星状态(tempRequired)及校验规则
993
+ * 支持两种触发:1) 本组 form 变化时由 watch 调用 2) 他组变化时由 refreshShowFunc 调用
994
+ * XFormGroup 场景下,自定义校验函数可通过 this.formGroupContext.allFormData 获取全部表单数据
995
+ */
996
+ runCustomValidationForDisplay() {
997
+ if (!this.customValidateItems || this.customValidateItems.length === 0) return
998
+ for (const item of this.customValidateItems) {
999
+ const itemIndex = this.formItems.findIndex(formItem => formItem.model === item.model)
1000
+ if (itemIndex < 0) continue
1001
+ try {
1002
+ this.customJsValidate(null, this.form[item.model], res => {
1003
+ this.$set(this.formItems[itemIndex], 'tempRequired', res instanceof Error)
1004
+ }, item)
1005
+ } catch (e) {
1006
+ console.error('[XAddNativeForm] runCustomValidationForDisplay:', e)
1007
+ this.$set(this.formItems[itemIndex], 'tempRequired', true)
1008
+ }
1009
+ }
1010
+ },
1011
+ itemDisabled(value) {
1012
+ return (
1013
+ (this.businessType === '新增' && value.addOrEdit === 'edit') ||
1014
+ (this.businessType === '修改' && value.addOrEdit === 'add')
1015
+ )
1016
+ },
1017
+ readonly(value) {
1018
+ return value.addOrEdit === 'readonly'
1019
+ },
1020
+ async onSubmit() {
1021
+ const valid = await this.validateForm()
1022
+ if (!valid) return false
1023
+ if (this.viewMode) {
1024
+ this.$message.info('预览模式禁止新增和修改')
1025
+ return false
1026
+ }
1027
+ this.loading = true
1028
+ const requestForm = this.prepareForm()
1029
+ await this.appendSilenceAddFields(requestForm)
1030
+ const realForm = this.handleFormKeys(requestForm)
1031
+ // 增加子表数据
1032
+ if (this.childTableData.length > 0) {
1033
+ for (const item of this.childTableData) {
1034
+ const childModel = item.model
1035
+ const childDataRef = this.$refs['childXFormTable_' + item.model][0].getTableData()
1036
+ const childData = []
1037
+ for (const item of childDataRef) {
1038
+ childData.push(JSON.parse(JSON.stringify(item)))
1039
+ }
1040
+ for (let i = 0; i < childData.length; i++) {
1041
+ childData[i] = this.handleFormKeys(childData[i])
1042
+ // 外键不需要带表别名,所以此处放到表单处理后赋值
1043
+ if (realForm.id) {
1044
+ childData[i][item.childTableForeignKeyName] = realForm.id
1045
+ }
1046
+ }
1047
+ realForm[childModel] = childData
1048
+ }
1049
+ }
1050
+ // 增加form子表数据
1051
+ if (this.childFormData.length > 0) {
1052
+ for (const item of this.childFormData) {
1053
+ const childModel = item.model
1054
+ const childData = this.$refs[item.model].getTableData()
1055
+ for (let i = 0; i < childData.length; i++) {
1056
+ childData[i] = this.handleFormKeys(childData[i], true)
1057
+ // 外键不需要带表别名,所以此处放到表单处理后赋值
1058
+ if (realForm.id) {
1059
+ childData[i][item.foreignKey] = realForm.id
1060
+ }
1061
+ }
1062
+ realForm[childModel] = childData
1063
+ }
1064
+ }
1065
+ if (this.$listeners.onSubmit) {
1066
+ // 交由父级处理
1067
+ this.$emit('onSubmit', {
1068
+ businessType: this.businessType,
1069
+ serviceName: this.serviceName,
1070
+ realForm: realForm,
1071
+ currUserName: this.currUser.name,
1072
+ currUserId: this.currUser.id,
1073
+ orgId: this.currUser.orgid
1074
+ })
1075
+ } else {
1076
+ this.defaultSubmit(realForm)
1077
+ }
1078
+ },
1079
+
1080
+ async asyncSubmit() {
1081
+ return new Promise((resolve, reject) => {
1082
+ this.$refs.selectForm.validate(async valid => {
1083
+ if (!valid) {
1084
+ reject(new Error('Form validation failed'))
1085
+ return
1086
+ }
1087
+ this.loading = true
1088
+ const requestForm = this.prepareForm()
1089
+ await this.appendSilenceAddFields(requestForm)
1090
+ const realForm = this.handleFormKeys(requestForm)
1091
+ resolve({
1092
+ realForm,
1093
+ businessType: this.businessType,
1094
+ serviceName: this.serviceName,
1095
+ currUserName: this.currUser.name,
1096
+ currUserId: this.currUser.id,
1097
+ orgId: this.currUser.orgid
1098
+ })
1099
+ })
1100
+ })
1101
+ },
1102
+
1103
+ validateForm() {
1104
+ return new Promise(resolve => {
1105
+ this.$refs.selectForm.validate(valid => resolve(valid))
1106
+ })
1107
+ },
1108
+
1109
+ childTableFixedQueryForm(item) {
1110
+ if (this.modifyModelData?.primaryKeyData) {
1111
+ const fixedForm = {}
1112
+ fixedForm[item.childTableForeignKeyName] = Object.values(this.modifyModelData.primaryKeyData)[0]
1113
+ return fixedForm
1114
+ }
1115
+ return null
1116
+ },
1117
+
1118
+ prepareForm() {
1119
+ const form = { ...this.form }
1120
+ for (const key of Object.keys(form)) {
1121
+ const value = form[key]
1122
+ if (value === null || (typeof value === 'object' && Object.keys(value).length === 0)) {
1123
+ form[key] = undefined
1124
+ }
1125
+ }
1126
+ return form
1127
+ },
1128
+
1129
+ async appendSilenceAddFields(form) {
1130
+ if (this.businessType === '新增') {
1131
+ for (const item of this.silenceAddJsonData) {
1132
+ switch (item.silencePurpose) {
1133
+ case 'createTime':
1134
+ form[item.model] = formatDate('now')
1135
+ break
1136
+ case 'operator':
1137
+ form[item.model] = this.currUser.name
1138
+ break
1139
+ case 'operatorId':
1140
+ form[item.model] = this.currUser.id
1141
+ break
1142
+ case 'orgId':
1143
+ form[item.model] = this.currUser.orgid
1144
+ break
1145
+ case 'orgName':
1146
+ form[item.model] = this.currUser.orgs
1147
+ break
1148
+ case 'depId':
1149
+ form[item.model] = this.currUser.depids
1150
+ break
1151
+ case 'depName':
1152
+ form[item.model] = this.currUser.deps
1153
+ break
1154
+ }
1155
+ }
1156
+ for (const item of this.silenceAddJsonData.filter(item => item.silencePurpose === 'customize')) {
1157
+ const result = await runLogic(item.silenceSource, form, this.serviceName)
1158
+ if (result) {
1159
+ const keys = Object.keys(result)
1160
+ if (keys.length === 1 && keys[0] === 'value') {
1161
+ form[item.model] = result.value
1162
+ } else {
1163
+ form[item.model] = result
1164
+ }
1165
+ } else {
1166
+ form[item.model] = result
1167
+ }
1168
+ }
1169
+ }
1170
+ },
1171
+
1172
+ handleFormKeys(form, mustHandleKey = false) {
1173
+ const realForm = {}
1174
+ for (const key of Object.keys(form)) {
1175
+ const value = form[key]
1176
+ const extraFormKeyTagIndex = key.indexOf('@')
1177
+ if (extraFormKeyTagIndex !== -1) {
1178
+ const extraFormKey = key.substring(0, extraFormKeyTagIndex)
1179
+ const realKey = key.substring(extraFormKeyTagIndex + 1)
1180
+ if (!realForm[extraFormKey]) {
1181
+ realForm[extraFormKey] = {}
1182
+ }
1183
+ realForm[extraFormKey][realKey] = value
1184
+ } else {
1185
+ const realKey = this.isHandleFormKey || mustHandleKey ? this.getRealKey(key, mustHandleKey) : key
1186
+ // 如果发生重名,不覆盖,把key的别名带上
1187
+ if (realForm[realKey]) {
1188
+ realForm[key] = value
1189
+ } else {
1190
+ realForm[realKey] = value
1191
+ }
1192
+ }
1193
+ }
1194
+ return realForm
1195
+ },
1196
+ // 默认提交事件
1197
+ defaultSubmit(realForm, callback) {
1198
+ // 新增移除id
1199
+ if (this.businessType === '新增') {
1200
+ delete realForm.id
1201
+ }
1202
+ // 组织请求
1203
+ const requestParameters = {
1204
+ queryParamsName: this.configName,
1205
+ queryParams: this.configContent,
1206
+ form: realForm,
1207
+ businessType: this.businessType,
1208
+ operator: this.currUser.name
1209
+ }
1210
+ addOrModify(requestParameters, this.serviceName, this.env === 'dev')
1211
+ .then(data => {
1212
+ this.$message.success(this.businessType + '成功!')
1213
+ // commit
1214
+ this.$emit('afterSubmit', {
1215
+ type: this.businessType,
1216
+ id: data.id,
1217
+ data: data,
1218
+ form: requestParameters.form
1219
+ })
1220
+ this.loading = false
1221
+ if (callback) {
1222
+ callback()
1223
+ }
1224
+ })
1225
+ .catch(e => {
1226
+ this.loading = false
1227
+ this.$message.error(this.businessType + '失败:' + e)
1228
+ })
1229
+ },
1230
+ // 获取表单字段实际值
1231
+ getRealKey(key, mustHandleKey = false) {
1232
+ if (key === 'selected_id') return key
1233
+ if (this.isHandleFormKey || mustHandleKey) {
1234
+ return key.substring(key.indexOf('_') + 1)
1235
+ } else {
1236
+ return key
1237
+ }
1238
+ },
1239
+ /**
1240
+ * 获取被修改记录数据
1241
+ * @param modifyModelData 被修改记录的数据
1242
+ */
1243
+ getModifyModelData(modifyModelData) {
1244
+ if (modifyModelData.primaryKeyData) {
1245
+ this.form = Object.assign(this.form, modifyModelData.primaryKeyData)
1246
+ }
1247
+ // 对动态简易表单项特殊处理
1248
+ for (const key in modifyModelData.data) {
1249
+ const realKey = this.isHandleFormKey ? this.getRealKey(key) : key
1250
+ if (this.simpleFormJsonData[realKey]) {
1251
+ const extraForm = JSON.parse(modifyModelData.data[key])
1252
+ for (const key in extraForm) {
1253
+ const model = realKey + '@' + key
1254
+ this.form[model] = extraForm[key]
1255
+ }
1256
+ }
1257
+ }
1258
+ // 对普通表单项处理
1259
+ for (let i = 0; i < this.realJsonData.length; i++) {
1260
+ if (['FilesId', 'Images'].includes(this.realJsonData[i])) {
1261
+ // 附件需要跳过 因为会通过 modifyModelData中的files,images属性给upload赋值
1262
+ // 新增修改表单每次提交时只会提交最新添加的文件
1263
+ continue
1264
+ }
1265
+ const item = this.realJsonData[i]
1266
+ // 地址选择器 需要传递 经纬度字段, 配置中添加 `${item.model}_lng_lat` CRUD 只需勾选 SQL生成查询项
1267
+ if (['addressSearch'].includes(item.type)) {
1268
+ this.form[item.model] = modifyModelData.data[item.model] + ''
1269
+ this.form[`${item.model}_lng_lat`] = modifyModelData.data[`${item.model}_lng_lat`] + ''
1270
+ continue
1271
+ }
1272
+ if (modifyModelData.data[item.model] || modifyModelData.data[item.model] === 0) {
1273
+ if (modifyModelData.data[item.model] instanceof Array) {
1274
+ this.form[item.model] = modifyModelData.data[item.model]
1275
+ } else {
1276
+ this.form[item.model] = modifyModelData.data[item.model] + ''
1277
+ }
1278
+ }
1279
+ }
1280
+ // 对分组表单进行处理
1281
+ for (let i = 0; i < this.groupJsonData.length; i++) {
1282
+ const item = this.groupJsonData[i]
1283
+ try {
1284
+ if (modifyModelData.data[item.model]) {
1285
+ this.form[item.model] = JSON.parse(modifyModelData.data[item.model])
1286
+ }
1287
+ } catch (e) {
1288
+ if (modifyModelData.data[item.model]) {
1289
+ this.form[item.model] = modifyModelData.data[item.model]
1290
+ }
1291
+ }
1292
+ }
1293
+ // 追加版本号信息
1294
+ for (const item of this.versionJsonData) {
1295
+ if (!modifyModelData.data[item.model]) {
1296
+ this.form[item.model] = 0
1297
+ } else {
1298
+ this.form[item.model] = modifyModelData.data[item.model] + ''
1299
+ }
1300
+ }
1301
+ },
1302
+ setForm(obj) {
1303
+ this.form = Object.assign(this.form, obj)
1304
+ // 给子表赋外键条件
1305
+ if (this.childFormData.length > 0) {
1306
+ for (const item of this.childFormData) {
1307
+ const child = this.$refs[item.model]
1308
+ // 获取子表别名,以便在条件上添加别名
1309
+ const alias = child.realQueryConfig.tableAliasName
1310
+ // 有主键,且主键有值,添加主键条件
1311
+ if (this.primaryKey && this.form[this.primaryKey]) {
1312
+ const foreignKey = item.foreignKey
1313
+ const fixedQueryForm = {
1314
+ [alias + '_' + foreignKey]: this.form[this.primaryKey]
1315
+ }
1316
+ if (!child.fixedQueryForm) {
1317
+ child.fixedQueryForm = fixedQueryForm
1318
+ } else {
1319
+ Object.assign(child.fixedQueryForm, fixedQueryForm)
1320
+ }
1321
+ child.refreshTable()
1322
+ }
1323
+ }
1324
+ }
1325
+ },
1326
+ setFormWithKey(obj) {
1327
+ setDataByRealKey(this.form, obj)
1328
+ },
1329
+ setFormWithNoKey(obj) {
1330
+ setDataByRealKey(this.form, obj)
1331
+ },
1332
+ emitFunc(func, data, value) {
1333
+ this.$emit(func, data, value)
1334
+ this.$emit('x-form-item-emit-func', func, data, value)
1335
+ },
1336
+ // 直接转发事件的函数
1337
+ emitEvent(event, ...args) {
1338
+ this.$emit(event, ...args)
1339
+ },
1340
+ close() {
1341
+ this.loaded = false
1342
+ },
1343
+ /**
1344
+ * 行选择事件
1345
+ * @param row 选中行集合
1346
+ * @param attr 表单项属性
1347
+ */
1348
+ async rowChoose(row, attr, callback) {
1349
+ // 如果配置了自定义函数
1350
+ if (attr.dataChangeFunc) {
1351
+ await executeStrFunction(attr.dataChangeFunc, [
1352
+ this.form,
1353
+ this.setForm,
1354
+ {
1355
+ ...attr,
1356
+ selectRows: row
1357
+ },
1358
+ util,
1359
+ this.mode,
1360
+ runLogic,
1361
+ getConfigByNameAsync
1362
+ ])
1363
+ } else {
1364
+ // 默认填充选中行数据到当前表单
1365
+ setDataByRealKey(this.form, row[0])
1366
+ }
1367
+ if (callback) {
1368
+ callback()
1369
+ }
1370
+ },
1371
+ /**
1372
+ * 刷新表单项展示函数
1373
+ * 通过修改 form 并添加时间戳来触发 watch form,从而自动触发 showFormItemFunc 重新计算
1374
+ * 他组数据变化时由 XFormGroup.handleFormDataChange 调用,此时 allFormData 已更新
1375
+ */
1376
+ refreshShowFunc() {
1377
+ // 自定义校验红星:他组变化时更新 tempRequired(可访问 formGroupContext.allFormData)
1378
+ if (this.customValidateItems && this.customValidateItems.length > 0) {
1379
+ this.runCustomValidationForDisplay()
1380
+ }
1381
+ // 设置标志位,避免触发 formDataChange 导致死循环
1382
+ this.isRefreshing = true
1383
+ // 修改 form 中的时间戳字段,触发 watch form,从而自动触发 showFormItemFunc
1384
+ this.$set(this.form, '__refreshTimestamp__', Date.now())
1385
+ // 在下一个 tick 重置标志位
1386
+ this.$nextTick(() => {
1387
+ this.isRefreshing = false
1388
+ })
1389
+ }
1390
+ }
1391
+ }
1392
+ </script>
1393
+
1394
+ <style scoped lang="less">
1395
+ :deep(.ant-form-inline .ant-form-item) {
1396
+ display: block !important;
1397
+ }
1398
+
1399
+ :deep(.ant-form-item-with-help) {
1400
+ margin-bottom: 0;
1401
+ }
1402
+
1403
+ .xFormGroupTitle {
1404
+ font-weight: bold;
1405
+ color: @primary-color;
1406
+ }
1407
+
1408
+ .simple-inline-item {
1409
+ max-width: 100% !important;
1410
+ }
1411
+
1412
+ /* simple-inline模式样式 */
1413
+ :deep(.simple-inline-item) {
1414
+ max-width: 100% !important;
1415
+
1416
+ .ant-form-item {
1417
+ margin: 0 !important;
1418
+ padding: 2px !important;
1419
+ }
1420
+
1421
+ .ant-form-item-control-wrapper,
1422
+ .ant-form-item-control {
1423
+ width: 100% !important;
1424
+ }
1425
+ }
1426
+
1427
+ /* simple-inline模式下隐藏label(默认行为) */
1428
+ :deep(.simple-inline-item) .ant-form-item-label {
1429
+ display: none !important;
1430
+ }
1431
+
1432
+ /* simple-inline模式下显示label时,给label区域设置宽度 */
1433
+ :deep(.simple-inline-item.show-label) .ant-form-item-label {
1434
+ display: block !important;
1435
+ width: 80px !important;
1436
+ flex-shrink: 0;
1437
+ }
1438
+
1439
+ :deep(.simple-inline-item.show-label) .ant-form-item-control-wrapper {
1440
+ width: calc(100% - 80px) !important;
1441
+ }
1442
+
1443
+ /* 表单底部按钮区域样式 */
1444
+ .form-footer-row {
1445
+ margin-top: 16px;
1446
+
1447
+ :deep(.ant-btn) {
1448
+ margin-left: 8px;
1449
+
1450
+ &:first-child {
1451
+ margin-left: 0;
1452
+ }
1453
+ }
1454
+ }
1455
+ </style>