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 +1 -1
- package/src/components/data/OtherCharge/OtherChargeForm.vue +28 -4
- package/src/components/data/OtherCharge/OtherChargeGroupModal.vue +542 -0
- package/src/components/data/XOlMap/types.ts +1 -1
- package/src/views/component/OtherCharge/index.vue +9 -6
- package/src/views/component/XCellListView/index.vue +78 -1
- package/src/views/component/XFormView/index.vue +1 -0
- package/src/views/component/XOlMapView/XLocationPicker/index.vue +118 -118
package/package.json
CHANGED
|
@@ -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>
|
|
@@ -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: '
|
|
15
|
-
f_userinfo_code: '
|
|
16
|
-
f_user_name: '
|
|
17
|
-
f_userfiles_id: '
|
|
18
|
-
f_orgid: '
|
|
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: '
|
|
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-
|
|
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>
|
|
@@ -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>
|