af-mobile-client-vue3 1.1.8 → 1.1.10

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 (80) hide show
  1. package/.env +6 -6
  2. package/.env.development +4 -4
  3. package/.env.envoiceShow +6 -6
  4. package/.env.production +6 -6
  5. package/.husky/commit-msg +1 -1
  6. package/.husky/pre-commit +1 -1
  7. package/.vscode/settings.json +61 -61
  8. package/mock/modules/user.mock.ts +152 -152
  9. package/package.json +1 -1
  10. package/public/favicon.svg +4 -4
  11. package/public/safari-pinned-tab.svg +32 -32
  12. package/scripts/verifyCommit.js +19 -19
  13. package/src/App.vue +43 -43
  14. package/src/api/user/index.ts +40 -40
  15. package/src/bootstrap.ts +18 -18
  16. package/src/components/core/NavBar/index.vue +12 -12
  17. package/src/components/core/Tabbar/index.vue +38 -38
  18. package/src/components/core/XGridDropOption/index.vue +151 -151
  19. package/src/components/core/XMultiSelect/index.vue +183 -183
  20. package/src/components/data/XCellDetail/index.vue +106 -106
  21. package/src/components/data/XFormItem/index.vue +105 -107
  22. package/src/components/data/XOlMap/XLocationPicker/index.vue +7 -9
  23. package/src/components/data/XOlMap/index.vue +103 -96
  24. package/src/components/data/XReportForm/XReportFormJsonRender.vue +220 -220
  25. package/src/components/data/XReportForm/index.vue +1079 -1079
  26. package/src/components/data/XReportGrid/XAddReport/index.ts +1 -1
  27. package/src/components/data/XReportGrid/XReportDrawer/index.ts +1 -1
  28. package/src/components/data/XSignature/index.vue +285 -285
  29. package/src/components/data/XTag/index.vue +10 -10
  30. package/src/components/layout/NormalDataLayout/index.vue +70 -70
  31. package/src/components/layout/TabBarLayout/index.vue +40 -40
  32. package/src/components.d.ts +53 -53
  33. package/src/env.d.ts +16 -16
  34. package/src/font-style/font.css +3 -3
  35. package/src/hooks/useCommon.ts +9 -9
  36. package/src/layout/PageLayout.vue +4 -5
  37. package/src/layout/SingleLayout.vue +4 -5
  38. package/src/locales/en-US.json +25 -25
  39. package/src/locales/zh-CN.json +25 -25
  40. package/src/plugins/AppData.ts +38 -38
  41. package/src/router/guards.ts +59 -59
  42. package/src/router/index.ts +61 -61
  43. package/src/router/invoiceRoutes.ts +33 -33
  44. package/src/services/api/common.ts +109 -109
  45. package/src/services/api/manage.ts +8 -8
  46. package/src/services/api/search.ts +16 -16
  47. package/src/services/restTools.ts +56 -56
  48. package/src/services/v3Api.ts +11 -11
  49. package/src/stores/modules/routeCache.ts +22 -0
  50. package/src/stores/modules/setting.ts +52 -52
  51. package/src/stores/mutation-type.ts +7 -7
  52. package/src/utils/authority-utils.ts +84 -84
  53. package/src/utils/crypto.ts +39 -39
  54. package/src/utils/i18n.ts +41 -41
  55. package/src/utils/indexedDB.ts +180 -180
  56. package/src/utils/mobileUtil.ts +26 -26
  57. package/src/utils/routerUtil.ts +271 -271
  58. package/src/utils/runEvalFunction.ts +13 -13
  59. package/src/utils/wechatUtil.ts +9 -9
  60. package/src/views/common/LoadError.vue +64 -64
  61. package/src/views/common/NotFound.vue +68 -68
  62. package/src/views/component/EvaluateRecordView/index.vue +40 -40
  63. package/src/views/component/XCellDetailView/index.vue +217 -217
  64. package/src/views/component/XCellListView/index.vue +2 -2
  65. package/src/views/component/XOlMapView/XLocationPicker/index.vue +0 -2
  66. package/src/views/component/XOlMapView/index.vue +3 -5
  67. package/src/views/component/XReportFormIframeView/index.vue +47 -47
  68. package/src/views/component/XReportFormView/index.vue +13 -13
  69. package/src/views/component/XSignatureView/index.vue +50 -50
  70. package/src/views/component/menu.vue +117 -117
  71. package/src/views/component/notice.vue +46 -46
  72. package/src/views/component/topNav.vue +36 -36
  73. package/src/views/invoiceShow/index.vue +61 -61
  74. package/src/views/user/login/ForgetPasswordForm.vue +94 -94
  75. package/src/views/user/login/LoginTitle.vue +68 -68
  76. package/src/views/user/login/index.vue +22 -22
  77. package/src/views/user/my/index.vue +230 -230
  78. package/src/vue-router.d.ts +9 -9
  79. package/tsconfig.json +43 -43
  80. package/src/stores/modules/cachedView.ts +0 -31
