Browse Source

安环费用管理移动端

liuzhuo 1 week ago
parent
commit
01c3fc7213

+ 10
- 0
src/router/index.ts View File

@@ -634,6 +634,16 @@ const router = createRouter({
634 634
 			name: '项目案例库编辑',
635 635
 			component: () => import('@/view/knowledge/projectList.vue')
636 636
 		},
637
+		{
638
+			path: '/moneySafe/safeMoneyManagement',
639
+			name: '安环费用管理',
640
+			component: () => import('@/view/moneySafe/safeMoneyManagement.vue')
641
+		},
642
+		{
643
+			path: '/safeMoneyManagementList',
644
+			name: '安环费用管理编辑',
645
+			component: () => import('@/view/moneySafe/safeMoneyManagementList.vue')
646
+		}
637 647
 	]
638 648
 })
639 649
 

+ 9
- 0
src/view/Home2.vue View File

@@ -254,6 +254,15 @@
254 254
         </van-grid-item>
255 255
       </van-grid>
256 256
     </div>
257
+    <div class="card">
258
+      <div class="title">安环费用管理</div>
259
+      <van-grid :border="false" :column-num="4" v-if="showCheckTakeN">
260
+        <van-grid-item to="/moneySafe/safeMoneyManagement">
261
+          <img src="../../public/images/aq.png" width="45rpx" />
262
+          <span class="vanicon_text">安环费用管理</span>
263
+        </van-grid-item>
264
+      </van-grid>
265
+    </div>
257 266
 
258 267
   </div>
259 268
 

+ 698
- 0
src/view/moneySafe/safeMoneyManagement.vue View File

