af-mobile-client-vue3 1.4.66 → 1.4.67
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 +1 -1
- package/src/components/core/ImageUploader/index.vue +7 -0
- package/src/components/data/OtherCharge/OtherChargeGroupModal.vue +542 -542
- package/src/components/data/XOlMap/types.ts +1 -1
- package/src/views/component/FilePreviewView/index.vue +31 -31
- package/src/views/component/XCellListView/index.vue +2 -78
- package/src/views/component/XFormView/index.vue +13 -28
- package/src/views/component/XOlMapView/XLocationPicker/index.vue +118 -118
|
@@ -1,542 +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>
|
|
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>
|