vue2-client 1.21.13 → 1.21.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.21.13",
3
+ "version": "1.21.14",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -201,7 +201,7 @@ import { formatDate, setDataByRealKey } from '@vue2-client/utils/util'
201
201
  import * as util from '@vue2-client/utils/util'
202
202
  import { mapState } from 'vuex'
203
203
  import { addOrModify, getConfigByName, getConfigByNameAsync, runLogic } from '@vue2-client/services/api/common'
204
- import {checkIdNumber, REG_EMAIL, REG_LANDLINE, REG_PHONE, REG_PHONE_MASKED} from '@vue2-client/utils/reg'
204
+ import { checkIdNumber, isMaskedPhone, REG_EMAIL, REG_LANDLINE, REG_PHONE } from '@vue2-client/utils/reg'
205
205
  import moment from 'moment/moment'
206
206
  import { executeStrFunction, executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
207
207
  import formValidationMixin from '@vue2-client/mixins/formValidationMixin'
@@ -855,14 +855,19 @@ export default {
855
855
  this.rules[rulesArrayKey].push({
856
856
  type: 'userPhone',
857
857
  validator: (rule, value, callback) => {
858
- if(value && REG_PHONE_MASKED.test(value)){
858
+ if (!value) {
859
859
  callback()
860
+ return
860
861
  }
861
- if (value && !REG_PHONE.test(value)) {
862
- callback(new Error('请输入正确的手机号码'))
863
- } else {
862
+ if (isMaskedPhone(value)) {
864
863
  callback()
864
+ return
865
+ }
866
+ if (!REG_PHONE.test(value)) {
867
+ callback(new Error('请输入正确的手机号码'))
868
+ return
865
869
  }
870
+ callback()
866
871
  },
867
872
  message: '请输入正确的手机号码',
868
873
  trigger: 'blur'
@@ -872,11 +877,15 @@ export default {
872
877
  case 'idNumber': {
873
878
  this.rules[rulesArrayKey].push({
874
879
  validator: (rule, value, callback) => {
875
- if (value && !checkIdNumber(value)) {
876
- callback(new Error('请输入正确的身份证号码'))
877
- } else {
880
+ if (!value) {
878
881
  callback()
882
+ return
883
+ }
884
+ if (!checkIdNumber(value)) {
885
+ callback(new Error('请输入正确的身份证号码'))
886
+ return
879
887
  }
888
+ callback()
880
889
  },
881
890
  trigger: 'blur'
882
891
  })
@@ -885,11 +894,19 @@ export default {
885
894
  case 'landlineNumber': {
886
895
  this.rules[rulesArrayKey].push({
887
896
  validator: (rule, value, callback) => {
888
- if (value && !REG_LANDLINE.test(value)) {
889
- callback(new Error('请输入正确的座机号码'))
890
- } else {
897
+ if (!value) {
898
+ callback()
899
+ return
900
+ }
901
+ if (isMaskedPhone(value)) {
891
902
  callback()
903
+ return
904
+ }
905
+ if (!REG_LANDLINE.test(value)) {
906
+ callback(new Error('请输入正确的座机号码'))
907
+ return
892
908
  }
909
+ callback()
893
910
  },
894
911
  trigger: 'blur'
895
912
  })
@@ -1064,24 +1081,33 @@ export default {
1064
1081
  },
1065
1082
 
1066
1083
  async asyncSubmit() {
1084
+ const selectForm = this.$refs.selectForm
1085
+ if (!selectForm) {
1086
+ return Promise.reject(new Error('表单尚未加载完成'))
1087
+ }
1067
1088
  return new Promise((resolve, reject) => {
1068
- this.$refs.selectForm.validate(async valid => {
1089
+ selectForm.validate(async valid => {
1069
1090
  if (!valid) {
1070
1091
  reject(new Error('Form validation failed'))
1071
1092
  return
1072
1093
  }
1073
- this.loading = true
1074
- const requestForm = this.prepareForm()
1075
- await this.appendSilenceAddFields(requestForm)
1076
- const realForm = this.handleFormKeys(requestForm)
1077
- resolve({
1078
- realForm,
1079
- businessType: this.businessType,
1080
- serviceName: this.serviceName,
1081
- currUserName: this.currUser.name,
1082
- currUserId: this.currUser.id,
1083
- orgId: this.currUser.orgid
1084
- })
1094
+ try {
1095
+ this.loading = true
1096
+ const requestForm = this.prepareForm()
1097
+ await this.appendSilenceAddFields(requestForm)
1098
+ const realForm = this.handleFormKeys(requestForm)
1099
+ resolve({
1100
+ realForm,
1101
+ businessType: this.businessType,
1102
+ serviceName: this.serviceName,
1103
+ currUserName: this.currUser.name,
1104
+ currUserId: this.currUser.id,
1105
+ orgId: this.currUser.orgid
1106
+ })
1107
+ } catch (error) {
1108
+ this.loading = false
1109
+ reject(error)
1110
+ }
1085
1111
  })
1086
1112
  })
1087
1113
  },
@@ -319,10 +319,11 @@ export default {
319
319
  })
320
320
  },
321
321
  scrollToGroup(index) {
322
- const groupElement = this.$refs[`group-${index}`][0]
323
- if (groupElement) {
324
- groupElement.scrollIntoView({ behavior: 'smooth' })
325
- }
322
+ const groupElement = this.$refs[`group-${index}`]?.[0]
323
+ if (!groupElement) return
324
+
325
+ this.activeTab = index
326
+ groupElement.scrollIntoView({ behavior: 'smooth', block: 'start' })
326
327
  },
327
328
  /**
328
329
  * 控制表单组的显示/隐藏
@@ -413,6 +414,7 @@ export default {
413
414
  },
414
415
  async onSubmit() {
415
416
  let pass = true
417
+ let firstFailedIndex = -1
416
418
  const promises = this.groups.map((item, index) => {
417
419
  const nativeFormRef = this.$refs[`nativeForm-${index}`] ? this.$refs[`nativeForm-${index}`][0] : undefined
418
420
  if ((item.groupName || item.slotName) && nativeFormRef && typeof nativeFormRef.asyncSubmit === 'function') {
@@ -424,7 +426,10 @@ export default {
424
426
  })
425
427
  .catch(_err => {
426
428
  pass = false
427
- this.scrollToGroup(index)
429
+ // 记录最靠前的失败组,避免并行校验时多次 scrollToGroup 互相覆盖
430
+ if (firstFailedIndex === -1 || index < firstFailedIndex) {
431
+ firstFailedIndex = index
432
+ }
428
433
  })
429
434
  } else {
430
435
  console.warn(item.groupName + '未找到组件,或者组件没有 asyncSubmit 方法')
@@ -435,10 +440,12 @@ export default {
435
440
 
436
441
  try {
437
442
  await Promise.all(promises)
438
-
439
443
  if (pass) {
440
444
  return Promise.resolve(this.allFormData)
441
445
  } else {
446
+ if (firstFailedIndex !== -1) {
447
+ this.scrollToGroup(firstFailedIndex)
448
+ }
442
449
  this.$message.error('请检查表单填写是否正确')
443
450
  return Promise.reject(new Error('Form validation failed'))
444
451
  }
@@ -1,88 +1,500 @@
1
+ <template>
2
+ <a-card :bordered="false">
3
+ <x-form-table
4
+ title="档案管理"
5
+ :queryParamsName="queryParamsName"
6
+ @edit="editUser"
7
+ @afterQuery="afterQuery"
8
+ serviceName="af-revenue"
9
+ ref="xFormTable"
10
+ >
11
+ </x-form-table>
12
+ <a-modal
13
+ :confirm-loading="confirmLoading"
14
+ v-model="formModalVisible"
15
+ :dialog-style="{ top: '30px' }"
16
+ :bodyStyle="{ height: '70vh' }"
17
+ :destroy-on-close="true"
18
+ :title="formTitle"
19
+ :keyboard="false"
20
+ @ok="submitAddForm"
21
+ width="85vw"
22
+ >
23
+ <x-form-group ref="xFormGroupDemo" @x-form-item-emit-func="groupFromItemEmitFunc">
24
+ <template #devices="{ data, index }">
25
+ <user-devices
26
+ @setRef="setRef(`nativeForm-${index}`)"
27
+ :ref="`nativeForm-${index}`"
28
+ :data="data"
29
+ ></user-devices>
30
+ </template>
31
+ <template #security="{ data, index }">
32
+ <user-security
33
+ @setRef="setRef1(`nativeForm-${index}`)"
34
+ :ref="`nativeForm-${index}`"
35
+ :data="data"
36
+ ></user-security>
37
+ </template>
38
+ </x-form-group>
39
+ </a-modal>
40
+ </a-card>
41
+ </template>
42
+
1
43
  <script>
2
- import XFormGroup from '@vue2-client/base-client/components/common/XFormGroup/XFormGroup.vue'
3
- import {getConfigByNameAsync} from '@vue2-client/services/api/common'
44
+ import XFormTable from '@vue2-client/base-client/components/common/XFormTable'
45
+ import XFormGroup from '@vue2-client/base-client/components/common/XFormGroup'
46
+ import XAddNativeForm from '@vue2-client/base-client/components/common/XAddNativeForm'
47
+ import XDescriptionsGroup from '@vue2-client/base-client/components/common/XDescriptions/XDescriptionsGroup.vue'
48
+ import XAddForm from '@vue2-client/base-client/components/common/XAddForm'
49
+ import { mapState } from 'vuex'
50
+ import {getConfigByNameAsync, runLogic} from '@vue2-client/services/api/common'
51
+ import { getRealKeyData } from '@vue2-client/utils/formatter'
52
+ import userInfoDetailManage from '@vue2-client/pages/userInfoDetailManage'
4
53
 
5
54
  export default {
6
- name: 'Demo',
7
- components: {XFormGroup},
55
+ name: 'UserFilesManage',
56
+ components: {
57
+ XFormTable,
58
+ XFormGroup,
59
+ XDescriptionsGroup,
60
+ XAddNativeForm,
61
+ XAddForm,
62
+ userInfoDetailManage
63
+ },
8
64
  data() {
9
65
  return {
10
- visible: true,
11
- /** 与 XFormGroup 内 allFormData 同步,用于展示总表单数据 */
12
- allFormDataSnapshot: {}
66
+ // 查询配置名称
67
+ queryParamsName: 'UserFilesListCRUD',
68
+ // 查询表单赋值
69
+ fixedQueryForm: {},
70
+ // 是否显示详情抽屉
71
+ detailVisible: false,
72
+ userInfoDetailVisible: false,
73
+ // 提交加载动画
74
+ confirmLoading: false,
75
+ // 是否显示详情抽屉
76
+ formModalVisible: false,
77
+ // 是否展示选择地址组件
78
+ selectAddressVisible: false,
79
+ accountClosureShow: false,
80
+ batchCancelUser: false,
81
+ accountClosureType: '',
82
+ oneUserManyMetersShow: false,
83
+ isSyncUser: false,
84
+ keyboard: false,
85
+ // 当前记录
86
+ record: {},
87
+ // 销户启用相关
88
+ enableUserVisible: false,
89
+ enableUserRecord: null,
90
+ enableUserReason: '',
91
+ enableUserLoading: false,
92
+ // 表单组title
93
+ formTitle: '新建档案',
94
+ // 修改设备列表
95
+ editDevices: [],
96
+ // 记录当前页面数据
97
+ curPageData: undefined,
98
+ // 查询参数
99
+ conditionParams: undefined,
100
+ securityDevices: [],
101
+ // 修改备用电话列表
102
+ rentPhone: [],
103
+ // 是否修改过备用电话标识
104
+ isEditRentPhone: false,
105
+ // 选择的省市区列表
106
+ divisions: undefined,
107
+ form: {
108
+ f_address_type: '',
109
+ f_residential_area_id: '',
110
+ f_street: '',
111
+ f_residential_area: '',
112
+ f_iscity: ''
113
+ },
114
+ addressModel: [
115
+ {
116
+ expression: '{f_building}楼号{f_unit}单元{f_floor}楼层{f_room}门牌号',
117
+ label: '城市',
118
+ value: '城市'
119
+ },
120
+ {
121
+ expression: '{f_building}组{f_unit}号',
122
+ label: '乡镇',
123
+ value: '乡镇'
124
+ },
125
+ {
126
+ expression: '{f_address}',
127
+ label: '自定义',
128
+ value: '自定义'
129
+ }
130
+ ],
131
+ config: {
132
+ showStreet: false, // 新增地址展示街道
133
+ autoEdit: false, // 选择小区后自动填充表单
134
+ isAutoEdit: false, // 选择小区后自动填充表单
135
+ addAddress: false // 获取定位后重新新建地址
136
+ },
137
+ addAddressFlag: false,
138
+ labelCol: { span: 4 },
139
+ wrapperCol: { span: 20 },
140
+ formItems: [],
141
+ areaList: [],
142
+ streetList: [],
143
+ street: '',
144
+ signContractVisible: false,
145
+ // 当前同步的用户记录
146
+ currentSyncRecord: {},
147
+ // 选中数据
148
+ finalSelectedRows: [],
149
+ // 销户启用表单数据
150
+ enableUserForm: {}
13
151
  }
14
152
  },
15
153
  created() {
16
- getConfigByNameAsync('changeMeterFormGroup', 'af-revenue').then(res => {
17
- this.$refs.xFormGroupDemo.init({
18
- ...res,
19
- serviceName: 'af-revenue',
20
- formShow: {showfillgasInfo: false},
21
- modifyModelData: { },
22
- extData: {
23
- user:{}
24
- }
25
- })
154
+ getConfigByNameAsync('UserFilesManageConfig', 'af-revenue').then(res => {
155
+ this.config = Object.assign(this.config, res)
156
+ console.log(this.config)
157
+ if (this.config.showStreet) {
158
+ this.getStreetList('')
159
+ } else {
160
+ this.getAreaList('')
161
+ }
26
162
  })
27
163
  },
28
- computed: {
29
- allFormDataJson() {
30
- try {
31
- return JSON.stringify(this.allFormDataSnapshot, null, 2)
32
- } catch (e) {
33
- return String(e)
34
- }
164
+ mounted() {
165
+ this.batchCancelUser = this.$login.r.includes('V4批量销户')
166
+ },
167
+ watch: {
168
+ 'form.f_address_type'(newVal, oldVal) {
169
+ this.onAddressTypeChange(newVal, oldVal)
35
170
  }
36
171
  },
37
172
  methods: {
38
- /**
39
- * 事件参数为 (groupName, 当前组 formData),但总数据已在子组件 allFormData 中合并完毕
40
- */
41
- xFormGroupDataChange() {
42
- const group = this.$refs.xFormGroupDemo
43
- if (!group || !group.allFormData) return
44
- this.allFormDataSnapshot = JSON.parse(JSON.stringify(group.allFormData))
45
- },
46
- submitForm() {
47
- this.$refs.xFormGroupDemo.onSubmit().then(res => {
48
- console.log('所有表单的结果', res)
173
+ refresh() {
174
+ this.$refs.xFormTable.refreshTable(true)
175
+ },
176
+
177
+ cancel() {
178
+ this.formCancelUser = false
179
+ this.$refs.xFormTable.refreshTable(true)
180
+ },
181
+ afterQuery(res, conditionParams) {
182
+ console.log('查询触发之后', res, conditionParams)
183
+ res.then(r => {
184
+ this.curPageData = r
185
+ this.conditionParams = conditionParams
49
186
  })
50
187
  },
51
- async meterBaseChange(attr, value) {
52
- if (!(value || value === 0)) {
53
- return
188
+
189
+ handleSearch(value) {
190
+ this.getAreaList(value)
191
+ },
192
+
193
+ getStreetList(value) {
194
+ runLogic(
195
+ 'getStreetListByName',
196
+ {
197
+ orgId: this.currUser.orgid,
198
+ name: value
199
+ },
200
+ 'af-revenue'
201
+ ).then(res => {
202
+ console.log(res)
203
+ this.streetList = res
204
+ })
205
+ },
206
+ async getAreaList(name) {
207
+ // 新版必须带街道ID
208
+ const params = this.config.showStreet
209
+ ? { orgId: this.currUser.orgid, f_street_id: this.street, name }
210
+ : { orgId: this.currUser.orgid, name }
211
+ const res = await runLogic('getAreaListByName', params, 'af-revenue')
212
+ this.areaList = res
213
+ },
214
+ handleChange(value) {
215
+ this.form.f_residential_area = this.areaList.find(item => item.value === value).label
216
+ this.street = this.areaList.find(item => item.value === value).f_street
217
+ },
218
+ onAddressTypeChange(newVal, oldVal) {
219
+ const selectedModel = this.addressModel.find(item => item.value === this.form.f_address_type)
220
+ Object.keys(this.form).forEach(key => {
221
+ if (key.endsWith('_suffix')) {
222
+ this.form[key] = ''
223
+ }
224
+ })
225
+ console.log('selectedModel' + selectedModel)
226
+ if (selectedModel) {
227
+ const matches = selectedModel.expression.match(/{(.*?)}([^{}]*)(?={|$)/g)
228
+ this.formItems = matches.map(item => {
229
+ const value = item.match(/{(.*?)}/)[1]
230
+ const label = item.replace(/{.*?}/, '').trim()
231
+ // 处理后缀
232
+ this.form[`${value}_suffix`] = label
233
+ return {
234
+ label: label || (value === 'f_address' || value === 'f_room' ? '' : value), // 如果存在后面的文字,就使用后面的文字作为 label,否则使用原来的值
235
+ value: `${value}`
236
+ }
237
+ })
54
238
  }
55
- this.$refs.xFormGroupDemo.updateGroupValues('fillgasInfo', {
56
- f_remanent_gas: value + 11,
57
- f_stair_use: 12
239
+ },
240
+ columnClick(key, value, record) {
241
+ this.record = record
242
+ this.record.f_userinfo_id = record.u_f_userinfo_id
243
+ this.record.f_userinfo_code = record.u_f_userinfo_code
244
+ this.userInfoDetailVisible = true
245
+ },
246
+ setRef(refName) {
247
+ // 给表单组赋值ref
248
+ // 因为提交的时候 表单组需要循环便利 ref 的 提交事件
249
+ this.$refs.xFormGroupDemo.setRef(refName, [this.$refs[refName]])
250
+ this.$refs[refName].init(this.editDevices)
251
+ },
252
+ setRef1(refName) {
253
+ // 给表单组赋值ref
254
+ // 因为提交的时候 表单组需要循环便利 ref 的 提交事件
255
+ this.$refs.xFormGroupDemo.setRef(refName, [this.$refs[refName]])
256
+ this.$refs[refName].init(this.securityDevices)
257
+ },
258
+ editUser(record, id, type) {
259
+ this.confirmLoading = false
260
+ this.formTitle = '编辑档案'
261
+ this.config.autoEdit = false // 编辑档案时选择地址不自动回填
262
+ const _record = getRealKeyData(record)
263
+ getConfigByNameAsync('editUserGeneralInfoFrom', 'af-revenue').then(configRes => {
264
+ runLogic(
265
+ 'getFileDetailForEdit',
266
+ {
267
+ f_userinfo_id: _record.f_userinfo_id
268
+ },
269
+ 'af-revenue',
270
+ false,
271
+ {
272
+ globalLoading: true
273
+ }
274
+ ).then(res => {
275
+ this.formModalVisible = true
276
+ // 组织修改表单
277
+ this.$nextTick(() => {
278
+ this.$refs.xFormGroupDemo.init({
279
+ ...configRes,
280
+ serviceName: 'af-revenue',
281
+ showLeftTab: true,
282
+ businessType: '编辑',
283
+ modifyModelData: res
284
+ })
285
+ this.editDevices = res.devices
286
+ this.securityDevices = res.security
287
+ this.rentPhone = res.phones
288
+ })
289
+ })
290
+ })
291
+ },
292
+ addUser() {
293
+ this.formTitle = '新建档案'
294
+ if (this.config.isAutoEdit) {
295
+ this.config.autoEdit = true
296
+ } // 新建档案时选择地址自动回填
297
+ getConfigByNameAsync('addUserGeneralInfoFrom', 'af-revenue').then(res => {
298
+ this.formModalVisible = true
299
+ this.$nextTick(() => {
300
+ this.$refs.xFormGroupDemo.init({
301
+ ...res,
302
+ serviceName: 'af-revenue',
303
+ showLeftTab: true,
304
+ businessType: '新增'
305
+ })
306
+ })
58
307
  })
59
- if(this.allFormDataSnapshot.baseInfo.f_gasmodel_id) {
60
- this.$refs.xFormGroupDemo.xFormShow('x-form-show', 'fillgasInfo', 2)
61
- }
308
+ },
309
+ async submitAddForm() {
310
+ if (this.confirmLoading) return
311
+ this.confirmLoading = true
312
+ await this.$refs.xFormGroupDemo
313
+ .onSubmit()
314
+ .then(res => {
315
+ console.warn('走到这个then了')
316
+ let saveData = Object.assign(res, { divisions: this.divisions })
317
+ if (this.formTitle === '编辑档案') {
318
+ saveData = Object.assign(saveData, {
319
+ f_operator_record: this.currUser.name,
320
+ f_operatorid_record: this.currUser.id,
321
+ f_orgid_record: this.currUser.orgid,
322
+ f_orgname_record: this.currUser.orgs,
323
+ f_depid_record: this.currUser.depids,
324
+ f_depname_record: this.currUser.dops
325
+ })
326
+ }
327
+ // 备用电话赋值
328
+ if (this.isEditRentPhone) {
329
+ saveData = Object.assign(saveData, {
330
+ rentPhone: this.rentPhone
331
+ })
332
+ }
333
+ if (this.isSyncUser) {
334
+ saveData = Object.assign(saveData, {
335
+ f_send_state: '已同步'
336
+ })
337
+ }
338
+ runLogic('userFIleSaveLogic', saveData, 'af-revenue')
339
+ .then(() => {
340
+ this.confirmLoading = false
341
+ this.formModalVisible = false
342
+ this.isSyncUser = false
343
+ this.$message.success('操作成功')
344
+ this.$refs.xFormTable.refreshTable(true)
345
+ })
346
+ .catch(() => {
347
+ this.confirmLoading = false
348
+ })
349
+ .finally(() => {
350
+ this.confirmLoading = false
351
+ })
352
+ })
353
+ .catch(() => {
354
+ console.warn('走到这个catch了')
355
+ this.confirmLoading = false
356
+ })
357
+ .finally(() => {
358
+ console.warn('走到这个finally了')
359
+ this.confirmLoading = false
360
+ })
361
+ this.confirmLoading = false
362
+ },
363
+ action(record, id, actionType) {
364
+ runLogic(
365
+ 'querySingleUserDetail',
366
+ {
367
+ f_userinfo_code: record.u_f_userinfo_code,
368
+ f_userinfo_id: record.u_f_userinfo_id
369
+ },
370
+ 'af-revenue'
371
+ ).then(res => {
372
+ this.record = res
373
+ this.detailVisible = true
374
+ })
375
+ },
376
+ onClose() {
377
+ this.detailVisible = false
378
+ // 关闭详情之后重新查询表单
379
+ this.$refs.xFormTable.refreshTable(true)
380
+ },
381
+ selAddress(record) {
382
+ // 先填充基本地址信息
383
+ const basicForm = {
384
+ f_address: record.tua_f_address,
385
+ f_address_id: record.tua_id
386
+ }
387
+ this.$refs.xFormGroupDemo.getNativeFormRef('t_userinfo')[0].setForm(basicForm)
388
+ if (!this.config.autoEdit) {
389
+ this.selectAddressVisible = false
390
+ return
391
+ }
392
+ console.log('hy 租户,执行自动填充功能')
393
+ // 通过后端逻辑重新查询t_area表获取完整信息
394
+ runLogic(
395
+ 'getAddressDetailById',
396
+ {
397
+ id: record.tua_f_residential_area_id
398
+ },
399
+ 'af-revenue'
400
+ )
401
+ .then(res => {
402
+ // 后端返回的是数组,取第一个元素
403
+ const areaData = Array.isArray(res) ? res[0] : res
404
+ if (!areaData) {
405
+ return
406
+ }
407
+ // 给用户信息表单赋值
408
+ const userInfoForm = {}
409
+ if (areaData.f_customer_type) {
410
+ userInfoForm.f_customer_type = areaData.f_customer_type
411
+ }
412
+ if (areaData.f_route_name) {
413
+ userInfoForm.f_route_name = areaData.f_route_name
414
+ }
415
+ if (areaData.f_accounting_area) {
416
+ userInfoForm.f_accounting_area = areaData.f_accounting_area
417
+ }
418
+ if (Object.keys(userInfoForm).length > 0) {
419
+ this.$refs.xFormGroupDemo.getNativeFormRef('t_userinfo')[0].setForm(userInfoForm)
420
+ }
421
+ // 给表具信息表单赋值
422
+ // 1. 先获取当前所有表单数据
423
+ const allFormData = {
424
+ t_userinfo: this.$refs.xFormGroupDemo.getNativeForm('t_userinfo') || {},
425
+ t_userfiles: this.$refs.xFormGroupDemo.getNativeForm('t_userfiles') || {},
426
+ t_userfiles_Other: this.$refs.xFormGroupDemo.getNativeForm('t_userfiles_Other') || {}
427
+ }
428
+ // 2. 合并 t_area 数据
429
+ if (areaData.f_area_code) {
430
+ allFormData.t_userfiles.f_area_code = areaData.f_area_code
431
+ }
432
+ if (areaData.f_meter_brand) {
433
+ allFormData.t_userfiles.f_gasbrand_id = Number(areaData.f_meter_brand)
434
+ }
435
+ if (areaData.f_meter_style) {
436
+ allFormData.t_userfiles.f_gasmodel_id = areaData.f_meter_style
437
+ }
438
+ if (areaData.f_price_name) {
439
+ allFormData.t_userfiles.f_price_id = Number(areaData.f_price_name)
440
+ }
441
+ console.log('准备重新打开表单弹窗,数据:', allFormData)
442
+ // 3. 关闭表单弹窗
443
+ this.formModalVisible = false
444
+ // 4. 延迟后重新打开(让组件完全销毁后重新渲染)
445
+ this.$nextTick(() => {
446
+ setTimeout(() => {
447
+ this.formModalVisible = true
448
+ // 5. 重新初始化表单组
449
+ this.$nextTick(() => {
450
+ getConfigByNameAsync('addUserGeneralInfoFrom', 'af-revenue').then(configRes => {
451
+ this.$refs.xFormGroupDemo.init({
452
+ ...configRes,
453
+ serviceName: 'af-revenue',
454
+ showLeftTab: true,
455
+ businessType: '新增',
456
+ modifyModelData: allFormData // 带上合并后的完整数据
457
+ })
458
+ })
459
+ })
460
+ }, 300)
461
+ })
462
+ // 给表具其他信息表单赋值
463
+ const userFilesOtherForm = {}
464
+ if (areaData.f_inputtor) {
465
+ userFilesOtherForm.f_inputtor = areaData.f_inputtor
466
+ }
467
+ if (areaData.f_position) {
468
+ userFilesOtherForm.f_position = areaData.f_position
469
+ }
470
+ if (areaData.f_meter_book_num) {
471
+ userFilesOtherForm.f_meter_book_num = areaData.f_meter_book_num
472
+ }
473
+ if (areaData.f_changetube_date) {
474
+ userFilesOtherForm.f_changetube_date = areaData.f_changetube_date
475
+ }
476
+ if (Object.keys(userFilesOtherForm).length > 0) {
477
+ this.$refs.xFormGroupDemo.getNativeFormRef('t_userfiles_Other')[0].setForm(userFilesOtherForm)
478
+ }
479
+ })
480
+ .catch(err => {
481
+ console.warn('查询t_area表详情失败:', err)
482
+ })
483
+
484
+ this.selectAddressVisible = false
62
485
  }
486
+ },
487
+ computed: {
488
+ inputWidth() {
489
+ if (this.formItems.length === 1) {
490
+ return '85%'
491
+ }
492
+ return this.formItems.length ? `${65 / this.formItems.length}%` : '85%'
493
+ },
494
+ ...mapState('account', { currUser: 'user' }),
495
+ ...mapState('setting', { isMobile: 'isMobile' })
63
496
  }
64
497
  }
65
498
  </script>
66
499
 
67
- <template>
68
- <a-card>
69
- <a-button @click="submitForm">提交测试</a-button>
70
- <a-divider orientation="left">总表单数据</a-divider>
71
- <pre class="all-form-data-preview">{{ allFormDataJson }}</pre>
72
- <XFormGroup ref="xFormGroupDemo" @x-form-group-data-change="xFormGroupDataChange" @meter-base-change="meterBaseChange"></XFormGroup>
73
- </a-card>
74
- </template>
75
-
76
- <style scoped lang="less">
77
- .all-form-data-preview {
78
- max-height: 320px;
79
- overflow: auto;
80
- padding: 12px;
81
- margin-bottom: 16px;
82
- font-size: 12px;
83
- line-height: 1.5;
84
- background: #fafafa;
85
- border: 1px solid #f0f0f0;
86
- border-radius: 4px;
87
- }
88
- </style>
500
+ <style scoped></style>
@@ -60,7 +60,7 @@ routerResource.example = {
60
60
  // component: () => import('@vue2-client/base-client/components/common/XDescriptions/demo.vue')
61
61
  // component: () => import('@vue2-client/base-client/components/his/HChart/demo.vue'),
62
62
  // component: () => import('@vue2-client/pages/WorkflowDetail/WorkFlowDemo.vue'),
63
- component: () => import('@vue2-client/base-client/components/common/XFormTable/demo.vue')
63
+ // component: () => import('@vue2-client/base-client/components/common/XFormTable/demo.vue')
64
64
  // component: () => import('@vue2-client/base-client/components/common/AfMap/demo.vue')
65
65
  // component: () => import('@vue2-client/base-client/components/common/ImagePreviewModal/demo.vue'),
66
66
  // component: () => import('@vue2-client/base-client/components/common/XImagePreview/demo.vue'),
@@ -70,7 +70,7 @@ routerResource.example = {
70
70
  // component: () => import('@vue2-client/base-client/components/common/XDescriptions/demo.vue'),
71
71
  // component: () => import('@vue2-client/base-client/components/common/XAddNativeForm/demo.vue')
72
72
  // component: () => import('@vue2-client/base-client/components/common/XInspectionDetailDrawer/demo.vue')
73
- // component: () => import('@vue2-client/base-client/components/common/XFormGroup/demo.vue')
73
+ component: () => import('@vue2-client/base-client/components/common/XFormGroup/demo.vue')
74
74
  // component: () => import('@vue2-client/base-client/components/common/XReport/XReportDemo.vue'),
75
75
  // component: () => import('@vue2-client/base-client/components/common/XReportGrid/XReportDemo.vue'),
76
76
  // component: () => import('@vue2-client/base-client/components/common/HIS/demo.vue'),
package/src/utils/reg.js CHANGED
@@ -0,0 +1,166 @@
1
+ /** 手机号 */
2
+ export const REG_PHONE =
3
+ /^[1](([3][0-9])|([4][01456789])|([5][012356789])|([6][2567])|([7][0-8])|([8][0-9])|([9][012356789]))[0-9]{8}$/
4
+
5
+ /** 邮箱 */
6
+ export const REG_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
7
+
8
+ /** url */
9
+ export const REG_URL =
10
+ /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/
11
+
12
+ /** 身份证号校验 */
13
+ export function checkIdNumber (value) {
14
+ if (isMaskedIdNumber(value)) return true
15
+ const psidno = String(value)
16
+ // 1.校验身份证号格式和长度
17
+ const regPsidno = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[X])$)$/
18
+ if (!regPsidno.test(psidno)) {
19
+ return false
20
+ }
21
+ // 2.校验前两位的省份编码是否正确
22
+ const province = { 11: '北京', 12: '天津', 13: '河北', 14: '山西', 15: '内蒙古', 21: '辽宁', 22: '吉林', 23: '黑龙江 ', 31: '上海', 32: '江苏', 33: '浙江', 34: '安徽', 35: '福建', 36: '江西', 37: '山东', 41: '河南', 42: '湖北 ', 43: '湖南', 44: '广东', 45: '广西', 46: '海南', 50: '重庆', 51: '四川', 52: '贵州', 53: '云南', 54: '西藏 ', 61: '陕西', 62: '甘肃', 63: '青海', 64: '宁夏', 65: '新疆', 71: '台湾', 81: '香港', 82: '澳门', 91: '国外' }
23
+ if (!province[Number(psidno.slice(0, 2))]) {
24
+ return false
25
+ }
26
+ // 3.校验出生日期
27
+ if (psidno.length === 15) {
28
+ // 15位号码 省(2位)市(2位)县(2位)年(2位)月(2位)日(2位)校验码(3位)
29
+ const reg = /^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/
30
+ const arrSplit = psidno.match(reg)
31
+ // 15位号码在年份前补 19 或 20
32
+ const year = Number(arrSplit[2].charAt(0)) > 0 ? '19' + arrSplit[2] : '20' + arrSplit[2]
33
+ const month = arrSplit[3]
34
+ const day = arrSplit[4]
35
+ if (!validateBirthday(year, month, day)) {
36
+ return false
37
+ }
38
+ } else if (psidno.length === 18) {
39
+ // 18位号码 省(2位)市(2位)县(2位)年(4位)月(2位)日(2位)校验码(4位)
40
+ const reg = /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/
41
+ const arrSplit = psidno.match(reg)
42
+ const year = arrSplit[2]
43
+ const month = arrSplit[3]
44
+ const day = arrSplit[4]
45
+ if (!validateBirthday(year, month, day)) {
46
+ return false
47
+ }
48
+ } else {
49
+ return false
50
+ }
51
+ // 校验出生日期是否合理
52
+ function validateBirthday (year, month, day) {
53
+ year = Number(year) // 年
54
+ month = Number(month) // 月
55
+ day = Number(day) // 日
56
+ const nowTime = new Date().getTime() // 当前时间戳
57
+ const birthTime = new Date(`${year}-${month}-${day}`).getTime() // 获取出生日期的时间戳
58
+ // 不能是明天出生的吧
59
+ if (birthTime > nowTime) {
60
+ return false
61
+ }
62
+ // 一般人活不到150岁吧
63
+ const nowYear = new Date().getFullYear()
64
+ if ((nowYear - year) > 150) {
65
+ return false
66
+ }
67
+ // 不能是13月出生的吧
68
+ if (month < 1 || month > 12) {
69
+ return false
70
+ }
71
+ // 不能是2月30号、4月31号、5月32号出生的吧
72
+ const date = new Date(year, month, 0) // 获取当月的最后一天
73
+ if (day < 1 || day > date.getDate()) {
74
+ return false
75
+ }
76
+ return true
77
+ }
78
+ // 4.18位号码校验生成的校验码
79
+ if (psidno.length === 18) {
80
+ const Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] // 加权因子
81
+ const parity = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] // 校验码
82
+ let sum = 0
83
+ for (let i = 0; i < 17; i++) {
84
+ sum += Number(psidno.charAt(i)) * Wi[i]
85
+ }
86
+ if (parity[sum % 11] !== psidno[17]) {
87
+ return false
88
+ }
89
+ }
90
+ return true
91
+ }
92
+ /** 座机号 */
93
+ export const REG_LANDLINE = /\d{3}-\d{8}|\d{4}-\d{7}/
94
+
95
+ /** 营业执照 */
96
+ export const REG_BUSINESS_LICENSE = /^[0-9a-zA-Z]{15}$/
97
+
98
+ /** 手机号 8~11 位脱敏:前 3 + **** + 后 4,如 138****1234 */
99
+ const REG_PHONE_MASKED_MOBILE = /^\d{3}\*{4}\d{4}$/
100
+
101
+ /** 4~7 位号码脱敏:前 2 + (1~4 个 *) + 后 1 */
102
+ const REG_PHONE_MASKED_SHORT = /^\d{2}\*{1,4}\d{1}$/
103
+
104
+ /** 超过 11 位号码脱敏:前 3 + (>=5 个 *) + 后 4 */
105
+ const REG_PHONE_MASKED_LONG = /^\d{3}\*{5,}\d{4}$/
106
+
107
+ /** 带分隔符的座机/手机号脱敏,如 010-1234****5678、0371-123****4567 */
108
+ const REG_PHONE_MASKED_FORMATTED = /^[\d\s\-()]*\*{2,}[\d\s\-()]*$/
109
+
110
+ /** 18 位身份证脱敏:前 6 + ******** + 后 4 */
111
+ const REG_ID_NUMBER_MASKED_18 = /^\d{6}\*{8}[\dX]{4}$/i
112
+
113
+ /** 15 位身份证脱敏:前 6 + ****** + 后 3 */
114
+ const REG_ID_NUMBER_MASKED_15 = /^\d{6}\*{6}\d{3}$/
115
+
116
+ /** 其它长度身份证脱敏:前 6 + (1~8 个 *) + 后 1~4 位 */
117
+ const REG_ID_NUMBER_MASKED_DEFAULT = /^\d{6}\*{1,8}[\dX]{1,4}$/i
118
+
119
+ /**
120
+ * 判断是否为后端脱敏后的手机号/座机号(脱敏数据跳过格式校验)
121
+ * 规则对齐后端 maskPhone:按纯数字长度分档保留前后位数,中间替换为 *
122
+ */
123
+ export function isMaskedPhone (phone) {
124
+ if (phone == null || phone === '') return false
125
+ const value = String(phone).trim()
126
+ if (!value.includes('*')) return false
127
+
128
+ if (
129
+ REG_PHONE_MASKED_MOBILE.test(value) ||
130
+ REG_PHONE_MASKED_SHORT.test(value) ||
131
+ REG_PHONE_MASKED_LONG.test(value)
132
+ ) {
133
+ return true
134
+ }
135
+
136
+ if (!REG_PHONE_MASKED_FORMATTED.test(value)) return false
137
+
138
+ const digitsOnly = value.replace(/\D/g, '')
139
+ const digitLen = digitsOnly.length
140
+ const starCount = (value.match(/\*/g) || []).length
141
+
142
+ // 8~11 位:保留前 3 后 4,中间 4 个 *
143
+ if (digitLen === 7 && starCount >= 4) return true
144
+ // 4~7 位:保留前 2 后 1
145
+ if (digitLen === 3 && starCount >= 1 && starCount <= 4) return true
146
+ // 超过 11 位:保留前 3 后 4,中间 length-7 个 *
147
+ if (digitLen === 7 && starCount >= 5) return true
148
+
149
+ return starCount >= 2 && digitLen >= 3
150
+ }
151
+
152
+ /**
153
+ * 判断是否为后端脱敏后的身份证号(脱敏数据跳过格式校验)
154
+ * 规则对齐后端 maskIdNumber
155
+ */
156
+ export function isMaskedIdNumber (value) {
157
+ if (value == null || value === '') return false
158
+ const idNumber = String(value).trim().toUpperCase()
159
+ if (!idNumber.includes('*')) return false
160
+
161
+ if (idNumber.length === 18 && REG_ID_NUMBER_MASKED_18.test(idNumber)) return true
162
+ if (idNumber.length === 15 && REG_ID_NUMBER_MASKED_15.test(idNumber)) return true
163
+ if (idNumber.length >= 10 && REG_ID_NUMBER_MASKED_DEFAULT.test(idNumber)) return true
164
+
165
+ return false
166
+ }