@@ -0,0 +1,698 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, watch, ref, computed } from 'vue';
3
+import { useRouter } from 'vue-router';
4
+const {
5
+  proxy
6
+} = getCurrentInstance()
7
+
8
+/* 通用方法: 重置list数据 */
9
+const basicReset = () => {
10
+  finished.value = false;
11
+  loading.value = true;
12
+  pageNum.value = 1
13
+  resultData.value = []
14
+}
15
+
16
+
17
+const dictList = ref([])
18
+
19
+/* 返回上一级页面 */
20
+const router = useRouter()
21
+
22
+/* 在线预览实现 */
23
+import {Base64} from "js-base64";
24
+const linShiFid=ref({
25
+  fileId:''
26
+})
27
+const handlePreview = (fileId) => {
28
+  if (fetchData.value.ruleName) {
29
+    sessionStorage.setItem("ruleName", fetchData.value.ruleName)
30
+  }
31
+  if (fetchData.value.ruleScope) {
32
+    sessionStorage.setItem("ruleScope", fetchData.value.ruleScope)
33
+  }
34
+  linShiFid.value.fileId= fileId
35
+  getTableDataQueryFile()
36
+}
37
+const bucket = ref(import.meta.env.VITE_BUCKET)
38
+const getTableDataQueryFile = () => {
39
+  var url = 'framework/Common/queryFileWithValues'
40
+  var param = {
41
+    fId: linShiFid.value.fileId,
42
+  }
43
+  proxy.$axios.get(url, param).then(response => {
44
+    if (response.data.code == 0) {
45
+      const downloadPath = import.meta.env.VITE_BASE_API + '/framework/Common/downloadFileS3?bucket='+ bucket.value + '&id='
46
+      const fileListWithUrls = response.data.data.map(file => ({
47
+        ...file,
48
+        url: `${downloadPath}${file.id}`, // 添加完整的下载路径
49
+        thumbUrl: `${downloadPath}${file.id}`, // 如果需要缩略图,可以使用相同的路径
50
+        name: file.fileName, // 确保有文件名属性
51
+        status: file.status, // 确保有状态属性
52
+        id: file.id
53
+      }));
54
+
55
+      var originUrl = import.meta.env.VITE_PREVIEW_BASE_API + 'framework/Common/downloadFileS3?bucket=' + bucket.value +'&id=' + fileListWithUrls[0].id
56
+      var previewUrl = originUrl + '&fullfilename=' + Date.now() + fileListWithUrls[0].name
57
+      var url = import.meta.env.VITE_PREVIEW_API + 'onlinePreview?url=' + encodeURIComponent(Base64.encode(
58
+        previewUrl)) + '&officePreviewType=pdf'
59
+      window.open(url);
60
+    } else {
61
+      showFailToast('失败!' + response.data.msg)
62
+    }
63
+  })
64
+}
65
+
66
+/* 查询数据 */
67
+const pageNum = ref(1)
68
+const pageSize = ref(10)
69
+const total = ref(0)
70
+const totalMoney = ref(0) // 费用总金额
71
+
72
+// 计算平均单笔费用
73
+const averageExpense = computed(() => {
74
+  return total.value > 0 ? (totalMoney.value / total.value).toFixed(2) : '0.00'
75
+})
76
+const resultData = ref([])
77
+// const fetchData = ref({
78
+//   ruleName:'',
79
+//   ruleScope: ''
80
+// })
81
+
82
+const onSearch = () => {
83
+  basicReset()
84
+  onLoad()
85
+}
86
+
87
+const resetCondition = () => {
88
+  basicReset()
89
+  fetchData.value = {
90
+    moneyDept: '',
91
+    moneyType: '',
92
+    moneyTypeId: '',
93
+    useTimeStart: '',
94
+    useTimeEnd: ''
95
+  }
96
+  onLoad()
97
+}
98
+
99
+const queryList = ref([])
100
+
101
+/* 查询请求 */
102
+const queryFetch = async () => {
103
+
104
+  fetchData.value.ruleScope = postBackRegimeScope.value
105
+
106
+  if (sessionStorage.getItem("ruleName")) {
107
+    fetchData.value.ruleName = sessionStorage.getItem("ruleName")
108
+    sessionStorage.removeItem("ruleName")
109
+  }
110
+  if (sessionStorage.getItem("ruleScope")) {
111
+    const deptInfo = sessionStorage.getItem("ruleScope")
112
+    fetchData.value.ruleScope = deptInfo
113
+    postBackRegimeScope.value = deptInfo
114
+    currentDeptName.value = deptInfo.split('-')[1]
115
+    sessionStorage.removeItem("ruleScope")
116
+  }
117
+  // if(currentDeptName.value) {
118
+  //   fetchData.value.moneyDept = currentDeptName.value
119
+  // }
120
+
121
+  // 构建查询参数,确保 moneyType 字段正确传递
122
+  // 如果 moneyType 是 dicCode,需要转换为名称进行查询(因为后端使用 like 查询,数据库中存储的是名称)
123
+  let moneyTypeForQuery = fetchData.value.moneyType || ''
124
+  if (moneyTypeForQuery && moneyTypeMap.value[moneyTypeForQuery]) {
125
+    // 如果是 dicCode,转换为名称进行查询
126
+    moneyTypeForQuery = moneyTypeMap.value[moneyTypeForQuery]
127
+  } else if (moneyTypeForQuery && moneyTypeMap.value[String(moneyTypeForQuery)]) {
128
+    // 兼容字符串类型的 dicCode
129
+    moneyTypeForQuery = moneyTypeMap.value[String(moneyTypeForQuery)]
130
+  }
131
+  
132
+  const queryParams = {
133
+    moneyDept: fetchData.value.moneyDept || '',
134
+    moneyType: moneyTypeForQuery, // 传递名称(因为后端使用 like 查询)
135
+    useTimeStart: fetchData.value.useTimeStart || '',
136
+    useTimeEnd: fetchData.value.useTimeEnd || ''
137
+  }
138
+  
139
+  console.log('查询参数:', queryParams)
140
+
141
+  const url = '/sgsafe/MoneySafe/query'
142
+  const param = {
143
+    page: pageNum.value,
144
+    rows: pageSize.value,
145
+    params: JSON.stringify(queryParams)
146
+  }
147
+  try {
148
+    const res = await proxy.$axios.post(url,param);
149
+    console.log('查询结果:', res.data)
150
+    if (res.data.code === 0) {
151
+      total.value = res.data.data.total
152
+      // 添加 canDelete 属性
153
+      const currentUserId = String(localStorage.getItem('userId') || '');
154
+      queryList.value = res.data.data.records.map(item => ({
155
+        ...item,
156
+        canDelete: String(item.addId || '') === currentUserId
157
+      }))
158
+      // 获取费用总金额
159
+      totalMoney.value = res.data.data.totalMoney || 0
160
+    } else {
161
+      console.log('操作失败!' + res.data.msg)
162
+    }
163
+  } catch (error) {
164
+    console.error('请求出错:', error);
165
+  }
166
+};
167
+/* 列表加载与下拉刷新 */
168
+// const list = ref([]);
169
+const refreshing = ref(false)
170
+const loading = ref(false)
171
+const finished = ref(false)
172
+
173
+const onRefresh = () => {
174
+  basicReset()
175
+  onLoad();
176
+};
177
+
178
+const onLoad = async () => {
179
+  if (refreshing.value) {
180
+    resultData.value = [];
181
+    pageNum.value = 1;
182
+    refreshing.value = false;
183
+  }
184
+  getDicList()
185
+  try {
186
+    await  queryFetch();
187
+    if (pageSize.value * pageNum.value < total.value) {
188
+      resultData.value = [...queryList.value,...resultData.value ]
189
+      pageNum.value++;
190
+    } else {
191
+      resultData.value = [...queryList.value,...resultData.value ]
192
+      finished.value = true;
193
+    }
194
+  } catch (error) {
195
+    console.log(error);
196
+    finished.value = true;
197
+  } finally {
198
+    loading.value = false;
199
+  }
200
+};
201
+
202
+/* 组织树选择 */
203
+const showBottom = ref(false)
204
+const postBackRegimeScope = ref()
205
+const currentDeptName = ref()
206
+import OrganizationalWithLeaf from '@/components/OrganizationalWithLeaf.vue';
207
+import { showFailToast, showDialog, showSuccessToast } from 'vant';
208
+import tools from "@/tools/index.js";
209
+const showPickerHandle = () => {
210
+  showBottom.value = true
211
+}
212
+
213
+const handleTableDataUserDeptUpdate = async (nodeData) => {
214
+  postBackRegimeScope.value = nodeData
215
+  currentDeptName.value = nodeData.split('-')[1]
216
+  // 关键:用户主动选择部门时,设置查询条件
217
+  fetchData.value.moneyDept = nodeData
218
+  basicReset()
219
+  await onLoad()
220
+  showBottom.value = false
221
+}
222
+
223
+const getDeptInfo = (currentDeptInfo) => {
224
+  // 只用于初始化显示当前组织名称,不设置查询条件
225
+  postBackRegimeScope.value = currentDeptInfo
226
+  currentDeptName.value = currentDeptInfo.split('-')[1]
227
+  // 注意:这里不设置 fetchData.value.moneyDept,让查询条件保持为空
228
+  // 这样页面初始化时会显示所有数据
229
+}
230
+
231
+// 添加页面初始化逻辑
232
+onMounted(() => {
233
+  // 页面加载时,先查询所有数据(不设置部门条件)
234
+  getDicList()
235
+  basicReset()
236
+  onLoad()
237
+})
238
+
239
+//日期
240
+const fetchData = ref({
241
+  moneyDept: '', // 所属部门
242
+  moneyType: '', // 费用类型(dicCode,用于查询)
243
+  moneyTypeId: '', // 费用类型ID(兼容字段)
244
+  useTimeStart: '', // 使用日期开始
245
+  useTimeEnd: '' // 使用日期结束
246
+})
247
+
248
+// 添加日期范围处理
249
+const dateRange = ref([])
250
+watch(dateRange, (newVal) => {
251
+  if (newVal && newVal.length === 2) {
252
+    fetchData.value.useTimeStart = newVal[0]
253
+    fetchData.value.useTimeEnd = newVal[1]
254
+  } else {
255
+    fetchData.value.useTimeStart = ''
256
+    fetchData.value.useTimeEnd = ''
257
+  }
258
+})
259
+
260
+const guid = () => {
261
+  const chars = '0123456789abcdefghijklmnopqrstuvwxyz'
262
+  const length = chars.length
263
+  const randomString = (len) => {
264
+    const array = new Uint8Array(len)
265
+    crypto.getRandomValues(array)
266
+    return Array.from(array)
267
+        .map(byte => chars[byte % length])
268
+        .join('');
269
+  }
270
+  return `${randomString(8)}${randomString(8)}${randomString(8)}${randomString(8)}`;
271
+}
272
+const moneySafeForm = ref({
273
+  id: '',
274
+  moneyDept: '', // 所属部门
275
+  moneyNumber: '', // 投入费用
276
+  useTime: '', // 使用日期
277
+  moneyType: '', // 费用类型
278
+  moneyIn: '', // 资金来源
279
+  moneyOut: '', // 资金使用情况说明
280
+  otherDec: '', // 备注
281
+  fileId: guid(), // 附件ID
282
+  moneyTypeId:'' // 费用类型ID
283
+})
284
+
285
+const showStartTimePicker = ref(false);
286
+const showEndTimePicker = ref(false);
287
+
288
+// 临时存储选中的日期(因为 van-date-picker 需要数组格式)
289
+const tempStartTime = ref([2024, 1, 1]);
290
+const tempEndTime = ref([2024, 1, 1]);
291
+
292
+// 格式化日期为 YYYY-MM-DD
293
+const formatDate = (dateArray) => {
294
+  const [year, month, day] = dateArray;
295
+  return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
296
+};
297
+
298
+ const confirmStartTime = async () => {
299
+  fetchData.value.useTimeStart = formatDate(tempStartTime.value);
300
+  showStartTimePicker.value = false;
301
+  if(fetchData.value.useTimeStart) {
302
+   await queryFetch()
303
+    resultData.value = queryList.value
304
+
305
+  }
306
+};
307
+
308
+const confirmEndTime = async () => {
309
+  fetchData.value.useTimeEnd = formatDate(tempEndTime.value);
310
+  showEndTimePicker.value = false;
311
+  if(fetchData.value.useTimeEnd) {
312
+    await queryFetch()
313
+    resultData.value = queryList.value
314
+
315
+  }
316
+  console.log('选中的日期:', fetchData.value.useTimeEnd)
317
+};
318
+
319
+const showPicker = ref(false)
320
+// const columns = ref([{ text: '劳动保护用品', value: '劳动保护用品' },
321
+//   { text: '安全工作激励', value: '安全工作激励' },
322
+//   { text: '安全培训教育', value: '安全培训教育' },
323
+//   { text: '检测与检验', value: '检测与检验' },
324
+//   { text: '职业健康查体', value: '职业健康查体' },
325
+//   { text: '应急与防护设施', value: '应急与防护设施' },
326
+//   { text: '安全改造整改', value: '安全改造整改' },
327
+//   { text: '其他', value: '其他' },
328
+//
329
+// ])
330
+const columns = ref([])
331
+const dicList = ref([])
332
+const moneyTypeMap = ref({}) // 映射表:dicCode -> dicName,用于将数字转换为名称显示
333
+
334
+
335
+const getDicList = () => {
336
+  tools.dic.getDicList(['MONEY_TYPE']).then((response => {
337
+
338
+    dictList.value = response.data.data
339
+    columns.value = dictList.value.MONEY_TYPE.map(item => ({
340
+      text: item.dicName,
341
+      value: item.dicName // Web端保存的是 dicCode
342
+    }))
343
+  })).catch(error => {
344
+    console.error('获取字典数据出错:', error)
345
+    columns.value = []
346
+  })
347
+}
348
+
349
+// 根据 dicCode 获取费用类型名称(用于显示转换)
350
+const getMoneyTypeName = (value) => {
351
+  if (!value) return ''
352
+  
353
+  // 先尝试直接查找(支持 dicCode)
354
+  if (moneyTypeMap.value[value]) {
355
+    return moneyTypeMap.value[value]
356
+  }
357
+  
358
+  // 尝试转换为字符串查找(兼容数字类型的 dicCode)
359
+  const strValue = String(value)
360
+  if (moneyTypeMap.value[strValue]) {
361
+    return moneyTypeMap.value[strValue]
362
+  }
363
+  
364
+  // 如果找不到,可能是 H5 端保存的名称(直接返回)
365
+  return value
366
+}
367
+
368
+const onConfirm = async (value) => {
369
+  // value 是选中的值
370
+  const selectedOption = value.selectedOptions[0]
371
+  // 保存 dicCode 到 moneyType(用于查询)
372
+  fetchData.value.moneyType = selectedOption.value
373
+  // 同时保存到 moneyTypeId(如果后端需要)
374
+  if (!fetchData.value.moneyTypeId) {
375
+    fetchData.value.moneyTypeId = selectedOption.value
376
+  }
377
+  showPicker.value = false // 关闭弹窗
378
+  // 重置分页并查询
379
+  basicReset()
380
+  await queryFetch()
381
+  resultData.value = queryList.value
382
+  console.log('选中的值:', selectedOption)
383
+  console.log('查询条件 moneyType:', fetchData.value.moneyType)
384
+}
385
+
386
+const handAdd =  () => {
387
+  router.push({ path: "/safeMoneyManagementList",
388
+    query: {
389
+      mark:-1,
390
+      deptName: '测试部门名称'
391
+    } });
392
+};
393
+const kz = ref(true);
394
+
395
+const edits = async (row) => {
396
+  const currentUserId = localStorage.getItem('userId');
397
+  const addId = row.addId;
398
+
399
+  const isOwner = String(addId).trim().toLowerCase() === String(currentUserId).trim().toLowerCase();
400
+
401
+  kz.value = true;
402
+  moneySafeForm.value = { ...row };
403
+  router.push({ path: "/safeMoneyManagementList",
404
+    query: {
405
+      mark:1,
406
+      data:JSON.stringify(moneySafeForm.value),
407
+      readOnly: !isOwner ? 'true' : undefined  // 如果不是所有者,设置为只读
408
+    } });
409
+};
410
+
411
+// 删除数据
412
+const deleteData = ref({})
413
+
414
+// 处理删除
415
+const handleDelete = (item) => {
416
+  const currentUserId = localStorage.getItem('userId');
417
+  const addId = item.addId;
418
+
419
+  if (!currentUserId || !addId || String(addId).trim() !== String(currentUserId).trim()) {
420
+    showFailToast('无权限删除!只能删除自己添加的记录。');
421
+    return;
422
+  }
423
+  
424
+  showDialog({
425
+    title: '删除确认',
426
+    message: '确定要删除该费用记录吗?删除后将无法恢复。',
427
+    showCancelButton: true,
428
+    confirmButtonText: '确定删除',
429
+    cancelButtonText: '取消',
430
+  }).then(() => {
431
+    executeDelete(item);
432
+  }).catch(() => {
433
+    console.log('取消删除');
434
+  });
435
+};
436
+
437
+// 执行删除
438
+const executeDelete = (item) => {
439
+  const deleteDataItem = { ...item };
440
+  const now = new Date();
441
+  const year = now.getFullYear();
442
+  const month = String(now.getMonth() + 1).padStart(2, '0');
443
+  const day = String(now.getDate()).padStart(2, '0');
444
+  const hours = String(now.getHours()).padStart(2, '0');
445
+  const minutes = String(now.getMinutes()).padStart(2, '0');
446
+  const seconds = String(now.getSeconds()).padStart(2, '0');
447
+  deleteDataItem.cancelTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
448
+  deleteDataItem.cancelFlag = '1';
449
+  
450
+  const url = '/sgsafe/MoneySafe/save';
451
+  const param = {
452
+    json: JSON.stringify(deleteDataItem)
453
+  };
454
+  
455
+  proxy.$axios.post(url, param).then(response => {
456
+    if (response.data.code == '0' || response.data.code === 0) {
457
+      showSuccessToast("删除成功");
458
+      onRefresh();
459
+    } else {
460
+      showFailToast('删除失败:' + (response.data.msg || '未知错误'));
461
+    }
462
+  }).catch(error => {
463
+    showFailToast('删除失败:网络错误');
464
+    console.error('删除失败:', error);
465
+  });
466
+};
467
+
468
+
469
+</script>
470
+
471
+<template>
472
+  <div class="page-container">
473
+    <van-sticky>
474
+      <van-nav-bar title="安环费用管理"  @click-right="handAdd" >
475
+      <template #right>
476
+        <van-icon name="add" size="25" color="#000" />
477
+      </template>
478
+      </van-nav-bar>
479
+    </van-sticky>
480
+    
481
+    <!-- 统计信息卡片 -->
482
+    <div class="statistics-container">
483
+      <div class="stat-item">
484
+        <div class="stat-label">费用总笔数</div>
485
+        <div class="stat-value">{{ total }}</div>
486
+      </div>
487
+      <div class="stat-item">
488
+        <div class="stat-label">费用总金额(元)</div>
489
+        <div class="stat-value">{{ totalMoney.toLocaleString() }}</div>
490
+      </div>
491
+      <div class="stat-item">
492
+        <div class="stat-label">平均单笔费用(元)</div>
493
+        <div class="stat-value">{{ averageExpense }}</div>
494
+      </div>
495
+    </div>
496
+    
497
+    <!-- 原有的查询表单 -->
498
+    <van-field
499
+        v-model="currentDeptName"
500
+        label="当前组织"
501
+        placeholder="请选择组织架构"
502
+        readonly
503
+        right-icon="arrow-down"
504
+        @click="showPickerHandle()"
505
+    />
506
+
507
+    <van-field
508
+        :model-value="getMoneyTypeName(fetchData.moneyType)"
509
+        is-link
510
+        readonly
511
+        name="picker"
512
+        label="费用类型"
513
+        placeholder="请选择"
514
+        @click="showPicker = true"
515
+    />
516
+    <van-popup v-model:show="showPicker" position="bottom">
517
+      <van-picker
518
+          :columns="columns"
519
+          @confirm="onConfirm"
520
+          @cancel="showPicker = false"
521
+      />
522
+    </van-popup>
523
+
524
+    <van-field
525
+        v-model="fetchData.useTimeStart"
526
+        is-link
527
+        readonly
528
+        name="useTimeStart"
529
+        label="开始时间"
530
+        :colon="true"
531
+        placeholder="点击选择开始时间"
532
+        @click="showStartTimePicker = true"
533
+    />
534
+    <!-- 结束时间 -->
535
+    <van-field
536
+        v-model="fetchData.useTimeEnd"
537
+        is-link
538
+        readonly
539
+        name="useTimeEnd"
540
+        label="结束时间"
541
+        :colon="true"
542
+        placeholder="点击选择结束时间"
543
+        @click="showEndTimePicker = true"
544
+    />
545
+    <!-- 开始时间选择器 -->
546
+    <van-popup v-model:show="showStartTimePicker" position="bottom">
547
+      <van-date-picker
548
+          v-model="tempStartTime"
549
+          type="date"
550
+          @confirm="confirmStartTime"
551
+          @cancel="showStartTimePicker = false"
552
+          :columns-type="['year', 'month', 'day']"
553
+      />
554
+    </van-popup>
555
+
556
+    <!-- 结束时间选择器 -->
557
+    <van-popup v-model:show="showEndTimePicker" position="bottom">
558
+      <van-date-picker
559
+          v-model="tempEndTime"
560
+          type="date"
561
+          @confirm="confirmEndTime"
562
+          @cancel="showEndTimePicker = false"
563
+          :columns-type="['year', 'month', 'day']"
564
+      />
565
+    </van-popup>
566
+
567
+    <div class="scroll-container">
568
+      <van-pull-refresh
569
+        v-model="refreshing"
570
+        success-text="刷新成功"
571
+        @refresh="onRefresh"
572
+      >
573
+        <van-list
574
+          class="listDiv"
575
+          v-model:loading="loading"
576
+          :finished="finished"
577
+          :immediate-check="false"
578
+          finished-text="没有更多了"
579
+          @load="onLoad"
580
+        >
581
+          <div v-for="item in resultData" :key="item.id" class="card">
582
+            <van-swipe-cell>
583
+              <template #default>
584
+                <van-cell @click="edits(item)" :border="false" is-link>
585
+                  <template #title>
586
+                    <span class="bold-title" style="margin-left: 4px;">
587
+                      <div>所属类型:{{ getMoneyTypeName(item.moneyType) }}</div>
588
+                    </span>
589
+                  </template>
590
+                  <template #label>
591
+                    <div class="label-content">
592
+                      <div>费用来源:{{ item.moneyIn }}</div>
593
+                      <div>投入费用:{{ item.moneyNumber }}</div>
594
+                    </div>
595
+                  </template>
596
+                </van-cell>
597
+              </template>
598
+              <template #right>
599
+                <van-button 
600
+                  v-if="item.canDelete" 
601
+                  square 
602
+                  class="delete-button" 
603
+                  text="删除" 
604
+                  @click="handleDelete(item)" 
605
+                />
606
+              </template>
607
+            </van-swipe-cell>
608
+          </div>
609
+        </van-list>
610
+      </van-pull-refresh>
611
+    </div>
612
+
613
+    <van-popup :close-on-click-overlay="false" :lazy-render="false" v-model:show="showBottom" position="bottom">
614
+      <OrganizationalWithLeaf @init="getDeptInfo" @close="showBottom = false" @update:selected-node="handleTableDataUserDeptUpdate" />
615
+    </van-popup>
616
+  </div>
617
+</template>
618
+
619
+<style scoped>
620
+.page-container {
621
+  height: 100vh;
622
+  display: flex;
623
+  flex-direction: column;
624
+
625
+}
626
+
627
+.scroll-container {
628
+  flex: 1;
629
+  overflow: auto;
630
+  -webkit-overflow-scrolling: touch;
631
+}
632
+
633
+.scroll-container::-webkit-scrollbar {
634
+  display: none;
635
+}
636
+
637
+.card {
638
+  margin: 10px;
639
+  border-radius: 8px;
640
+  overflow: hidden;
641
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
642
+  background-color: #fff;
643
+}
644
+
645
+.label-content {
646
+  display: flex;
647
+  flex-direction: column;
648
+  gap: 4px;
649
+}
650
+
651
+.bold-title {
652
+  font-weight: bold;
653
+  color: #333;
654
+}
655
+
656
+.statistics-container {
657
+  display: flex;
658
+  justify-content: space-around;
659
+  align-items: center;
660
+  padding: 16px;
661
+  background-color: #fff;
662
+  margin-bottom: 8px;
663
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
664
+}
665
+
666
+.stat-item {
667
+  flex: 1;
668
+  text-align: center;
669
+  display: flex;
670
+  flex-direction: column;
671
+  align-items: center;
672
+}
673
+
674
+.stat-item:not(:last-child) {
675
+  border-right: 1px solid #ebedf0;
676
+}
677
+
678
+.stat-label {
679
+  font-size: 12px;
680
+  color: #969799;
681
+  margin-bottom: 8px;
682
+}
683
+
684
+.stat-value {
685
+  font-size: 18px;
686
+  font-weight: bold;
687
+  color: #323233;
688
+}
689
+
690
+.delete-button {
691
+  height: 100%;
692
+  border: none;
693
+  color: #fff;
694
+  background-color: #ee0a24;
695
+  font-size: 16px;
696
+  padding: 0 20px;
697
+}
698
+</style>