@@ -1,7 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { FieldType } from 'vant'
3
3
  import type { Numeric } from 'vant/es/utils'
4
- import type { LocationResult } from '../XOlMap/types'
5
4
  import Uploader from '@af-mobile-client-vue3/components/core/Uploader/index.vue'
6
5
  import XGridDropOption from '@af-mobile-client-vue3/components/core/XGridDropOption/index.vue'
7
6
  import XMultiSelect from '@af-mobile-client-vue3/components/core/XMultiSelect/index.vue'
@@ -146,87 +145,91 @@ const showFormItemFunc = debounce(async () => {
146
145
  }
147
146
  }, 500)
148
147
 
149
- const localValue = computed({
150
- get() {
151
- switch (attr.type) {
152
- case 'uploader':
153
- if (mode === '查询') {
154
- return props.modelValue !== undefined ? props.modelValue : querySelectDefaultValue.value
155
- }
156
- else {
157
- return props.modelValue !== undefined ? props.modelValue : formSelectDefaultValue.value
158
- }
159
- case 'switch':
160
- return props.modelValue !== undefined ? props.modelValue : false
161
- case 'checkbox':
162
- case 'file':
163
- case 'image':
164
- case 'timePicker':
165
- case 'datePicker':
166
- if (mode === '查询') {
167
- // console.log(querySelectDefaultValue.value)
168
- return props.modelValue !== undefined ? props.modelValue : querySelectDefaultValue.value
169
- }
170
- else {
171
- // console.log(formSelectDefaultValue.value)
172
- return props.modelValue !== undefined ? props.modelValue : formSelectDefaultValue.value
173
- }
174
- // case 'datePicker':
175
- // if (mode === '查询') {
176
- // // console.log(querySelectDefaultValue.value)
177
- // return props.modelValue !== undefined ? props.modelValue : querySelectDefaultValue.value
178
- // }
179
- // else {
180
- // if (props.modelValue !== undefined) {
181
- // // 拆分日期和时间
182
- // const [dateStr, timeStr] = props.modelValue.split(' ')
183
- // // 拆分日期部分
184
- // const date = dateStr.split('-')
185
- // // 拆分时间部分
186
- // const time = timeStr.split(':')
187
- // // 赋值给 dateTimePickerValue
188
- // // eslint-disable-next-line vue/no-side-effects-in-computed-properties
189
- // dateTimePickerValue.value = {
190
- // date,
191
- // time,
192
- // }
193
- // return dateTimePickerValue.value
194
- // }
195
- // return formSelectDefaultValue.value
196
- // }
197
- case 'radio':
198
- case 'rate':
199
- case 'slider':
200
- case 'area':
201
- case 'citySelect':
202
- case 'calendar':
203
- case 'textarea':
204
- case 'intervalPicker':
205
- case 'input':
206
- case 'select':
207
- if (mode === '查询')
208
- return props.modelValue !== undefined ? props.modelValue : queryInputDefaultValue.value
209
- else
210
- return props.modelValue !== undefined ? props.modelValue : formInputDefaultValue.value
211
- case 'stepper':
212
- return props.modelValue !== undefined ? props.modelValue : 1
213
- case 'rangePicker':
214
- if (props.modelValue && Array.isArray(props.modelValue) && props.modelValue.length > 1)
215
- return `${props.modelValue[0]} ~ ${props.modelValue[1]}`
148
+ // 获取默认值的函数
149
+ function getDefaultValue() {
150
+ switch (attr.type) {
151
+ case 'uploader':
152
+ case 'checkbox':
153
+ case 'file':
154
+ case 'image':
155
+ case 'timePicker':
156
+ case 'datePicker':
157
+ if (mode === '查询')
158
+ return props.modelValue !== undefined ? props.modelValue : querySelectDefaultValue.value
159
+ else
160
+ return props.modelValue !== undefined ? props.modelValue : formSelectDefaultValue.value
161
+ case 'switch':
162
+ return props.modelValue !== undefined ? props.modelValue : false
163
+ case 'radio':
164
+ case 'rate':
165
+ case 'slider':
166
+ case 'area':
167
+ case 'citySelect':
168
+ case 'calendar':
169
+ case 'textarea':
170
+ case 'intervalPicker':
171
+ case 'input':
172
+ case 'select':
173
+ if (mode === '查询')
174
+ return props.modelValue !== undefined ? props.modelValue : queryInputDefaultValue.value
175
+ else
176
+ return props.modelValue !== undefined ? props.modelValue : formInputDefaultValue.value
177
+ case 'stepper':
178
+ return props.modelValue !== undefined ? props.modelValue : 1
179
+ case 'rangePicker':
180
+ if (props.modelValue && Array.isArray(props.modelValue) && props.modelValue.length > 1)
181
+ return `${props.modelValue[0]} ~ ${props.modelValue[1]}`
182
+ else
183
+ return props.modelValue
184
+ case 'addressSearch':
185
+ return props.modelValue
186
+ default:
187
+ return undefined
188
+ }
189
+ }
216
190
 
217
- else
218
- return props.modelValue
191
+ // 改用 ref,并设置初始值
192
+ const localValue = ref(getDefaultValue())
219
193
 
220
- default:
221
- return undefined
222
- }
223
- },
224
- set(newValue) {
225
- emits('update:modelValue', newValue)
226
- dataChangeFunc()
227
- },
194
+ // 监听 props.modelValue 的变化
195
+ watch(() => props.modelValue, (newVal) => {
196
+ // 如果是文件上传类型,需要特殊处理
197
+ if (attr.type === 'image' || attr.type === 'file') {
198
+ localValue.value = Array.isArray(newVal) ? newVal : []
199
+ }
200
+ else {
201
+ localValue.value = newVal !== undefined ? newVal : getDefaultValue()
202
+ }
228
203
  })
229
204
 
205
+ // 监听 localValue 的变化
206
+ watch(localValue, (newVal) => {
207
+ if (attr.type === 'image' || attr.type === 'file') {
208
+ // 确保上传组件的值始终是数组
209
+ const value = Array.isArray(newVal) ? newVal : []
210
+ emits('update:modelValue', value)
211
+ }
212
+ else {
213
+ emits('update:modelValue', newVal)
214
+ }
215
+ dataChangeFunc()
216
+ })
217
+
218
+ function updateFile(files, _index) {
219
+ // 处理文件数据
220
+ // 更新本地值
221
+ localValue.value = files.map((file) => {
222
+ const newFile = { ...file }
223
+ if (newFile.content)
224
+ delete newFile.content
225
+ if (newFile.file)
226
+ delete newFile.file
227
+ if (newFile.objectUrl)
228
+ delete newFile.objectUrl
229
+ return newFile
230
+ })
231
+ }
232
+
230
233
  // 表单校验的类型校验
231
234
  function formTypeCheck(attr, value) {
232
235
  switch (attr.rule.type) {
@@ -553,30 +556,6 @@ function onAreaConfirm({ selectedOptions }) {
553
556
  }])
554
557
  }
555
558
 
556
- function updateFile(files, _index) {
557
- files.forEach((file) => {
558
- if (file.content)
559
- delete file.content
560
- if (file.file)
561
- delete file.file
562
- if (file.objectUrl)
563
- delete file.objectUrl
564
- })
565
- localValue.value = files
566
- emits('update:modelValue', localValue.value)
567
- }
568
- // 监听表单发生变化后触发展示函数
569
- watch(() => form, (_oldVal, _newVal) => {
570
- showFormItemFunc()
571
- // 数据源来自人员联动时更新数据
572
- if (attr?.keyName?.toString()?.startsWith('search@根据表单项[') && attr?.keyName?.toString().endsWith(']联动人员'))
573
- debouncedUserLinkFunc()
574
-
575
- // 数据源来自部门联动时更新数据
576
- if (attr?.keyName?.toString()?.startsWith('search@根据表单项[') && attr?.keyName?.toString().endsWith(']联动部门'))
577
- debouncedDepLinkFunc()
578
- }, { deep: true })
579
-
580
559
  function onDateTimePickerConfirm() {
581
560
  showDatePicker.value = false
582
561
  const dateStr = dateTimePickerValue.value.date.join('-')
@@ -590,9 +569,30 @@ function onPickerCancel() {
590
569
 
591
570
  const showAddressPicker = ref(false)
592
571
  const addressValue = ref('')
572
+
573
+ // XLocationPicker 默认加载的中心点
574
+ const defaultMapCenter = computed(() => {
575
+ const lonLat = form[`${attr.model}_lon_lat`]
576
+ if (lonLat && typeof lonLat === 'string' && lonLat.includes(',')) {
577
+ const [lon, lat] = lonLat.split(',').map(Number)
578
+ if (!Number.isNaN(lon) && !Number.isNaN(lat)) {
579
+ return [lon, lat] as [number, number]
580
+ }
581
+ }
582
+ return undefined
583
+ })
584
+
593
585
  // 处理地址选择器确认
594
586
  function handleAddressConfirm(location) {
595
- addressValue.value = location.address
587
+ // 构造新的数据格式
588
+ const formData = {
589
+ [`${attr.model}_lon_lat`]: `${location.longitude},${location.latitude}`,
590
+ [attr.model]: location.address,
591
+ }
592
+
593
+ // 更新表单数据
594
+ // eslint-disable-next-line vue/custom-event-name-casing
595
+ emits('set-form', formData)
596
596
  showAddressPicker.value = false
597
597
  }
598
598
  </script>
@@ -998,7 +998,7 @@ function handleAddressConfirm(location) {
998
998
  <!-- 地址选择器 -->
999
999
  <VanField
1000
1000
  v-if="attr.type === 'addressSearch' && showItem"
1001
- v-model="addressValue"
1001
+ v-model="localValue as string"
1002
1002
  name="addressSearch"
1003
1003
  :label="labelData"
1004
1004
  :label-align="labelAlign"
@@ -1016,9 +1016,7 @@ function handleAddressConfirm(location) {
1016
1016
  teleport="body"
1017
1017
  >
1018
1018
  <XLocationPicker
1019
- v-model="localValue as LocationResult"
1020
- tian-di-tu-key="c16876b28898637c0a1a68b3fa410504"
1021
- amap-key="5ebabc4536d4b42e0dd1e20175cca8ab"
1019
+ :default-center="defaultMapCenter"
1022
1020
  @confirm="handleAddressConfirm"
1023
1021
  />
1024
1022
  </VanPopup>
@@ -63,17 +63,15 @@ function handleConfirm() {
63
63
  }
64
64
 
65
65
  // 组件挂载时初始化地图
66
- onMounted(() => {
66
+ onMounted(async () => {
67
67
  // 使用 nextTick 确保 DOM 已更新
68
- nextTick(() => {
69
- mapRef.value.init({
70
- center: props.defaultCenter,
71
- zoom: props.defaultZoom,
72
- })
73
-
74
- // 初始化后尝试获取地址信息
75
- handleCenterChange(props.defaultCenter)
68
+ await nextTick()
69
+ await mapRef.value.init({
70
+ center: props.defaultCenter,
71
+ zoom: props.defaultZoom,
76
72
  })
73
+ // 初始化后尝试获取地址信息
74
+ handleCenterChange(props.defaultCenter)
77
75
  })
78
76
 
79
77
  // 监听弹窗状态变化
@@ -308,109 +308,115 @@ async function handleMoveEnd() {
308
308
  * 初始化地图
309
309
  * @param params - 初始化参数
310
310
  */
311
- function init(params: InitParams = {}): void {
312
- if (!mapRef.value) {
313
- return
314
- }
315
-
316
- // 保存初始化参数
317
- mapParams.value = params
318
-
319
- // 设置默认参数
320
- const {
321
- center = [116.404, 39.915],
322
- zoom = 10,
323
- maxZoom = 18,
324
- minZoom = 4,
325
- } = params
311
+ function init(params: InitParams = {}): Promise<void> {
312
+ return new Promise((resolve) => {
313
+ if (!mapRef.value) {
314
+ resolve()
315
+ return
316
+ }
326
317
 
327
- try {
328
- getConfigByName('webConfig', (res) => {
329
- const tianDiTuKey = res.tianDiTuKey || 'c16876b28898637c0a1a68b3fa410504'
330
- const amapKey = res.amapKey || '5ebabc4536d4b42e0dd1e20175cca8ab'
331
-
332
- tiandityKey.value = tianDiTuKey
333
- gaodeKey.value = amapKey
334
- // 初始化所有底图图层
335
- initializeLayers(tianDiTuKey)
336
-
337
- // 创建地图实例 - 加载所有底图图层,但默认只显示高德地图
338
- map = new Map({
339
- target: mapRef.value,
340
- layers: Object.values(baseMaps), // 加载所有底图图层
341
- view: new View({
342
- center: fromLonLat(center),
343
- zoom,
344
- projection: 'EPSG:3857',
345
- maxZoom,
346
- minZoom,
347
- }),
348
- controls: defaultControls({
349
- zoom: false,
350
- rotate: false,
351
- attribution: false,
352
- }).extend([
353
- new ScaleLine({
354
- units: 'metric',
355
- className: 'ol-scale-line',
318
+ // 保存初始化参数
319
+ mapParams.value = params
320
+
321
+ // 设置默认参数
322
+ const {
323
+ center = [116.404, 39.915],
324
+ zoom = 10,
325
+ maxZoom = 18,
326
+ minZoom = 4,
327
+ } = params
328
+
329
+ try {
330
+ getConfigByName('webConfig', (res) => {
331
+ const tianDiTuKey = res.tianDiTuKey || 'c16876b28898637c0a1a68b3fa410504'
332
+ const amapKey = res.amapKey || '5ebabc4536d4b42e0dd1e20175cca8ab'
333
+
334
+ tiandityKey.value = tianDiTuKey
335
+ gaodeKey.value = amapKey
336
+ // 初始化所有底图图层
337
+ initializeLayers(tianDiTuKey)
338
+
339
+ // 创建地图实例 - 加载所有底图图层,但默认只显示高德地图
340
+ map = new Map({
341
+ target: mapRef.value,
342
+ layers: Object.values(baseMaps), // 加载所有底图图层
343
+ view: new View({
344
+ center: fromLonLat(center),
345
+ zoom,
346
+ projection: 'EPSG:3857',
347
+ maxZoom,
348
+ minZoom,
349
+ }),
350
+ controls: defaultControls({
351
+ zoom: false,
352
+ rotate: false,
353
+ attribution: false,
354
+ }).extend([
355
+ new ScaleLine({
356
+ units: 'metric',
357
+ className: 'ol-scale-line',
358
+ }),
359
+ ]),
360
+ interactions: defaultInteractions({
361
+ altShiftDragRotate: false,
362
+ pinchRotate: false,
356
363
  }),
357
- ]),
358
- interactions: defaultInteractions({
359
- altShiftDragRotate: false,
360
- pinchRotate: false,
361
- }),
362
- })
363
-
364
- // 更新地图大小,确保地图正确渲染
365
- setTimeout(() => {
366
- if (map) {
367
- map.updateSize()
368
- // 确保默认图层正确显示
369
- handleMapChange('tianditu')
370
- }
371
- }, 200)
372
-
373
- // 监听地图移动结束事件
374
- map.on('moveend', handleMoveEnd)
375
-
376
- // 设置鼠标样式
377
- if (mapRef.value) {
378
- mapRef.value.style.cursor = 'grab'
379
- // 监听地图事件
380
- const mapElement = mapRef.value
381
-
382
- // 鼠标按下时
383
- mapElement.addEventListener('mousedown', () => {
384
- mapElement.style.cursor = 'grabbing'
385
- // 用户开始拖动地图,取消跟随定位
386
- if (locationTimer) {
387
- isFollowingLocation.value = false
388
- }
389
364
  })
390
365
 
391
- // 触摸开始时
392
- mapElement.addEventListener('touchstart', () => {
393
- // 用户开始拖动地图,取消跟随定位
394
- if (locationTimer) {
395
- isFollowingLocation.value = false
366
+ // 更新地图大小,确保地图正确渲染
367
+ setTimeout(() => {
368
+ if (map) {
369
+ map.updateSize()
370
+ // 确保默认图层正确显示
371
+ handleMapChange('tianditu')
372
+ // 地图初始化完成后解析 Promise
373
+ resolve()
396
374
  }
397
- })
375
+ }, 200)
376
+
377
+ // 监听地图移动结束事件
378
+ map.on('moveend', handleMoveEnd)
379
+
380
+ // 设置鼠标样式
381
+ if (mapRef.value) {
382
+ mapRef.value.style.cursor = 'grab'
383
+ // 监听地图事件
384
+ const mapElement = mapRef.value
385
+
386
+ // 鼠标按下时
387
+ mapElement.addEventListener('mousedown', () => {
388
+ mapElement.style.cursor = 'grabbing'
389
+ // 用户开始拖动地图,取消跟随定位
390
+ if (locationTimer) {
391
+ isFollowingLocation.value = false
392
+ }
393
+ })
398
394
 
399
- // 鼠标释放时
400
- mapElement.addEventListener('mouseup', () => {
401
- mapElement.style.cursor = 'grab'
402
- })
395
+ // 触摸开始时
396
+ mapElement.addEventListener('touchstart', () => {
397
+ // 用户开始拖动地图,取消跟随定位
398
+ if (locationTimer) {
399
+ isFollowingLocation.value = false
400
+ }
401
+ })
403
402
 
404
- // 鼠标离开地图时
405
- mapElement.addEventListener('mouseleave', () => {
406
- mapElement.style.cursor = 'grab'
407
- })
408
- }
409
- })
410
- }
411
- catch (error) {
412
- console.error('地图初始化失败:', error)
413
- }
403
+ // 鼠标释放时
404
+ mapElement.addEventListener('mouseup', () => {
405
+ mapElement.style.cursor = 'grab'
406
+ })
407
+
408
+ // 鼠标离开地图时
409
+ mapElement.addEventListener('mouseleave', () => {
410
+ mapElement.style.cursor = 'grab'
411
+ })
412
+ }
413
+ })
414
+ }
415
+ catch (error) {
416
+ console.error('地图初始化失败:', error)
417
+ resolve()
418
+ }
419
+ })
414
420
  }
415
421
 
416
422
  /**
@@ -905,6 +911,7 @@ defineExpose({
905
911
  // 组件卸载时清理地图实例
906
912
  onUnmounted(() => {
907
913
  if (map) {
914
+ stopNavigation()
908
915
  map.setTarget(undefined)
909
916
  map = null
910
917
  }