af-mobile-client-vue3 1.4.25 → 1.4.27

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,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.4.25",
4
+ "version": "1.4.27",
5
5
  "packageManager": "pnpm@10.13.1",
6
6
  "description": "Vue + Vite component lib",
7
7
  "engines": {
@@ -2,6 +2,7 @@
2
2
  import type { FileItem } from '../../common/otherCharge/FileUploader.vue'
3
3
  import CardContainer from '@af-mobile-client-vue3/components/data/CardContainer/CardContainer.vue'
4
4
  import CardHeader from '@af-mobile-client-vue3/components/data/CardContainer/CardHeader.vue'
5
+ import OtherChargeGroupModal from '@af-mobile-client-vue3/components/data/OtherCharge/OtherChargeGroupModal.vue'
5
6
  import { getConfigByNameAsync, runLogic } from '@af-mobile-client-vue3/services/api/common'
6
7
  import useUserStore from '@af-mobile-client-vue3/stores/modules/user'
7
8
  import {
@@ -109,6 +110,8 @@ const props = defineProps<{
109
110
  user?: BusinessUser
110
111
  isWorkOrder?: boolean
111
112
  workOrderData?: any
113
+ serviceName?: string
114
+ showGroup?: boolean
112
115
  }>()
113
116
 
114
117
  const emit = defineEmits<{
@@ -127,13 +130,14 @@ const remarks = ref('')
127
130
  const fileList = ref<FileItem[]>([])
128
131
  const showAddItemModal = ref(false)
129
132
  const showQrCodePayment = ref(false)
133
+ // 材料组相关状态
134
+ const showAddGroupModal = ref(false)
130
135
  // 子组件的响应组件引用
131
136
  const printRef = ref()
132
137
  // 收费类型数据
133
138
  const chargeTypeConfig = reactive<ChargeTypeConfig>({
134
139
  value: [],
135
140
  })
136
-
137
141
  // 配置数据
138
142
  const config = reactive<Partial<OtherChargeConfig>>({
139
143
  payment: '现金缴费',
@@ -150,6 +154,10 @@ const useGridUploader = computed(() => {
150
154
  return config.fileTypes && config.fileTypes.length > 0
151
155
  })
152
156
 
157
+ // 是否显示添加材料组按钮
158
+ const showAddGroupButton = computed(() => {
159
+ return props.showGroup ?? false
160
+ })
153
161
  // 初始化获取配置
154
162
  async function initConfig() {
155
163
  try {
@@ -196,9 +204,8 @@ async function initConfig() {
196
204
  chargeTypeConfig.value = chargeTypes
197
205
  console.log('新的收费类型数据', chargeTypes)
198
206
  })
199
-
200
207
  // 获取其他收费类型配置
201
- const chargeConfig = await getConfigByNameAsync('mobile_otherChargeConfig')
208
+ const chargeConfig = await getConfigByNameAsync('mobile_otherChargeConfig', props.serviceName || import.meta.env.VITE_APP_SYSTEM_NAME)
202
209
  if (chargeConfig) {
203
210
  // 更新配置
204
211
  Object.assign(config, chargeConfig)
@@ -428,10 +435,21 @@ function onFileRemoved(): void {
428
435
  <CardHeader title="费用项目">
429
436
  <template #extra>
430
437
  <VanButton
438
+ v-if="showAddGroupButton"
431
439
  type="primary"
432
440
  size="small"
433
441
  icon="plus"
434
442
  plain
443
+ @click="showAddGroupModal = true"
444
+ >
445
+ 选择材料组
446
+ </VanButton>
447
+ <VanButton
448
+ type="primary"
449
+ size="small"
450
+ icon="plus"
451
+ plain
452
+ style="margin-left: 8px;"
435
453
  @click="showAddItemModal = true"
436
454
  >
437
455
  添加费用项
@@ -576,7 +594,13 @@ function onFileRemoved(): void {
576
594
  :charge-types="chargeTypeConfig"
577
595
  @add="addChargeItem"
578
596
  />
579
-
597
+ <!-- 添加材料组 -->
598
+ <OtherChargeGroupModal
599
+ v-model:show="showAddGroupModal"
600
+ :work-order-data="props.workOrderData || []"
601
+ :service-name="props.serviceName"
602
+ @add="addChargeItem"
603
+ />
580
604
  <!-- 收据弹窗 -->
581
605
  <ReceiptModal ref="printRef" @close="emit('closeOperation')" />
582
606
  <!-- 二维码支付弹窗 -->
@@ -0,0 +1,542 @@
1
+ <script setup lang="ts">
2
+ // 组件依赖:API 调用工具与 Vant 组件
3
+ import { runLogic } from '@af-mobile-client-vue3/services/api/common'
4
+ import {
5
+ showFailToast,
6
+ showToast,
7
+ Button as VanButton,
8
+ Field as VanField,
9
+ Icon as VanIcon,
10
+ Loading as VanLoading,
11
+ Picker as VanPicker,
12
+ Popup as VanPopup,
13
+ } from 'vant'
14
+ import { computed, reactive, ref, watch } from 'vue'
15
+
16
+ // 工单信息接口定义
17
+ interface WorkOrderOption {
18
+ text: string
19
+ value?: string
20
+ workflowId?: string
21
+ }
22
+
23
+ // 材料组接口定义
24
+ interface MaterialGroupItem {
25
+ value: string
26
+ label: string
27
+ }
28
+
29
+ // 表单数据接口定义
30
+ interface FormData {
31
+ workOrderId: string
32
+ workOrderCode: string
33
+ groupId: string
34
+ groupName: string
35
+ }
36
+
37
+ // 组件属性定义:控制弹窗显示、工单数据与服务名
38
+ const props = defineProps<{
39
+ show: boolean
40
+ workOrderData: WorkOrderOption[]
41
+ serviceName?: string
42
+ }>()
43
+
44
+ // 组件事件定义:同步 show 状态与新增收费项
45
+ const emit = defineEmits<{
46
+ (e: 'update:show', value: boolean): void
47
+ (e: 'add', item: {
48
+ id: number
49
+ type: string
50
+ item: string
51
+ model: string
52
+ unitPrice: number
53
+ quantity: number
54
+ total: string
55
+ workOrderCode: string
56
+ workOrderId: string
57
+ }): void
58
+ }>()
59
+
60
+ // 计算属性:双向绑定弹窗显隐
61
+ const showModal = computed({
62
+ get: () => props.show,
63
+ set: value => emit('update:show', value),
64
+ })
65
+
66
+ // 计算属性:确定服务名称(优先使用外部传入)
67
+ const serviceAppName = computed(() => props.serviceName || import.meta.env.VITE_APP_SYSTEM_NAME)
68
+
69
+ // 全局变量:用于记录当前选中的工单详细信息
70
+ const selectedWorkOrder = ref<WorkOrderOption | null>(null)
71
+
72
+ // 表单状态:记录选择的工单与材料组
73
+ const formData = reactive<FormData>({
74
+ workOrderId: '',
75
+ workOrderCode: '',
76
+ groupId: '',
77
+ groupName: '',
78
+ })
79
+
80
+ // 控制选择器显示状态
81
+ const showWorkOrderSelector = ref(false)
82
+ const showGroupSelector = ref(false)
83
+
84
+ // 加载状态与提示文案
85
+ const loading = ref(false)
86
+ const materialGroups = ref<MaterialGroupItem[]>([])
87
+ const materials = ref<any[]>([])
88
+ const groupMessage = ref('')
89
+ const materialMessage = ref('')
90
+ const initializing = ref(false)
91
+
92
+ // 工单下拉选项(仅保留合法 workflowId/value)
93
+ const workOrderOptions = computed(() => {
94
+ return (props.workOrderData || []).map(order => ({
95
+ text: order.text || order.workflowId || order.value || '未命名工单',
96
+ value: order.workflowId || order.value || '',
97
+ })).filter(option => option.value)
98
+ })
99
+
100
+ // 材料组选项
101
+ const groupOptions = computed(() => materialGroups.value.map(group => ({
102
+ text: group.label,
103
+ value: group.value,
104
+ })))
105
+
106
+ // 顶部提示信息:优先展示材料组提示,其次材料提示
107
+ const headerMessage = computed(() => {
108
+ if (groupMessage.value)
109
+ return groupMessage.value
110
+ if (materialMessage.value)
111
+ return materialMessage.value
112
+ return ''
113
+ })
114
+
115
+ // 提交按钮可用状态:需选择材料组并成功获取材料
116
+ const canSubmit = computed(() => Boolean(formData.groupId && materials.value.length > 0 && !loading.value))
117
+
118
+ // 关闭弹窗并重置数据
119
+ function closeModal() {
120
+ showModal.value = false
121
+ resetForm()
122
+ }
123
+
124
+ // 重置所有状态数据
125
+ function resetForm() {
126
+ formData.workOrderId = ''
127
+ formData.workOrderCode = ''
128
+ formData.groupId = ''
129
+ formData.groupName = ''
130
+ materialGroups.value = []
131
+ materials.value = []
132
+ groupMessage.value = ''
133
+ materialMessage.value = ''
134
+ showWorkOrderSelector.value = false
135
+ showGroupSelector.value = false
136
+ selectedWorkOrder.value = null
137
+ }
138
+
139
+ // 根据 workflowId 定位工单
140
+ function getSelectedWorkOrder(workflowId: string) {
141
+ return (props.workOrderData || []).find(order => (order.workflowId || order.value) === workflowId)
142
+ }
143
+
144
+ // 选择工单后更新表单并查询材料组
145
+ function onWorkOrderSelected({ selectedValues }: { selectedValues: string[] }) {
146
+ const workflowId = selectedValues[0]
147
+ const selected = getSelectedWorkOrder(workflowId) || null
148
+ selectedWorkOrder.value = selected
149
+ formData.workOrderId = workflowId
150
+ formData.workOrderCode = selected?.text || '未命名工单'
151
+ showWorkOrderSelector.value = false
152
+ fetchMaterialGroups(workflowId, true)
153
+ }
154
+
155
+ // 选择材料组后更新表单并查询材料
156
+ function onGroupSelected({ selectedValues }: { selectedValues: string[] }) {
157
+ const selectedGroupId = selectedValues[0]
158
+ const selectedGroup = materialGroups.value.find(group => group.value === selectedGroupId)
159
+ if (selectedGroup) {
160
+ formData.groupId = selectedGroup.value
161
+ formData.groupName = selectedGroup.label
162
+ }
163
+ showGroupSelector.value = false
164
+ materialMessage.value = ''
165
+ materials.value = []
166
+ if (formData.groupId) {
167
+ fetchMaterialsByGroup(formData.groupId)
168
+ }
169
+ }
170
+
171
+ // 根据工单查询材料组,可选择自动选中第一个材料组
172
+ async function fetchMaterialGroups(workflowId: string, autoSelectFirstGroup = false) {
173
+ if (!workflowId) {
174
+ groupMessage.value = '请选择工单后再获取材料组'
175
+ return
176
+ }
177
+ loading.value = true
178
+ groupMessage.value = ''
179
+ materialMessage.value = ''
180
+ materialGroups.value = []
181
+ materials.value = []
182
+ formData.groupId = ''
183
+ formData.groupName = ''
184
+
185
+ try {
186
+ const res = await runLogic('getMaterialGroup', {
187
+ workflowId,
188
+ }, serviceAppName.value)
189
+ const groups = Array.isArray(res)
190
+ ? res.map((item: any) => ({
191
+ value: item.value || item.id || '',
192
+ label: item.name || item.label || '未命名材料组',
193
+ })).filter((group: MaterialGroupItem) => group.value)
194
+ : []
195
+
196
+ materialGroups.value = groups
197
+ if (!groups.length) {
198
+ groupMessage.value = '当前工单暂无可用材料组'
199
+ }
200
+ else if (autoSelectFirstGroup) {
201
+ const [firstGroup] = groups
202
+ formData.groupId = firstGroup.value
203
+ formData.groupName = firstGroup.label
204
+ await fetchMaterialsByGroup(firstGroup.value)
205
+ }
206
+ }
207
+ catch (error) {
208
+ console.error('获取材料组失败:', error)
209
+ showFailToast('获取材料组失败')
210
+ groupMessage.value = '获取材料组失败,请稍后重试'
211
+ }
212
+ finally {
213
+ loading.value = false
214
+ }
215
+ }
216
+
217
+ // 根据材料组查询材料清单
218
+ async function fetchMaterialsByGroup(groupId: string) {
219
+ if (!groupId)
220
+ return
221
+ loading.value = true
222
+ materialMessage.value = ''
223
+ materials.value = []
224
+ try {
225
+ const res = await runLogic('getMaterialByGroup', {
226
+ id: groupId,
227
+ }, serviceAppName.value)
228
+
229
+ if (Array.isArray(res) && res.length > 0) {
230
+ materials.value = res
231
+ }
232
+ else {
233
+ materialMessage.value = '该材料组暂无材料'
234
+ }
235
+ }
236
+ catch (error) {
237
+ console.error('获取材料列表失败:', error)
238
+ showFailToast('获取材料列表失败')
239
+ materialMessage.value = '获取材料失败,请稍后再试'
240
+ }
241
+ finally {
242
+ loading.value = false
243
+ }
244
+ }
245
+
246
+ // 点击添加按钮时校验并返回材料数据
247
+ async function handleSubmit() {
248
+ if (!formData.workOrderId) {
249
+ showToast('请选择工单')
250
+ return
251
+ }
252
+ if (!formData.groupId) {
253
+ showToast('请选择材料组')
254
+ return
255
+ }
256
+ if (!materials.value.length) {
257
+ showToast('该材料组暂无材料,无法添加')
258
+ return
259
+ }
260
+
261
+ try {
262
+ materials.value.forEach((material, index) => {
263
+ const unitPrice = Number.parseFloat(material.price ?? '0') || 0
264
+ const quantity = Number.parseFloat(material.count ?? '1') || 1
265
+ const total = (unitPrice * quantity).toFixed(2)
266
+
267
+ emit('add', {
268
+ id: Date.now() + index,
269
+ item: material.name || '未知材料',
270
+ type: material.type || '未分类',
271
+ model: material.model || '型号未知',
272
+ unitPrice,
273
+ quantity,
274
+ total,
275
+ workOrderId: formData.workOrderId,
276
+ workOrderCode: formData.workOrderCode,
277
+ })
278
+ })
279
+ showToast(`成功添加${materials.value.length}项材料`)
280
+ closeModal()
281
+ }
282
+ catch (error) {
283
+ console.error('提交材料失败:', error)
284
+ showFailToast('添加材料失败')
285
+ }
286
+ }
287
+
288
+ // 初始化默认选择:自动选择首个工单与材料组
289
+ async function initDefaultSelections() {
290
+ if (formData.workOrderId || initializing.value)
291
+ return
292
+ if (!workOrderOptions.value.length)
293
+ return
294
+ initializing.value = true
295
+ try {
296
+ const firstOrderOption = workOrderOptions.value[0]
297
+ const firstOrder = getSelectedWorkOrder(firstOrderOption.value) || null
298
+ selectedWorkOrder.value = firstOrder
299
+ formData.workOrderId = firstOrderOption.value
300
+ formData.workOrderCode = firstOrderOption.text
301
+ await fetchMaterialGroups(firstOrderOption.value, true)
302
+ }
303
+ finally {
304
+ initializing.value = false
305
+ }
306
+ }
307
+
308
+ // 监听弹窗显示状态,打开时尝试进行默认选择
309
+ watch(() => props.show, (visible) => {
310
+ if (visible) {
311
+ initDefaultSelections()
312
+ }
313
+ else {
314
+ resetForm()
315
+ }
316
+ })
317
+
318
+ // 监听工单数据变化,必要时重新初始化
319
+ watch(() => props.workOrderData, () => {
320
+ if (showModal.value && !formData.workOrderId) {
321
+ initDefaultSelections()
322
+ }
323
+ }, { deep: true })
324
+ </script>
325
+
326
+ <template>
327
+ <!-- 材料组选择弹窗容器 -->
328
+ <VanPopup
329
+ v-model:show="showModal"
330
+ round
331
+ position="center"
332
+ :style="{ width: '90%', maxWidth: '420px' }"
333
+ close-icon-position="top-right"
334
+ class="other-charge-group-modal"
335
+ >
336
+ <!-- 主内容区域 -->
337
+ <div class="other-charge-group-modal__container">
338
+ <!-- 弹窗加载遮罩 -->
339
+ <div v-if="loading" class="other-charge-group-modal__loading-mask">
340
+ <VanLoading size="24px">
341
+ 加载中...
342
+ </VanLoading>
343
+ </div>
344
+ <!-- 弹窗标题区域 -->
345
+ <div class="other-charge-group-modal__header">
346
+ <h3 class="other-charge-group-modal__title">
347
+ 选择材料组
348
+ </h3>
349
+ <VanIcon name="cross" @click="closeModal" />
350
+ </div>
351
+ <!-- 顶部提示信息 -->
352
+ <p v-if="headerMessage" class="other-charge-group-modal__tip">
353
+ {{ headerMessage }}
354
+ </p>
355
+
356
+ <!-- 选择表单 -->
357
+ <form class="other-charge-group-modal__form" @submit.prevent="handleSubmit">
358
+ <!-- 工单选择 -->
359
+ <div class="other-charge-group-modal__field">
360
+ <label class="other-charge-group-modal__label">工单号</label>
361
+ <VanField
362
+ v-model="formData.workOrderCode"
363
+ placeholder="请选择工单"
364
+ readonly
365
+ right-icon="arrow-down"
366
+ :disabled="!workOrderOptions.length"
367
+ @click="workOrderOptions.length ? showWorkOrderSelector = true : showToast('暂无工单可选')"
368
+ />
369
+ </div>
370
+
371
+ <!-- 材料组选择 -->
372
+ <div class="other-charge-group-modal__field">
373
+ <label class="other-charge-group-modal__label">材料组名称</label>
374
+ <VanField
375
+ v-model="formData.groupName"
376
+ placeholder="请先选择工单"
377
+ readonly
378
+ right-icon="arrow-down"
379
+ :disabled="!formData.workOrderId || !materialGroups.length"
380
+ @click="formData.workOrderId && materialGroups.length ? showGroupSelector = true : showToast(formData.workOrderId ? '该工单暂无材料组' : '请先选择工单')"
381
+ />
382
+ </div>
383
+
384
+ <!-- 材料数量提示 -->
385
+ <p v-if="materials.length" class="other-charge-group-modal__material-count">
386
+ 已获取 {{ materials.length }} 条材料
387
+ </p>
388
+
389
+ <!-- 操作按钮 -->
390
+ <div class="other-charge-group-modal__buttons">
391
+ <VanButton
392
+ plain
393
+ type="default"
394
+ size="normal"
395
+ class="other-charge-group-modal__cancel-btn"
396
+ @click="closeModal"
397
+ >
398
+ 取消
399
+ </VanButton>
400
+ <VanButton
401
+ type="primary"
402
+ size="normal"
403
+ native-type="submit"
404
+ class="other-charge-group-modal__confirm-btn"
405
+ :loading="loading"
406
+ :disabled="!canSubmit"
407
+ >
408
+ 添加
409
+ </VanButton>
410
+ </div>
411
+ </form>
412
+ </div>
413
+
414
+ <!-- 工单选择器弹窗 -->
415
+ <VanPopup
416
+ v-model:show="showWorkOrderSelector"
417
+ position="bottom"
418
+ teleport="#other-charge-form"
419
+ round
420
+ destroy-on-close
421
+ >
422
+ <VanPicker
423
+ :columns="workOrderOptions"
424
+ show-toolbar
425
+ title="选择工单"
426
+ @confirm="onWorkOrderSelected"
427
+ @cancel="showWorkOrderSelector = false"
428
+ />
429
+ </VanPopup>
430
+
431
+ <!-- 材料组选择器弹窗 -->
432
+ <VanPopup
433
+ v-model:show="showGroupSelector"
434
+ position="bottom"
435
+ teleport="#other-charge-form"
436
+ round
437
+ destroy-on-close
438
+ >
439
+ <VanPicker
440
+ :columns="groupOptions"
441
+ show-toolbar
442
+ title="选择材料组"
443
+ @confirm="onGroupSelected"
444
+ @cancel="showGroupSelector = false"
445
+ />
446
+ </VanPopup>
447
+ </VanPopup>
448
+ </template>
449
+
450
+ <style scoped lang="less">
451
+ /* 组件样式:整体结构 */
452
+ .other-charge-group-modal {
453
+ /* 容器样式,含内边距与定位 */
454
+ &__container {
455
+ padding: 16px;
456
+ position: relative;
457
+ }
458
+
459
+ /* 头部区域布局 */
460
+ &__header {
461
+ display: flex;
462
+ justify-content: space-between;
463
+ align-items: center;
464
+ margin-bottom: 16px;
465
+ }
466
+
467
+ /* 标题样式 */
468
+ &__title {
469
+ font-size: 18px;
470
+ font-weight: 500;
471
+ color: #1f2937;
472
+ margin: 0;
473
+ }
474
+
475
+ /* 表单输入域样式 */
476
+ &__form {
477
+ .van-field {
478
+ background-color: #f9fafb;
479
+ border-radius: 6px;
480
+ }
481
+ }
482
+
483
+ /* 单个字段间距 */
484
+ &__field {
485
+ margin-bottom: 16px;
486
+ }
487
+
488
+ /* 字段标题样式 */
489
+ &__label {
490
+ display: block;
491
+ font-size: 14px;
492
+ font-weight: 500;
493
+ color: #374151;
494
+ margin-bottom: 4px;
495
+ }
496
+
497
+ /* 操作按钮区域 */
498
+ &__buttons {
499
+ display: flex;
500
+ justify-content: flex-end;
501
+ margin-top: 24px;
502
+ gap: 12px;
503
+ }
504
+
505
+ /* 取消按钮样式 */
506
+ &__cancel-btn {
507
+ border-color: #d1d5db;
508
+ color: #374151;
509
+ }
510
+
511
+ /* 确认按钮样式 */
512
+ &__confirm-btn {
513
+ background-color: #2563eb;
514
+ }
515
+
516
+ /* 加载遮罩样式 */
517
+ &__loading-mask {
518
+ position: absolute;
519
+ inset: 0;
520
+ background-color: rgba(255, 255, 255, 0.85);
521
+ display: flex;
522
+ align-items: center;
523
+ justify-content: center;
524
+ z-index: 2;
525
+ border-radius: 12px;
526
+ }
527
+
528
+ /* 顶部提示文字 */
529
+ &__tip {
530
+ margin: 8px 0 0 0;
531
+ font-size: 13px;
532
+ color: #ef4444;
533
+ }
534
+
535
+ /* 材料数量提示 */
536
+ &__material-count {
537
+ font-size: 13px;
538
+ color: #10b981;
539
+ margin: 0 0 12px 0;
540
+ }
541
+ }
542
+ </style>
@@ -188,4 +188,4 @@ export interface PolygonLayerConfig {
188
188
  onClick?: (polygon: PolygonData, event: any) => void
189
189
  /** 多边形数据提供者 */
190
190
  dataProvider?: () => PolygonData[] | Promise<PolygonData[]>
191
- }
191
+ }
@@ -8,21 +8,22 @@ const router = useRouter()
8
8
  const loading = ref(false)
9
9
 
10
10
  const workOrderData = ref([])
11
+ const serviceName = ref('af-telephone')
11
12
 
12
13
  const userinfo = {
13
14
  f_workflow_id: '1',
14
- f_userinfo_id: '1',
15
- f_userinfo_code: '1',
16
- f_user_name: '1',
17
- f_userfiles_id: '1',
18
- f_orgid: '1',
15
+ f_userinfo_id: '88035',
16
+ f_userinfo_code: '11058442',
17
+ f_user_name: '苟水平',
18
+ f_userfiles_id: '91063',
19
+ f_orgid: '37710',
19
20
  }
20
21
  function backList() {
21
22
  router.back()
22
23
  }
23
24
  onMounted(() => {
24
25
  console.log('userinfo', userinfo)
25
- workOrderData.value = [{ text: '1', value: '1' }, { text: '2', value: '2' }]
26
+ workOrderData.value = [{ text: '2025111300305', value: '308', workflowId: '4653' }, { text: '2025111300288', value: '291', workflowId: '4636' }]
26
27
  loading.value = true
27
28
  })
28
29
  </script>
@@ -32,6 +33,8 @@ onMounted(() => {
32
33
  v-if="loading"
33
34
  :user="userinfo"
34
35
  :is-work-order="true"
36
+ :show-group="true"
37
+ :service-name="serviceName"
35
38
  :work-order-data="workOrderData"
36
39
  @close-operation="backList"
37
40
  />
@@ -13,7 +13,83 @@ const router = useRouter()
13
13
 
14
14
  // 简易crud表单测试
15
15
  const configName = ref('ceshiCRUD')
16
- const serviceName = ref('af-linepatrol')
16
+ const serviceName = ref('af-safecheck')
17
+
18
+ // 资源权限测试
19
+ // const configName = ref('crud_sources_test')
20
+ // const serviceName = ref('af-system')
21
+
22
+ // 实际业务测试
23
+ // const configName = ref('lngChargeAuditMobileCRUD')
24
+ // const serviceName = ref('af-gaslink')
25
+
26
+ // 跳转到详情页面
27
+ // function toDetail(item) {
28
+ // router.push({
29
+ // name: 'XCellDetailView',
30
+ // params: { id: item[idKey.value] }, // 如果使用命名路由,推荐使用路由参数而不是直接构建 URL
31
+ // query: {
32
+ // operName: item[operNameKey.value],
33
+ // method:item[methodKey.value],
34
+ // requestMethod:item[requestMethodKey.value],
35
+ // operatorType:item[operatorTypeKey.value],
36
+ // operUrl:item[operUrlKey.value],
37
+ // operIp:item[operIpKey.value],
38
+ // costTime:item[costTimeKey.value],
39
+ // operTime:item[operTimeKey.value],
40
+ //
41
+ // title: item[titleKey.value],
42
+ // businessType: item[businessTypeKey.value],
43
+ // status:item[statusKey.value]
44
+ // }
45
+ // })
46
+ // }
47
+
48
+ // 跳转到表单——以表单组来渲染纯表单
49
+ // function toDetail(item) {
50
+ // router.push({
51
+ // name: 'XFormGroupView',
52
+ // query: {
53
+ // id: item[idKey.value],
54
+ // // id: item.rr_id,
55
+ // // o_id: item.o_id,
56
+ // },
57
+ // })
58
+ // }
59
+
60
+ // 新增功能
61
+ // function addOption(totalCount) {
62
+ // router.push({
63
+ // name: 'XFormView',
64
+ // params: { id: totalCount, openid: totalCount },
65
+ // query: {
66
+ // configName: configName.value,
67
+ // serviceName: serviceName.value,
68
+ // mode: '新增',
69
+ // },
70
+ // })
71
+ // }
72
+
73
+ // 修改功能
74
+ // function updateRow(result) {
75
+ // router.push({
76
+ // name: 'XFormView',
77
+ // params: { id: result.o_id, openid: result.o_id },
78
+ // query: {
79
+ // configName: configName.value,
80
+ // serviceName: serviceName.value,
81
+ // mode: '修改',
82
+ // },
83
+ // })
84
+ // }
85
+
86
+ // 删除功能
87
+ // function deleteRow(result) {
88
+ // emit('deleteRow', result.o_id)
89
+ // }
90
+ // const fixQueryForm = ref({
91
+ // f_operator_id: '487184754014158848',
92
+ // })
17
93
  </script>
18
94
 
19
95
  <template>
@@ -21,6 +97,7 @@ const serviceName = ref('af-linepatrol')
21
97
  <template #layout_content>
22
98
  <XCellList
23
99
  :config-name="configName"
100
+ :service-name="serviceName"
24
101
  />
25
102
  </template>
26
103
  </NormalDataLayout>
@@ -28,6 +28,7 @@ function onSubmit(data: any) {
28
28
  ref="formGroupAddConstruction"
29
29
  mode="修改"
30
30
  :config-name="configName"
31
+ :service-name="serviceName"
31
32
  :form-data="formData"
32
33
  @on-submit="onSubmit"
33
34
  />
@@ -1,118 +1,118 @@
1
- <script setup lang="ts">
2
- import type { LocationResult } from '@af-mobile-client-vue3/components/data/XOlMap/types'
3
- import LocationPicker from '@af-mobile-client-vue3/components/data/XOlMap/XLocationPicker/index.vue'
4
- import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
5
- import { showNotify } from 'vant'
6
- import { ref } from 'vue'
7
-
8
- const selectedLocation = ref<LocationResult>()
9
-
10
- // 处理位置选择
11
- function handleLocationConfirm(location: LocationResult) {
12
- // console.log('选择的位置:', location)
13
- // selectedLocation.value = location
14
- showNotify({ type: 'success', message: '位置已选择' })
15
- }
16
- </script>
17
-
18
- <template>
19
- <NormalDataLayout id="XLocationPicker" title="XOlMap地址选择器">
20
- <template #layout_content>
21
- <div class="location-picker-demo">
22
- <!-- 页面标题 -->
23
- <div class="page-header">
24
- <div class="title">
25
- 位置选择
26
- </div>
27
- </div>
28
-
29
- <!-- 选择结果展示 -->
30
- <div v-if="selectedLocation" class="location-result">
31
- <div class="label">
32
- 已选位置:
33
- </div>
34
- <div class="value">
35
- {{ selectedLocation.address }}
36
- </div>
37
- <div class="coordinates">
38
- 经度: {{ selectedLocation.longitude.toFixed(6) }},
39
- 纬度: {{ selectedLocation.latitude.toFixed(6) }}
40
- </div>
41
- </div>
42
-
43
- <!-- 地图组件 -->
44
- <div class="map-container">
45
- <LocationPicker
46
- v-model="selectedLocation"
47
- :default-center="[108.948024, 34.263161]"
48
- :default-zoom="12"
49
- @confirm="handleLocationConfirm"
50
- />
51
- </div>
52
- </div>
53
- </template>
54
- </NormalDataLayout>
55
- </template>
56
-
57
- <style scoped lang="less">
58
- .location-picker-demo {
59
- width: 100%;
60
- height: 100%;
61
- position: relative;
62
- display: flex;
63
- flex-direction: column;
64
- background-color: #f7f8fa;
65
- }
66
-
67
- .page-header {
68
- height: 44px;
69
- display: flex;
70
- align-items: center;
71
- justify-content: center;
72
- background: white;
73
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
74
- position: relative;
75
- z-index: 1;
76
-
77
- .title {
78
- font-size: 16px;
79
- color: #333;
80
- font-weight: 500;
81
- }
82
- }
83
-
84
- .location-result {
85
- background: white;
86
- padding: 12px 16px;
87
- margin: 10px;
88
- border-radius: 8px;
89
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
90
-
91
- .label {
92
- font-size: 14px;
93
- color: #666;
94
- margin-bottom: 4px;
95
- }
96
-
97
- .value {
98
- font-size: 16px;
99
- color: #333;
100
- margin-bottom: 8px;
101
- word-break: break-all;
102
- }
103
-
104
- .coordinates {
105
- font-size: 12px;
106
- color: #999;
107
- }
108
- }
109
-
110
- .map-container {
111
- flex: 1;
112
- position: relative;
113
- margin: 0 10px 10px 10px;
114
- border-radius: 8px;
115
- overflow: hidden;
116
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
117
- }
118
- </style>
1
+ <script setup lang="ts">
2
+ import type { LocationResult } from '@af-mobile-client-vue3/components/data/XOlMap/types'
3
+ import LocationPicker from '@af-mobile-client-vue3/components/data/XOlMap/XLocationPicker/index.vue'
4
+ import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
5
+ import { showNotify } from 'vant'
6
+ import { ref } from 'vue'
7
+
8
+ const selectedLocation = ref<LocationResult>()
9
+
10
+ // 处理位置选择
11
+ function handleLocationConfirm(location: LocationResult) {
12
+ // console.log('选择的位置:', location)
13
+ // selectedLocation.value = location
14
+ showNotify({ type: 'success', message: '位置已选择' })
15
+ }
16
+ </script>
17
+
18
+ <template>
19
+ <NormalDataLayout id="XLocationPicker" title="XOlMap地址选择器">
20
+ <template #layout_content>
21
+ <div class="location-picker-demo">
22
+ <!-- 页面标题 -->
23
+ <div class="page-header">
24
+ <div class="title">
25
+ 位置选择
26
+ </div>
27
+ </div>
28
+
29
+ <!-- 选择结果展示 -->
30
+ <div v-if="selectedLocation" class="location-result">
31
+ <div class="label">
32
+ 已选位置:
33
+ </div>
34
+ <div class="value">
35
+ {{ selectedLocation.address }}
36
+ </div>
37
+ <div class="coordinates">
38
+ 经度: {{ selectedLocation.longitude.toFixed(6) }},
39
+ 纬度: {{ selectedLocation.latitude.toFixed(6) }}
40
+ </div>
41
+ </div>
42
+
43
+ <!-- 地图组件 -->
44
+ <div class="map-container">
45
+ <LocationPicker
46
+ v-model="selectedLocation"
47
+ :default-center="[108.948024, 34.263161]"
48
+ :default-zoom="12"
49
+ @confirm="handleLocationConfirm"
50
+ />
51
+ </div>
52
+ </div>
53
+ </template>
54
+ </NormalDataLayout>
55
+ </template>
56
+
57
+ <style scoped lang="less">
58
+ .location-picker-demo {
59
+ width: 100%;
60
+ height: 100%;
61
+ position: relative;
62
+ display: flex;
63
+ flex-direction: column;
64
+ background-color: #f7f8fa;
65
+ }
66
+
67
+ .page-header {
68
+ height: 44px;
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: center;
72
+ background: white;
73
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
74
+ position: relative;
75
+ z-index: 1;
76
+
77
+ .title {
78
+ font-size: 16px;
79
+ color: #333;
80
+ font-weight: 500;
81
+ }
82
+ }
83
+
84
+ .location-result {
85
+ background: white;
86
+ padding: 12px 16px;
87
+ margin: 10px;
88
+ border-radius: 8px;
89
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
90
+
91
+ .label {
92
+ font-size: 14px;
93
+ color: #666;
94
+ margin-bottom: 4px;
95
+ }
96
+
97
+ .value {
98
+ font-size: 16px;
99
+ color: #333;
100
+ margin-bottom: 8px;
101
+ word-break: break-all;
102
+ }
103
+
104
+ .coordinates {
105
+ font-size: 12px;
106
+ color: #999;
107
+ }
108
+ }
109
+
110
+ .map-container {
111
+ flex: 1;
112
+ position: relative;
113
+ margin: 0 10px 10px 10px;
114
+ border-radius: 8px;
115
+ overflow: hidden;
116
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
117
+ }
118
+ </style>