+ 680
- 0
src/view/moneySafe/safeMoneyManagementList.vue View File

@@ -0,0 +1,680 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, ref , computed, nextTick } from 'vue';
3
+import { useRoute, useRouter } from 'vue-router';
4
+import tools from '@/tools'
5
+import OrganizationalWithLeafUserOne from '@/components/OrganizationalWithLeafUserOne.vue';
6
+const {
7
+  proxy
8
+} = getCurrentInstance()
9
+const accidentDictList = ref([])
10
+const columns =  ref([])
11
+const columnsLevel = ref([])
12
+
13
+
14
+const columnsIn = ref([{text: '公司专项', value: '公司专项'},
15
+    {text: '自筹', value: '自筹'},
16
+    {text: '其他', value: '其他'},])
17
+
18
+// 定义生成编号的函数(你已写好的逻辑)
19
+
20
+const generateCode = () => {
21
+  const now = new Date();
22
+  const year = now.getFullYear();
23
+  const month = String(now.getMonth() + 1).padStart(2, '0');
24
+  const day = String(now.getDate()).padStart(2, '0');
25
+  const formattedDate = `${year}${month}${day}`;
26
+  const hours = String(now.getHours()).padStart(2, '0');
27
+  const minutes = String(now.getMinutes()).padStart(2, '0');
28
+  const seconds = String(now.getSeconds()).padStart(2, '0');
29
+  const formattedTime = `${hours}${minutes}${seconds}`;
30
+  const sequenceNumber = Math.floor(Math.random() * 1000);
31
+  const paddedSequence = String(sequenceNumber).padStart(3, '0');
32
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
33
+};
34
+
35
+// 存储生成的编号(响应式变量)
36
+const generatedCode = ref(generateCode());
37
+
38
+// 重新生成编号的方法
39
+const regenerateCode = () => {
40
+  generatedCode.value = generateCode();
41
+};
42
+
43
+const caseSourceFlag = ref(false)
44
+const moneyTypeFlag = ref(false)
45
+const moneyInFlag = ref(false)
46
+
47
+let title = '新增安全生产费用登记'
48
+
49
+/* 返回上一级页面 */
50
+const router = useRouter()
51
+
52
+
53
+
54
+
55
+const onClickLeft = () => {
56
+  router.go(-1)
57
+}
58
+
59
+const currentYear = ref()
60
+currentYear.value = new Date().getFullYear()
61
+
62
+/* 获取用户部门信息 */
63
+const jsonArray = localStorage.getItem('dept')
64
+const deptInformation = ref([])
65
+try {
66
+  deptInformation.value = jsonArray ? JSON.parse(jsonArray) : [];
67
+} catch (error) {
68
+  deptInformation.value = [];
69
+}
70
+const deptName = deptInformation.value[0].deptName
71
+const deptCode = deptInformation.value[0].deptCode
72
+
73
+const guid = () =>  {
74
+  function S4() {
75
+    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
76
+  }
77
+  return (S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4())
78
+}
79
+const formJieguo = ref({
80
+  resultWhether:'',
81
+  resultDetail:'',
82
+  resultWhy:'',
83
+  resultFile:'',
84
+  itemsId:'',
85
+  resultFileId:'',
86
+  resType:''
87
+})
88
+const route = useRoute()
89
+
90
+const currentDeptName = ref('')
91
+console.log('获取路由传值信息',route)
92
+currentDeptName.value = route.query.deptName
93
+let planInfo = {}
94
+const  userName1=localStorage.getItem('userName');
95
+const isEdit = ref(route.query.mark === '1');
96
+const isReadOnly = ref(route.query.readOnly === 'true');
97
+const isCaseSubmitted = computed(() => isReadOnly.value && isEdit.value);
98
+const result=ref('')
99
+
100
+const moneySafeForm = ref({
101
+  id: '',
102
+  moneyDept: '', // 所属部门
103
+  moneyNumber: '', // 投入费用
104
+  useTime: '', // 使用日期
105
+  moneyType: '', // 费用类型
106
+  moneyIn: '', // 资金来源
107
+  moneyOut: '', // 资金使用情况说明
108
+  otherDec: '', // 备注
109
+  fileId: guid(), // 附件ID
110
+  moneyTypeId:'' // 费用类型ID
111
+})
112
+if (route.query.mark) {
113
+  planInfo = JSON.parse(route.query.mark)
114
+}
115
+
116
+console.log(planInfo);
117
+// 新增模式
118
+if (planInfo==-1){
119
+  const caseNumber = generateCode();
120
+  const fileId = ref()
121
+  result.value= caseNumber
122
+  //初始化 moneySafeForm
123
+  moneySafeForm.value = {
124
+    id: '',
125
+    moneyDept: '', // 所属部门
126
+    moneyNumber: '', // 投入费用
127
+    useTime: '', // 使用日期
128
+    moneyType: '', // 费用类型
129
+    moneyIn: '', // 资金来源
130
+    moneyOut: '', // 资金使用情况说明
131
+    otherDec: '', // 备注
132
+    fileId: guid(), // 附件ID
133
+    moneyTypeId:'' // 费用类型ID
134
+  };
135
+  console.log( result.value);
136
+}
137
+if (planInfo==1) {
138
+  console.log(planInfo);
139
+  title = '查看安环费用管理'
140
+  moneySafeForm.value= JSON.parse(route.query.data)
141
+  if (!moneySafeForm.value.fileId) {
142
+    const newFileId = guid();
143
+    moneySafeForm.value.fileId = newFileId;
144
+    result.value = newFileId;
145
+  } else {
146
+    result.value = moneySafeForm.value.fileId;
147
+  }
148
+
149
+  console.log('编辑模式 - fileId:', result.value);
150
+}
151
+
152
+const moneySafeFormRef = ref()
153
+const moneySafeFormRules = ref({
154
+  moneyDept: [{ required: true, message: '请输入所属部门' }],
155
+  moneyNumber: [{ required: true, message: '请输入投入费用' }],
156
+  useTime: [{ required: true, message: '请选择使用日期' }],
157
+  moneyType: [{ required: true, message: '请选择费用类型' }],
158
+  moneyIn: [{ required: true, message: '请选择资金来源' }],
159
+  moneyOut: [{ required: true, message: '请输入资金使用情况说明' }]
160
+})
161
+
162
+
163
+const resDetail=ref('')
164
+const ruleIds = ref([]);
165
+/*const getRuleId = () => {
166
+  var url = '/sgsafe/ExamHead/getCheckRuleId'
167
+  var param = {}
168
+  proxy.$axios.get(url, param).then(response => {
169
+    if (response.data.code == '0') {
170
+      ruleIds.value = response.data.data
171
+    } else {
172
+      console.log("1111111");
173
+    }
174
+  })
175
+  console.log('ruleIds', ruleIds)
176
+}
177
+getRuleId()*/
178
+
179
+const onConfirmDatetime = () => {
180
+  const year = currentDate.value[0];
181
+  const month = currentDate.value[1].toString().padStart(2, '0');
182
+  const day = currentDate.value[2].toString().padStart(2, '0');
183
+
184
+  moneySafeForm.value.useTime = `${year}-${month}-${day}`;
185
+  showDatetimePicker.value = false;
186
+  dateOrTime.value = false;
187
+};
188
+
189
+
190
+const showDatetimePicker = ref(false);
191
+const currentTime = ref();
192
+const minDate = ref(new Date(1900, 0, 1)); // 初始化最小日期
193
+const maxDate = ref(new Date(2100, 11, 31)); // 初始化最大日期
194
+
195
+const dateOrTime = ref(false);
196
+const onDateConfirm = () => {
197
+  // 日期选择确认后的处理
198
+  moneySafeForm.value.useTime = currentDate.value[0] + '-' + currentDate.value[1] + '-' + currentDate.value[2];
199
+  showDatetimePicker.value = false
200
+};
201
+const resetDatetime = () => {
202
+  dateOrTime.value = false;
203
+
204
+  // 初始化日期和时间
205
+  if (moneySafeForm.value.useTime) {
206
+    // 修复:使用 useTime 而不是 accidentTime
207
+    const dt = new Date(moneySafeForm.value.useTime);
208
+    currentDate.value = [dt.getFullYear(), dt.getMonth() + 1, dt.getDate()];
209
+  } else {
210
+    const now = new Date();
211
+    currentDate.value = [now.getFullYear(), now.getMonth() + 1, now.getDate()];
212
+  }
213
+};
214
+const cancelDatePicker = () => {
215
+  // 先关闭弹窗,避免在关闭过程中触发重置导致错误
216
+  showDatetimePicker.value = false;
217
+  // 使用 nextTick 确保弹窗关闭后再重置,避免状态冲突
218
+  nextTick(() => {
219
+    resetDatetime();
220
+  });
221
+};
222
+
223
+// 时间选择器取消
224
+const cancelTimePicker = () => {
225
+  resetDatetime();
226
+  // 重置为当前时间或从表单获取时间
227
+  if (moneySafeForm.value.useTime) {
228
+    const dt = new Date(moneySafeForm.value.useTime);
229
+  } else {
230
+    const now = new Date();
231
+    currentTime.value = [
232
+      String(now.getHours()).padStart(2, '0'),
233
+      String(now.getMinutes()).padStart(2, '0'),
234
+      String(now.getSeconds()).padStart(2, '0')
235
+    ];
236
+  }
237
+};
238
+
239
+
240
+/* 下拉框 */
241
+const showActionSheet = ref(false)
242
+const showActionSheet1 = ref(false)
243
+const planLevelList = [
244
+  { name: '转发', value: '转发' },
245
+  { name: '内部', value: '内部' },
246
+  { name: '文章', value: '文章' }
247
+];
248
+const isdisabled=ref(true)
249
+const isdisabled2=ref(true)
250
+const onSelect = (item) => {
251
+  moneySafeForm.value.fileContent = item.name
252
+
253
+  showActionSheet.value=false
254
+}
255
+
256
+const onSelect2 = (item) => {
257
+  moneySafeForm.value.fileType=item.name
258
+  showActionSheet2.value=false
259
+  }
260
+
261
+const onCaseSourseSelect = (item) => {
262
+  moneySafeForm.value.caseSource=item.dicCode
263
+  caseSourceFlag.value = false
264
+}
265
+
266
+const onAccidentLevelSelect = (item) => {
267
+  moneySafeForm.value.accidentLevel = item.dicCode
268
+  moneyTypeFlag.value = false
269
+
270
+}
271
+
272
+const displayFileName = ref('')
273
+const onSelect1 = (item) => {
274
+  console.log(item);
275
+  formJieguo.value.resultFile = item.value
276
+  result.value=formJieguo.value.resultFile
277
+  displayFileName.value = item.name
278
+  console.log(result.value);
279
+  showActionSheet1.value = false
280
+}
281
+const questionIds = ref([])
282
+const actions=ref([])
283
+/*const getQuestionId = () => {
284
+  var url = '/sgsafe/AssessmentRecord/queryRuleNoPage';
285
+  var param = {};
286
+  proxy.$axios.get(url, param).then(response => {
287
+    if (response.data.code == '0') {
288
+      questionIds.value = response.data.data; // 先赋值给 questionIds.value
289
+
290
+
291
+      // ✅ 关键:使用 questionIds.value.map
292
+      actions.value = questionIds.value.map(item => ({
293
+        name: item.ruleName,
294
+        value: item.id
295
+      }));
296
+      console.log('actions:', actions.value); // 看看有没有输出
297
+    } else {
298
+      ElMessage.error('操作失败!' + response.data.msg);
299
+    }
300
+  });
301
+};
302
+getQuestionId()*/
303
+
304
+const baocun3 = (ruleFormRef) => {
305
+  console.log(formJieguo.value)
306
+  ruleFormRef.validate((valid, fields) => {
307
+    if (valid) {
308
+
309
+      var url = '/sgsafe/ItemsResult/save';
310
+      var param = {
311
+        json: JSON.stringify(formJieguo.value)
312
+      };
313
+      proxy.$axios.post(url, param).then(response => {
314
+        if (response.data.code == '0') {
315
+          getTableData1()
316
+          ElMessage({
317
+            message: '保存成功',
318
+            type: 'success',
319
+          })
320
+          if (ruleFormRef.value) {
321
+            ruleFormRef.value.resetFields();
322
+          }
323
+          dialogVisibletemplate.value=false
324
+        } else {
325
+          ElMessage.error('操作失败!' + response.data.msg)
326
+        }
327
+
328
+      })
329
+    }
330
+  })
331
+}
332
+
333
+/* 组织树选择 */
334
+const showBottom = ref(false)
335
+import OrganizationalWithLeaf from '@/components/OrganizationalWithLeaf.vue';
336
+import { showFailToast, showLoadingToast, showSuccessToast } from 'vant';
337
+const handleTableDataUserDeptUpdate = async (nodeData) => {
338
+  moneySafeForm.value.moneyDept = nodeData
339
+  showBottom.value = false
340
+}
341
+
342
+const addEmergencyDrillPlan = async () => {
343
+  const loadingToast = showLoadingToast({
344
+    duration: 0,
345
+    message: '加载中',
346
+    forbidClick: true
347
+  })
348
+
349
+  moneySafeForm.value.fileId = result.value
350
+
351
+  var url = '/sgsafe/MoneySafe/save';
352
+  const params = {
353
+    json: JSON.stringify(moneySafeForm.value)
354
+  }
355
+  proxy.$axios.post(url,params).then(res=>{
356
+    if (res.data.code === 0) {
357
+      loadingToast.close()
358
+      showSuccessToast('保存成功')
359
+      onClickLeft()
360
+
361
+    } else {
362
+      loadingToast.close()
363
+      showFailToast('操作失败!' + res.data.msg)
364
+    }
365
+  })
366
+}
367
+const showDatePicker = ref(false)
368
+const onDatePicker = (value) => {
369
+  const dateArr = value.selectedValues
370
+  moneySafeForm.value.checkTime = dateArr[0] + '-' + dateArr[1] + '-' + dateArr[2]
371
+  showDatePicker.value = false
372
+}
373
+const currentDate = ref([2025, 7, 25])
374
+//定义字典集合
375
+const dicList = ref([])
376
+const dictList = ref([])
377
+
378
+const getDicList = () => {
379
+  tools.dic.getDicList(['MONEY_TYPE']).then((response => {
380
+
381
+    dictList.value = response.data.data
382
+    columnsLevel.value = dictList.value.MONEY_TYPE.map(item => ({
383
+      text: item.dicName,
384
+      value: item.dicName // Web端保存的是 dicCode
385
+    }))
386
+  })).catch(error => {
387
+    console.error('获取字典数据出错:', error)
388
+    columns.value = []
389
+  })
390
+}
391
+onMounted(() => {
392
+  //getAccidentDicList()
393
+  console.log('这是编辑页面')
394
+  const today = new Date()
395
+  const year = today.getFullYear()
396
+  const month = today.getMonth() + 1 // 月份从 0 开始
397
+  const day = today.getDate()
398
+  currentDate.value = [year, month, day]
399
+  
400
+  // 确保 minDate 和 maxDate 已初始化
401
+  if (!minDate.value) {
402
+    minDate.value = new Date(1900, 0, 1);
403
+  }
404
+  if (!maxDate.value) {
405
+    maxDate.value = new Date(2100, 11, 31);
406
+  }
407
+  
408
+  // 初始化时间
409
+  currentTime.value = [today.getHours(), today.getMinutes(), today.getSeconds()];
410
+  // 如果是编辑模式且有已有的使用日期,解析并初始化
411
+  if (isEdit.value && moneySafeForm.value.useTime) {
412
+    try {
413
+      // 解析格式如 "2025-01-15" 的日期字符串
414
+      const dateStr = moneySafeForm.value.useTime;
415
+      const [year, month, day] = dateStr.split('-').map(Number);
416
+      if (year && month && day) {
417
+        currentDate.value = [year, month, day];
418
+      }
419
+    } catch (error) {
420
+      console.error('解析使用日期失败:', error);
421
+    }
422
+  }
423
+  getDicList()
424
+})
425
+const showActionSheet2=ref(false)
426
+/* 文件上传 */
427
+import AttachmentS3 from '@/components/AttachmentS3.vue';
428
+
429
+const onSubmit = (values) => {
430
+  addEmergencyDrillPlan()
431
+}
432
+const leaderKeyysr = guid();
433
+const PopupDepartmentLeaderNameRefysr = ref();
434
+const handleDepartmentLeaderNameysr = () => {
435
+  PopupDepartmentLeaderNameRefysr.value.open();
436
+};
437
+const getDepartmentLeaderNameysr = (item) => {
438
+  moneySafeForm.value.punCode = item.user.userCode;
439
+  moneySafeForm.value.punName = item.user.userDesc;
440
+  moneySafeForm.value.punId = item.user.id
441
+};
442
+
443
+const onCaseSourceConfirm = ({ selectedOptions }) => {
444
+  caseSourceFlag.value = false;
445
+  moneySafeForm.value.caseSource = selectedOptions[0].text;
446
+};
447
+
448
+const moneyTypeLevelConfirm = ({ selectedOptions }) => {
449
+  moneyTypeFlag.value = false;
450
+  moneySafeForm.value.moneyTypeId = selectedOptions[0].value;
451
+  moneySafeForm.value.moneyType = selectedOptions[0].text;
452
+};
453
+
454
+const moneyInConfirm = ({ selectedOptions }) => {
455
+  moneyInFlag.value = false;
456
+  moneySafeForm.value.moneyIn = selectedOptions[0].text;
457
+};
458
+
459
+const getDeptInfo = (currentDeptInfo) => {
460
+  // 如果需要初始化部门信息,可以在这里处理
461
+  // 例如:moneySafeForm.value.moneyDept = currentDeptInfo
462
+}
463
+</script>
464
+
465
+<template>
466
+
467
+  <div class="page-container">
468
+    <van-sticky class="header">
469
+      <van-nav-bar
470
+        :title="title"
471
+        left-text="返回"
472
+        left-arrow
473
+        @click-left="onClickLeft" >
474
+      </van-nav-bar>
475
+    </van-sticky>
476
+    <div class="scroll-container">
477
+      <van-form @submit="onSubmit">
478
+        <van-field
479
+            v-model="moneySafeForm.moneyDept"
480
+        label="所属部门"
481
+        name="moneyDept"
482
+        readonly
483
+        placeholder="请选择所属部门"
484
+        @click="!isCaseSubmitted && (showBottom = true)"
485
+        :rules="[{required: true, message: '请选择所属部门'}]"
486
+        required
487
+      />
488
+
489
+        <van-field
490
+          v-model="moneySafeForm.moneyNumber"
491
+          label="投入费用"
492
+          name="moneyNumber"
493
+          :readonly="isCaseSubmitted"
494
+          required
495
+          placeholder="请输入投入费用"
496
+          :rules="[{required: true, message: '请输入投入费用'}]"
497
+        />
498
+
499
+        <!--        //时间-->
500
+        <van-field
501
+            v-model="moneySafeForm.useTime"
502
+            is-link
503
+            readonly
504
+            name="useTime"
505
+            label="使用日期"
506
+            :colon="true"
507
+            placeholder="点击选择日期"
508
+            @click="showDatetimePicker = !isCaseSubmitted"
509
+            :rules="[{ required:true, message: '请点击选择日期' }]"
510
+            required
511
+        />
512
+        <van-popup
513
+            v-model:show="showDatetimePicker"
514
+            position="bottom"
515
+            round
516
+            style="max-height: 50vh;"
517
+        >
518
+          <van-date-picker
519
+              v-model="currentDate"
520
+              title="选择日期"
521
+              :min-date="minDate"
522
+              :max-date="maxDate"
523
+              @confirm="onDateConfirm"
524
+              @cancel="cancelDatePicker"
525
+          >
526
+            <template #confirm>
527
+              <van-button type="primary" @click="onDateConfirm">确认</van-button>
528
+            </template>
529
+            <template #cancel>
530
+              <van-button type="danger" @click="cancelDatePicker">取消</van-button>
531
+            </template>
532
+          </van-date-picker>
533
+
534
+        </van-popup>
535
+
536
+
537
+        <van-field
538
+          v-model="moneySafeForm.moneyType"
539
+          is-link
540
+          readonly
541
+          label="费用类型"
542
+          name="moneyType"
543
+          placeholder="请选择"
544
+          @click="!isCaseSubmitted && (moneyTypeFlag = true)"
545
+          :rules="[{required: true, message: '请选择费用类型'}]"
546
+          required
547
+        />
548
+
549
+        <van-field
550
+            v-model="moneySafeForm.moneyIn"
551
+            is-link
552
+            readonly
553
+            label="资金来源"
554
+            name="moneyIn"
555
+            placeholder="请选择"
556
+            :rules="[{required: true, message: '请选择资金来源'}]"
557
+            @click="!isCaseSubmitted && (moneyInFlag = true)"
558
+            required
559
+        />
560
+
561
+        <van-field
562
+            v-model="moneySafeForm.moneyOut"
563
+            label="资金使用情况说明"
564
+            name="casualtyCount"
565
+            rows="1"
566
+            autosize
567
+            type="textarea"
568
+            placeholder="请输入事故造成后果"
569
+            :readonly="isCaseSubmitted"
570
+            :rules="[{required: true, message: '请输入事故造成后果'}]"
571
+            required
572
+        />
573
+        <van-field
574
+            v-model="moneySafeForm.otherDec"
575
+            label="备注"
576
+            name="accidentSummary"
577
+            rows="3"
578
+            autosize
579
+            type="textarea"
580
+            placeholder="请输入事故简要经过"
581
+            :readonly="isCaseSubmitted"
582
+        />
583
+        <div style="margin: 16px;">
584
+          <van-button v-if="!isReadOnly" round block type="primary" native-type="submit">
585
+            {{ isEdit ? '保存' : '提交' }}
586
+          </van-button>
587
+        </div>
588
+      </van-form>
589
+
590
+      <van-action-sheet
591
+        v-model:show="showActionSheet"
592
+        :actions="planLevelList"
593
+        @select="onSelect"
594
+      />
595
+      <van-action-sheet
596
+        v-model:show="showActionSheet2"
597
+        :actions="dicList"
598
+        @select="onSelect2"
599
+      />
600
+
601
+      <van-action-sheet
602
+          v-model:show="caseSourceFlag"
603
+          :actions="accidentDictList.case_source"
604
+          @select="onCaseSourseSelect"
605
+      />
606
+
607
+      <van-popup v-model:show="caseSourceFlag" round position="bottom">
608
+        <van-picker
609
+            :columns="columns"
610
+            @cancel="caseSourceFlag = false"
611
+            @confirm="onCaseSourceConfirm"
612
+        />
613
+      </van-popup>
614
+
615
+      <van-popup v-model:show="moneyTypeFlag" round position="bottom">
616
+        <van-picker
617
+            :columns="columnsLevel"
618
+            @cancel="moneyTypeFlag = false"
619
+            @confirm="moneyTypeLevelConfirm"
620
+        />
621
+      </van-popup>
622
+
623
+      <van-popup v-model:show="moneyInFlag" round position="bottom">
624
+        <van-picker
625
+            :columns="columnsIn"
626
+            @cancel="moneyInFlag = false"
627
+            @confirm="moneyInConfirm"
628
+        />
629
+      </van-popup>
630
+
631
+      <van-popup 
632
+        :close-on-click-overlay="false" 
633
+        :lazy-render="false" 
634
+        v-model:show="showBottom" 
635
+        position="bottom"
636
+      >
637
+        <OrganizationalWithLeaf 
638
+          @init="getDeptInfo" 
639
+          @close="showBottom = false" 
640
+          @update:selected-node="handleTableDataUserDeptUpdate" 
641
+        />
642
+      </van-popup>
643
+      <van-popup v-model:show="showDatePicker" position="bottom">
644
+        <van-date-picker
645
+          v-model="currentDate"
646
+          @confirm="onDatePicker"
647
+          @cancel="showDatePicker = false" />
648
+      </van-popup>
649
+    </div>
650
+  </div>
651
+</template>
652
+
653
+<style scoped>
654
+.page-container {
655
+  height: 100vh; /* 关键:外层容器高度设为视口高度 */
656
+  display: flex;
657
+  flex-direction: column;
658
+
659
+}
660
+/*  overflow-y: auto; !* 启用垂直滚动 *!*/
661
+
662
+
663
+.scroll-container {
664
+  flex: 1;
665
+  overflow: auto;
666
+  -webkit-overflow-scrolling: touch; /* iOS 平滑滚动 */
667
+}
668
+
669
+/* 可选:隐藏滚动条(视觉优化) */
670
+.scroll-container::-webkit-scrollbar {
671
+  display: none;
672
+}
673
+
674
+.header, .footer {
675
+  /* 固定高度区域 */
676
+  flex-shrink: 0; /* 防止被压缩 */
677
+  background: #f5f5f5;
678
+  padding: 12px;
679
+}
680
+</style>

Loading…
Cancel
Save