Browse Source

基本信息

miaofuhao 1 month ago
parent
commit
545f7055a0

+ 78 - 0
apps/web-ele/src/api/oilstation/emergency/emergency.ts

@@ -0,0 +1,78 @@
1
+import type { EmergencyMaterialModel, EmergencyMaterialListModel } from './model';
2
+
3
+import type { BaseResult } from '#/api/base-result';
4
+
5
+import { commonExport } from '#/api/helper';
6
+import { requestClient } from '#/api/request';
7
+
8
+// API路径常量枚举
9
+enum Api {
10
+  // 导出
11
+  export = '/gasEmergencyMaterial/material/export',
12
+  // 列表查询
13
+  list = '/gasEmergencyMaterial/material/list',
14
+  // 基础路径
15
+  root = '/gasEmergencyMaterial/material',
16
+}
17
+
18
+/**
19
+ * 查询场站应急防护列表
20
+ * @param params 查询参数
21
+ * @returns 分页结果
22
+ */
23
+export function emergencyMaterialList(params: any) {
24
+  return requestClient.get<BaseResult<EmergencyMaterialModel[]>>(Api.list, {
25
+    params,
26
+  });
27
+}
28
+
29
+/**
30
+ * 获取场站应急防护详细信息
31
+ * @param id 应急防护ID
32
+ * @returns 应急防护详情
33
+ */
34
+export function getEmergencyMaterialDetail(id: string) {
35
+  return requestClient.get<EmergencyMaterialModel>(`${Api.root}/${id}`);
36
+}
37
+
38
+/**
39
+ * 新增场站应急防护
40
+ * @param data 应急防护数据
41
+ * @returns 操作结果
42
+ */
43
+export function addEmergencyMaterial(data: EmergencyMaterialModel) {
44
+  return requestClient.post(Api.root, data, {
45
+    successMessageMode: 'message',
46
+  });
47
+}
48
+
49
+/**
50
+ * 修改场站应急防护
51
+ * @param data 应急防护数据
52
+ * @returns 操作结果
53
+ */
54
+export function updateEmergencyMaterial(data: EmergencyMaterialModel) {
55
+  return requestClient.put(Api.root, data, {
56
+    successMessageMode: 'message',
57
+  });
58
+}
59
+
60
+/**
61
+ * 删除场站应急防护
62
+ * @param ids 应急防护ID数组
63
+ * @returns 操作结果
64
+ */
65
+export function deleteEmergencyMaterial(ids: string[]) {
66
+  return requestClient.delete(`${Api.root}/${ids.join(',')}`, {
67
+    successMessageMode: 'message',
68
+  });
69
+}
70
+
71
+/**
72
+ * 导出场站应急防护列表
73
+ * @param data 导出参数
74
+ * @returns 导出结果
75
+ */
76
+export function exportEmergencyMaterial(data: Partial<EmergencyMaterialModel>) {
77
+  return commonExport(Api.export, data);
78
+}

+ 58 - 0
apps/web-ele/src/api/oilstation/emergency/model.ts

@@ -0,0 +1,58 @@
1
+export interface EmergencyMaterialModel {
2
+  /**
3
+   * 主键id
4
+   */
5
+  id?: number;
6
+  
7
+  /**
8
+   * 用品ID
9
+   */
10
+  protectionId?: number;
11
+  
12
+  /**
13
+   * 数量
14
+   */
15
+  quantity?: number;
16
+  
17
+  /**
18
+   * 场站ID
19
+   */
20
+  stationId?: number;
21
+  
22
+  /**
23
+   * 用品名称
24
+   */
25
+  itemName?: string;
26
+  
27
+  /**
28
+   * 用品类型
29
+   */
30
+  itemType?: string;
31
+  
32
+  /**
33
+   * 单位
34
+   */
35
+  unit?: string;
36
+  
37
+  /**
38
+   * 创建人
39
+   */
40
+  createBy?: string;
41
+  
42
+  /**
43
+   * 创建时间
44
+   */
45
+  createTime?: string;
46
+  
47
+  /**
48
+   * 更新人
49
+   */
50
+  updateBy?: string;
51
+  
52
+  /**
53
+   * 更新时间
54
+   */
55
+  updateTime?: string;
56
+}
57
+
58
+export type EmergencyMaterialListModel = EmergencyMaterialModel[];

+ 33 - 0
apps/web-ele/src/api/oilstation/firstaidkit/firstaidkit.ts

@@ -0,0 +1,33 @@
1
+import type { FirstAidKitModel, FirstAidKitListModel } from './model';
2
+
3
+import type { BaseResult } from '#/api/base-result';
4
+
5
+import { requestClient } from '#/api/request';
6
+
7
+// API路径常量枚举
8
+enum Api {
9
+  // 修改场站急救箱用品
10
+  update = '/gasFirstAidKit/kit',
11
+  // 查询场站急救箱用品列表
12
+  list = '/gasFirstAidKit/kit/list',
13
+}
14
+
15
+/**
16
+ * 查询场站急救箱用品列表
17
+ * @param stationId 场站ID
18
+ * @returns 急救箱用品列表
19
+ */
20
+export function getFirstAidKitList(stationId: number) {
21
+  return requestClient.get<BaseResult<FirstAidKitModel[]>>(`${Api.list}/${stationId}`);
22
+}
23
+
24
+/**
25
+ * 修改场站急救箱用品
26
+ * @param data 急救箱用品数据
27
+ * @returns 操作结果
28
+ */
29
+export function updateFirstAidKit(data: FirstAidKitModel | FirstAidKitListModel) {
30
+  return requestClient.put(Api.update, data, {
31
+    successMessageMode: 'message',
32
+  });
33
+}

+ 53 - 0
apps/web-ele/src/api/oilstation/firstaidkit/model.ts

@@ -0,0 +1,53 @@
1
+export interface FirstAidKitModel {
2
+  /**
3
+   * 主键id
4
+   */
5
+  id?: number;
6
+  
7
+  /**
8
+   * 检查数量
9
+   */
10
+  checkedQuantity?: number;
11
+  
12
+  /**
13
+   * 标准用品ID
14
+   */
15
+  itemId?: number;
16
+  
17
+  /**
18
+   * 场站ID
19
+   */
20
+  stationId?: number;
21
+  
22
+  /**
23
+   * 操作人
24
+   */
25
+  operator?: string;
26
+  
27
+  /**
28
+   * 操作时间
29
+   */
30
+  operationTime?: string;
31
+  
32
+  /**
33
+   * 创建人
34
+   */
35
+  createBy?: string;
36
+  
37
+  /**
38
+   * 创建时间
39
+   */
40
+  createTime?: string;
41
+  
42
+  /**
43
+   * 更新人
44
+   */
45
+  updateBy?: string;
46
+  
47
+  /**
48
+   * 更新时间
49
+   */
50
+  updateTime?: string;
51
+}
52
+
53
+export type FirstAidKitListModel = FirstAidKitModel[];

+ 6 - 0
apps/web-ele/src/api/system/infoEntry/emergencyInfo/emergencyInfo.ts

@@ -13,6 +13,12 @@ enum Api {
13 13
   list = '/sysEmergencyProtection/protection/list',
14 14
   // 基础路径
15 15
   root = '/sysEmergencyProtection/protection',
16
+  // 所有用品列表
17
+  all = '/sysEmergencyProtection/protection/all',
18
+}
19
+
20
+export function emergencyInfoAll() {
21
+  return requestClient.get<BaseResult<EmergencyInfoModel[]>>(Api.all);
16 22
 }
17 23
 
18 24
 /**

+ 6 - 2
apps/web-ele/src/api/system/infoEntry/stationInfo/stationInfo.ts

@@ -13,13 +13,17 @@ enum Api {
13 13
   list = '/sysStation/station/list',
14 14
   // 基础路径
15 15
   root = '/sysStation/station',
16
-  // 查询所有片区信息
17
-  selectAllSysStationList = '/sysStationArea/area/selectAllSysStationAreaList',
16
+  // 查询所有片区信息  /sysStationArea/area/selectAllSysStationAreaList
17
+  selectAllSysStationAreaList = '/sysStationArea/area/selectAllSysStationAreaList',
18
+  selectAllSysStationList = '/sysStation/station/selectAllSysStationList',
18 19
   selectAllSysStation = '/sysStation/station/selectAllSysStationList'
19 20
 }
20 21
 
21 22
 
22 23
 
24
+export function selectAllSysAreaList() {
25
+  return requestClient.get<BaseResult<StationInfoModel[]>>(Api.selectAllSysStationAreaList);
26
+}
23 27
 /**
24 28
  * 查询所有油站信息
25 29
  * @returns 油站列表

+ 3 - 3
apps/web-ele/src/views/oilstation/base/config-data.tsx

@@ -3,7 +3,7 @@ import type { VxeGridProps } from '#/adapter/vxe-table';
3 3
 
4 4
 import { DictEnum } from '@vben/constants';
5 5
 
6
-import { selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
6
+import { selectAllSysAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
7 7
 import { getDictOptions } from '#/utils/dict';
8 8
 import { renderDict } from '#/utils/render';
9 9
 
@@ -25,7 +25,7 @@ export const queryFormSchema: FormSchemaGetter = () => [
25 25
       placeholder: '请选择所属片区',
26 26
       clearable: true,
27 27
       api: async () => {
28
-        const resp = await selectAllSysStationAreaList();
28
+        const resp = await selectAllSysAreaList();
29 29
         const data = resp || [];
30 30
         return Array.isArray(data)
31 31
           ? data.map((item: any) => ({
@@ -141,7 +141,7 @@ export const drawerFormSchema: FormSchemaGetter = () => [
141 141
     componentProps: {
142 142
       placeholder: '请选择所属片区',
143 143
       api: async () => {
144
-        const resp = await selectAllSysStationAreaList();
144
+        const resp = await selectAllSysAreaList();
145 145
         const data = resp || [];
146 146
         return Array.isArray(data)
147 147
           ? data.map((item: any) => ({

+ 47 - 69
apps/web-ele/src/views/oilstation/emergency/emergency-data.tsx

@@ -1,18 +1,26 @@
1 1
 import type { FormSchemaGetter } from '#/adapter/form';
2 2
 import type { VxeGridProps } from '#/adapter/vxe-table';
3 3
 
4
+import { selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
5
+import { emergencyInfoAll } from '#/api/system/infoEntry/emergencyInfo/emergencyInfo';
6
+
7
+
8
+
4 9
 export const queryFormSchema: FormSchemaGetter = () => [
5 10
   {
6
-    component: 'Select',
7
-    fieldName: 'stationName',
11
+    component: 'ApiSelect',
12
+    fieldName: 'stationId',
8 13
     label: '油站',
9 14
     componentProps: {
10 15
       placeholder: '请选择油站',
11
-      options: [
12
-        { label: '第一加油站', value: '第一加油站' },
13
-        { label: '第二加油站', value: '第二加油站' },
14
-        { label: '第三加油站', value: '第三加油站' },
15
-      ],
16
+      api: async () => {
17
+        const response = await selectAllSysStationAreaList({});
18
+        const data = response || [];
19
+        return Array.isArray(data) ? data.map(item => ({
20
+          label: item.stationName,
21
+          value: item.id.toString()
22
+        })) : [];
23
+      },
16 24
     },
17 25
   },
18 26
   {
@@ -43,21 +51,14 @@ export const tableColumns: VxeGridProps['columns'] = [
43 51
     minWidth: 120,
44 52
   },
45 53
   {
46
-    field: 'name',
54
+    field: 'itemName',
47 55
     title: '名称',
48 56
     minWidth: 120,
49 57
   },
50 58
   {
51
-    field: 'type',
59
+    field: 'itemTypeName',
52 60
     title: '类型',
53 61
     minWidth: 120,
54
-    formatter: ({ cellValue }) => ({
55
-      fire_extinguisher: '灭火器',
56
-      gas_mask: '防毒面具',
57
-      first_aid_kit: '急救箱',
58
-      protective_clothing: '防护服',
59
-      fire_hydrant: '消防栓',
60
-    })[cellValue] || cellValue,
61 62
   },
62 63
   {
63 64
     field: 'unit',
@@ -70,11 +71,6 @@ export const tableColumns: VxeGridProps['columns'] = [
70 71
     minWidth: 80,
71 72
   },
72 73
   {
73
-    field: 'remark',
74
-    title: '备注',
75
-    minWidth: 150,
76
-  },
77
-  {
78 74
     field: 'createBy',
79 75
     title: '操作人',
80 76
     minWidth: 120,
@@ -103,52 +99,43 @@ export const drawerFormSchema: FormSchemaGetter = () => [
103 99
     fieldName: 'id',
104 100
   },
105 101
   {
106
-    component: 'Select',
107
-    fieldName: 'stationName',
102
+    component: 'ApiSelect',
103
+    fieldName: 'stationId',
108 104
     label: '油站',
109 105
     componentProps: {
110 106
       placeholder: '请选择油站',
111
-      options: [
112
-        { label: '第一加油站', value: '第一加油站' },
113
-        { label: '第二加油站', value: '第二加油站' },
114
-        { label: '第三加油站', value: '第三加油站' },
115
-      ],
116
-    },
117
-    rules: 'required',
118
-  },
119
-  {
120
-    component: 'Input',
121
-    fieldName: 'name',
122
-    label: '名称',
123
-    componentProps: {
124
-      placeholder: '请输入名称',
125
-      maxlength: 100,
126
-    },
127
-    rules: 'required',
128
-  },
129
-  {
130
-    component: 'Select',
131
-    fieldName: 'type',
132
-    label: '类型',
133
-    componentProps: {
134
-      placeholder: '请选择类型',
135
-      options: [
136
-        { label: '灭火器', value: 'fire_extinguisher' },
137
-        { label: '防毒面具', value: 'gas_mask' },
138
-        { label: '急救箱', value: 'first_aid_kit' },
139
-        { label: '防护服', value: 'protective_clothing' },
140
-        { label: '消防栓', value: 'fire_hydrant' },
141
-      ],
107
+      api: async () => {
108
+        const response = await selectAllSysStationAreaList({});
109
+        const data = response || [];
110
+        return Array.isArray(data) ? data.map(item => ({
111
+          label: item.stationName,
112
+          value: item.id.toString()
113
+        })) : [];
114
+      },
142 115
     },
143 116
     rules: 'required',
144 117
   },
145 118
   {
146
-    component: 'Input',
147
-    fieldName: 'unit',
148
-    label: '单位',
119
+    component: 'ApiSelect',
120
+    fieldName: 'protectionId',
121
+    label: '用品名称',
149 122
     componentProps: {
150
-      placeholder: '请输入单位',
151
-      maxlength: 20,
123
+      placeholder: '请选择用品名称',
124
+      api: async () => {
125
+        try {
126
+          // 调用真实的用品名称接口
127
+          const response = await emergencyInfoAll();
128
+          const data = response || [];
129
+          console.log('获取到的用品数据:', data);
130
+          return Array.isArray(data) ? data.map((item: any) => ({
131
+            label: item.name || item.itemName || `用品${item.id}`,
132
+            value: item.id.toString()
133
+          })) : [];
134
+        } catch (error) {
135
+          console.error('获取用品名称列表失败:', error);
136
+          return [];
137
+        }
138
+      },
152 139
     },
153 140
     rules: 'required',
154 141
   },
@@ -163,14 +150,5 @@ export const drawerFormSchema: FormSchemaGetter = () => [
163 150
     },
164 151
     rules: 'required',
165 152
   },
166
-  {
167
-    component: 'Input',
168
-    fieldName: 'remark',
169
-    label: '备注',
170
-    componentProps: {
171
-      maxlength: 500,
172
-      type: 'textarea',
173
-      showWordLimit: true,
174
-    },
175
-  },
176 153
 ];
154
+

+ 28 - 14
apps/web-ele/src/views/oilstation/emergency/emergency-drawer.vue

@@ -2,8 +2,10 @@
2 2
 import { ref } from 'vue';
3 3
 
4 4
 import { useVbenDrawer, useVbenForm } from '@vben/common-ui';
5
+import { ElMessage } from 'element-plus';
5 6
 
6 7
 import { drawerFormSchema } from './emergency-data';
8
+import { addEmergencyMaterial, getEmergencyMaterialDetail, updateEmergencyMaterial } from '#/api/oilstation/emergency/emergency';
7 9
 
8 10
 const emit = defineEmits<{
9 11
   reload: [];
@@ -26,20 +28,21 @@ const [Drawer, drawerApi] = useVbenDrawer({
26 28
       const { id, isUpdate } = drawerApi.getData();
27 29
       isUpdateRef.value = isUpdate;
28 30
       if (isUpdate && id) {
29
-        // 模拟获取详情数据
30
-        const mockDetail = {
31
-          id,
32
-          stationName: '第一加油站',
33
-          name: '干粉灭火器',
34
-          type: 'fire_extinguisher',
35
-          unit: '个',
36
-          quantity: 5,
37
-          remark: '定期检查压力',
31
+        const response = await getEmergencyMaterialDetail(id.toString());
32
+        const detailData = response?.data || response;
33
+        
34
+        // 处理数据格式,确保与表单字段匹配
35
+        const formData = {
36
+          id: detailData.id,
37
+          stationId: detailData.stationId?.toString() || '',
38
+          protectionId: detailData.protectionId?.toString() || '',
39
+          quantity: detailData.quantity || 0,
38 40
         };
39
-        await formApi.setValues(mockDetail);
41
+        await formApi.setValues(formData);
40 42
       }
41 43
     } catch (error) {
42 44
       console.error('获取应急防护详情失败:', error);
45
+      ElMessage.error('获取应急防护详情失败');
43 46
     } finally {
44 47
       drawerApi.drawerLoading(false);
45 48
     }
@@ -53,13 +56,24 @@ const [Drawer, drawerApi] = useVbenDrawer({
53 56
         return;
54 57
       }
55 58
       const data = await formApi.getValues();
56
-      // 模拟提交数据
57
-      console.log('提交数据:', data);
58
-      // 模拟成功
59
+      
60
+      // 处理提交数据格式
61
+      const submitData = {
62
+        id: data.id,
63
+        stationId: Number(data.stationId),
64
+        protectionId: Number(data.protectionId),
65
+        quantity: data.quantity,
66
+      };
67
+      
68
+      await (isUpdateRef.value
69
+        ? updateEmergencyMaterial(submitData)
70
+        : addEmergencyMaterial(submitData));
71
+      
59 72
       emit('reload');
60 73
       drawerApi.close();
61 74
     } catch (error) {
62 75
       console.error('保存应急防护信息失败:', error);
76
+      ElMessage.error('保存应急防护信息失败');
63 77
     } finally {
64 78
       this.confirmLoading = false;
65 79
     }
@@ -75,4 +89,4 @@ const [Drawer, drawerApi] = useVbenDrawer({
75 89
   <Drawer :title="isUpdateRef ? '编辑应急防护' : '新增应急防护'">
76 90
     <Form />
77 91
   </Drawer>
78
-</template>
92
+</template>

+ 39 - 87
apps/web-ele/src/views/oilstation/emergency/index.vue

@@ -7,12 +7,13 @@ import { ref } from 'vue';
7 7
 
8 8
 import { Page, useVbenDrawer } from '@vben/common-ui';
9 9
 
10
-import { ElMessageBox } from 'element-plus';
10
+import { ElMessageBox, ElMessage } from 'element-plus';
11 11
 
12 12
 import { useVbenVxeGrid } from '#/adapter/vxe-table';
13 13
 
14 14
 import { queryFormSchema, tableColumns } from './emergency-data';
15 15
 import EmergencyDrawerComp from './emergency-drawer.vue';
16
+import { emergencyMaterialList, deleteEmergencyMaterial } from '#/api/oilstation/emergency/emergency';
16 17
 
17 18
 const formOptions: VbenFormProps = {
18 19
   commonConfig: {
@@ -25,68 +26,6 @@ const formOptions: VbenFormProps = {
25 26
   wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',
26 27
 };
27 28
 
28
-// 模拟数据
29
-const mockData = {
30
-  rows: [
31
-    {
32
-      id: 1,
33
-      stationName: '第一加油站',
34
-      name: '干粉灭火器',
35
-      type: 'fire_extinguisher',
36
-      unit: '个',
37
-      quantity: 5,
38
-      remark: '定期检查压力',
39
-      createBy: '管理员',
40
-      createTime: '2024-01-01 10:00:00',
41
-    },
42
-    {
43
-      id: 2,
44
-      stationName: '第二加油站',
45
-      name: '防毒面具',
46
-      type: 'gas_mask',
47
-      unit: '套',
48
-      quantity: 10,
49
-      remark: '有效期至2025-12-31',
50
-      createBy: '管理员',
51
-      createTime: '2024-01-02 11:00:00',
52
-    },
53
-    {
54
-      id: 3,
55
-      stationName: '第一加油站',
56
-      name: '急救箱',
57
-      type: 'first_aid_kit',
58
-      unit: '个',
59
-      quantity: 2,
60
-      remark: '包含常用药品',
61
-      createBy: '管理员',
62
-      createTime: '2024-01-03 12:00:00',
63
-    },
64
-    {
65
-      id: 4,
66
-      stationName: '第三加油站',
67
-      name: '防护服',
68
-      type: 'protective_clothing',
69
-      unit: '套',
70
-      quantity: 8,
71
-      remark: '防火防化',
72
-      createBy: '管理员',
73
-      createTime: '2024-01-04 13:00:00',
74
-    },
75
-    {
76
-      id: 5,
77
-      stationName: '第二加油站',
78
-      name: '消防栓',
79
-      type: 'fire_hydrant',
80
-      unit: '个',
81
-      quantity: 3,
82
-      remark: '每月检查一次',
83
-      createBy: '管理员',
84
-      createTime: '2024-01-05 14:00:00',
85
-    },
86
-  ],
87
-  total: 5,
88
-};
89
-
90 29
 const gridOptions: VxeGridProps = {
91 30
   checkboxConfig: {
92 31
     highlight: true,
@@ -99,24 +38,27 @@ const gridOptions: VxeGridProps = {
99 38
   proxyConfig: {
100 39
     ajax: {
101 40
       query: async ({ page }, formValues = {}) => {
102
-        // 模拟API请求
103
-        console.log('查询参数:', formValues, page);
104
-        // 模拟过滤
105
-        let filteredRows = [...mockData.rows];
106
-        if (formValues.stationName) {
107
-          filteredRows = filteredRows.filter(row => row.stationName === formValues.stationName);
108
-        }
109
-        if (formValues.type) {
110
-          filteredRows = filteredRows.filter(row => row.type === formValues.type);
41
+        try {
42
+          // 构建查询参数
43
+          const params = {
44
+            ...formValues,
45
+            pageNum: page.currentPage,
46
+            pageSize: page.pageSize,
47
+          };
48
+          
49
+          // 调用API获取数据
50
+          const response = await emergencyMaterialList(params);
51
+          console.log('查询应急防护列表响应:', response)
52
+          const data = response || {};
53
+          return { 
54
+            items: data.rows|| [], 
55
+            total: data.total || 0 
56
+          };
57
+        } catch (error) {
58
+          console.error('查询应急防护列表失败:', error);
59
+          ElMessage.error('查询应急防护列表失败');
60
+          return { items: [], total: 0 };
111 61
         }
112
-        // 模拟分页
113
-        const start = (page.currentPage - 1) * page.pageSize;
114
-        const end = start + page.pageSize;
115
-        const paginatedRows = filteredRows.slice(start, end);
116
-        return { 
117
-          items: paginatedRows, 
118
-          total: filteredRows.length 
119
-        };
120 62
       },
121 63
     },
122 64
   },
@@ -152,15 +94,20 @@ function handleEdit(row: any) {
152 94
 
153 95
 // 单个删除应急防护
154 96
 async function confirmEvent(row: any) {
155
-  // 模拟删除操作
156
-  console.log('删除应急防护:', row.id);
157
-  await basicTableApi.reload();
97
+  try {
98
+    await deleteEmergencyMaterial([row.id.toString()]);
99
+    ElMessage.success('删除成功');
100
+    await basicTableApi.reload();
101
+  } catch (error) {
102
+    console.error('删除应急防护失败:', error);
103
+    ElMessage.error('删除应急防护失败');
104
+  }
158 105
 }
159 106
 
160 107
 // 批量删除应急防护
161 108
 function deleteHandle() {
162 109
   const checkRecords = basicTableApi.grid.getCheckboxRecords();
163
-  const ids = checkRecords.map((item: any) => item.id);
110
+  const ids = checkRecords.map((item: any) => item.id.toString());
164 111
   if (ids.length <= 0) {
165 112
     return;
166 113
   }
@@ -170,9 +117,14 @@ function deleteHandle() {
170 117
     cancelButtonText: '取消',
171 118
     type: 'warning',
172 119
   }).then(async () => {
173
-    // 模拟批量删除操作
174
-    console.log('批量删除应急防护:', ids);
175
-    await basicTableApi.reload();
120
+    try {
121
+      await deleteEmergencyMaterial(ids);
122
+      ElMessage.success('删除成功');
123
+      await basicTableApi.reload();
124
+    } catch (error) {
125
+      console.error('批量删除应急防护失败:', error);
126
+      ElMessage.error('批量删除应急防护失败');
127
+    }
176 128
   });
177 129
 }
178 130
 </script>

+ 34 - 43
apps/web-ele/src/views/oilstation/extinguisher/extinguisher-data.tsx

@@ -1,15 +1,27 @@
1 1
 import type { FormSchemaGetter } from '#/adapter/form';
2 2
 import type { VxeGridProps } from '#/adapter/vxe-table';
3 3
 
4
+import { selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
5
+
4 6
 export const queryFormSchema: FormSchemaGetter = () => [
5
-  {
6
-    component: 'Input',
7
-    fieldName: 'stationName',
8
-    label: '油站',
9
-    componentProps: {
10
-      placeholder: '请输入油站名称',
7
+   {
8
+      component: 'ApiSelect',
9
+      fieldName: 'stationId',
10
+      label: '油站',
11
+      componentProps: {
12
+        placeholder: '请选择油站',
13
+        api: async () => {
14
+          const resp = await selectAllSysStationAreaList();
15
+          const data = resp || [];
16
+          return Array.isArray(data)
17
+            ? data.map((item: any) => ({
18
+                label: item.stationName,
19
+                value: item.id.toString(),
20
+              }))
21
+            : [];
22
+        },
23
+      },
11 24
     },
12
-  },
13 25
   {
14 26
     component: 'DatePicker',
15 27
     componentProps: {
@@ -85,14 +97,7 @@ export const tableColumns: VxeGridProps['columns'] = [
85 97
       params.cellValue,
86 98
   },
87 99
   {
88
-    field: 'remark',
89
-    title: '备注',
90
-    minWidth: 150,
91
-    formatter: (params: { cellValue: string; column: any; row: any }) =>
92
-      params.cellValue,
93
-  },
94
-  {
95
-    field: 'operatorName',
100
+    field: 'updateBy',
96 101
     title: '操作人姓名',
97 102
     minWidth: 120,
98 103
     formatter: (params: { cellValue: string; column: any; row: any }) =>
@@ -117,12 +122,21 @@ export const drawerFormSchema: FormSchemaGetter = () => [
117 122
     fieldName: 'id',
118 123
   },
119 124
   {
120
-    component: 'Input',
121
-    fieldName: 'stationName',
125
+    component: 'ApiSelect',
126
+    fieldName: 'stationId',
122 127
     label: '油站',
123 128
     componentProps: {
124
-      placeholder: '请输入油站名称',
125
-      maxlength: 100,
129
+      placeholder: '请选择油站',
130
+      api: async () => {
131
+        const resp = await selectAllSysStationAreaList();
132
+        const data = resp || [];
133
+        return Array.isArray(data)
134
+          ? data.map((item: any) => ({
135
+              label: item.stationName,
136
+              value: item.id.toString(),
137
+            }))
138
+          : [];
139
+      },
126 140
     },
127 141
     rules: 'required',
128 142
   },
@@ -190,28 +204,5 @@ export const drawerFormSchema: FormSchemaGetter = () => [
190 204
     label: '有效日期',
191 205
     rules: 'required',
192 206
   },
193
-  {
194
-    component: 'Input',
195
-    fieldName: 'remark',
196
-    label: '备注',
197
-    componentProps: {
198
-      placeholder: '请输入备注',
199
-      maxlength: 200,
200
-      type: 'textarea',
201
-      showWordLimit: true,
202
-    },
203
-  },
204
-  {
205
-    component: 'Input',
206
-    dependencies: {
207
-      show: () => false,
208
-      triggerFields: [''],
209
-    },
210
-    componentProps: {
211
-      placeholder: '请输入油站ID',
212
-      maxlength: 100,
213
-    },
214
-    fieldName: 'stationId',
215
-    label: '油站ID',
216
-  },
207
+
217 208
 ];

+ 1 - 2
apps/web-ele/src/views/oilstation/extinguisher/extinguisher-drawer.vue

@@ -61,8 +61,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
61 61
 
62 62
       // 确保使用正确的字段名提交数据
63 63
       const submitData = {
64
-        ...data,
65
-        stationId: 1, // 默认油站ID,实际应从表单或其他地方获取
64
+        ...data
66 65
       };
67 66
 
68 67
       console.log('提交数据:', submitData);

+ 117 - 28
apps/web-ele/src/views/oilstation/firstaidkit/index.vue

@@ -1,36 +1,109 @@
1 1
 <script setup lang="ts">
2
-import { ref, reactive } from 'vue'
2
+import { ref, reactive, onMounted } from 'vue'
3 3
 import { ElMessage } from 'element-plus'
4 4
 
5
-// 模拟油站数据
6
-const stations = [
7
-  { label: '龙飞加油站', value: '1' },
8
-  { label: '和平加油站', value: '2' },
9
-  { label: '安全加油站', value: '3' }
10
-]
11
-
12
-// 模拟急救箱用品数据
13
-const firstAidItems = reactive([
14
-  { id: 1, name: '一次性手套', unit: '双', standardQty: 5, checkQty: 5 },
15
-  { id: 2, name: '云南白药(气雾剂)', unit: '瓶', standardQty: 1, checkQty: 1 },
16
-  { id: 3, name: '创可贴', unit: '片', standardQty: 30, checkQty: 30 },
17
-  { id: 4, name: '医用酒精棉球或类似用品', unit: '瓶', standardQty: 2, checkQty: 2 },
18
-  { id: 5, name: '红花油', unit: '瓶', standardQty: 1, checkQty: 1 },
19
-  { id: 6, name: '绷带', unit: '卷', standardQty: 2, checkQty: 2 },
20
-  { id: 7, name: '脱脂棉', unit: '包', standardQty: 2, checkQty: 2 },
21
-  { id: 8, name: '脱脂棉签', unit: '包', standardQty: 1, checkQty: 1 },
22
-  { id: 9, name: '风油精', unit: '瓶', standardQty: 2, checkQty: 2 },
23
-  { id: 10, name: '胶带', unit: '卷', standardQty: 2, checkQty: 2 }
24
-])
5
+import { selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo'
6
+import { getFirstAidKitList, updateFirstAidKit } from '#/api/oilstation/firstaidkit/firstaidkit'
25 7
 
8
+// 油站数据
9
+const stations = ref<any[]>([])
10
+// 急救箱用品数据
11
+const firstAidItems = reactive<any[]>([])
12
+// 加载状态
13
+const loading = ref(false)
26 14
 // 选中的油站
27
-const selectedStation = ref('1')
15
+const selectedStation = ref('')
16
+
17
+// 获取油站列表
18
+const fetchStations = async () => {
19
+  try {
20
+    const response = await selectAllSysStationAreaList()
21
+    const data = response || []
22
+    stations.value = Array.isArray(data) ? data.map(item => ({
23
+      label: item.stationName,
24
+      value: item.id.toString()
25
+    })) : []
26
+    
27
+    // 默认选中第一个油站
28
+    if (stations.value.length > 0) {
29
+      selectedStation.value = stations.value[0].value
30
+      fetchFirstAidKitList()
31
+    }
32
+  } catch (error) {
33
+    console.error('获取油站列表失败:', error)
34
+    ElMessage.error('获取油站列表失败')
35
+  }
36
+}
37
+
38
+// 获取急救箱用品列表
39
+const fetchFirstAidKitList = async () => {
40
+  if (!selectedStation.value) return
41
+  
42
+  loading.value = true
43
+  try {
44
+    const response = await getFirstAidKitList(Number(selectedStation.value))
45
+    console.log('获取急救箱用品列表响应:', response)
46
+    const data = response || []
47
+    
48
+    // 处理数据格式,确保与页面显示字段匹配
49
+    firstAidItems.splice(0, firstAidItems.length)
50
+    if (Array.isArray(data)) {
51
+      data.forEach(item => {
52
+        firstAidItems.push({
53
+          id: item.id,
54
+          itemId: item.itemId,
55
+          name: item.name || `用品${item.itemId}`, // 如果没有名称,使用默认名称
56
+          unit: item.unit || '', // 如果没有单位,使用空字符串
57
+          standardQty: item.standardQuantity || 0, // 标准数量
58
+          checkQty: item.checkedQuantity || 0, // 检查数量
59
+          stationId: item.stationId
60
+        })
61
+      })
62
+    }
63
+  } catch (error) {
64
+    console.error('获取急救箱用品列表失败:', error)
65
+    ElMessage.error('获取急救箱用品列表失败')
66
+  } finally {
67
+    loading.value = false
68
+  }
69
+}
28 70
 
29 71
 // 保存修改
30
-const saveChanges = () => {
31
-  // 这里可以添加保存逻辑,如调用接口
32
-  ElMessage.success('保存成功')
72
+const saveChanges = async () => {
73
+  if (!selectedStation.value) {
74
+    ElMessage.warning('请选择油站')
75
+    return
76
+  }
77
+  
78
+  loading.value = true
79
+  try {
80
+    // 构建保存数据格式
81
+    const saveData = firstAidItems.map(item => ({
82
+      id: item.id,
83
+      itemId: item.itemId,
84
+      checkedQuantity: item.checkQty,
85
+      stationId: Number(selectedStation.value)
86
+    }))
87
+    
88
+    await updateFirstAidKit(saveData)
89
+    ElMessage.success('保存成功')
90
+  } catch (error) {
91
+    console.error('保存失败:', error)
92
+    ElMessage.error('保存失败')
93
+  } finally {
94
+    loading.value = false
95
+  }
33 96
 }
97
+
98
+// 当油站变更时,重新获取急救箱用品列表
99
+const handleStationChange = () => {
100
+  fetchFirstAidKitList()
101
+}
102
+
103
+// 组件挂载时获取油站列表
104
+onMounted(() => {
105
+  fetchStations()
106
+})
34 107
 </script>
35 108
 
36 109
 <template>
@@ -38,7 +111,12 @@ const saveChanges = () => {
38 111
     <div class="search-container">
39 112
       <el-form :inline="true" label-position="right">
40 113
         <el-form-item label="油站" label-width="80px">
41
-          <el-select v-model="selectedStation" placeholder="请选择油站" style="width: 200px">
114
+          <el-select 
115
+            v-model="selectedStation" 
116
+            placeholder="请选择油站" 
117
+            style="width: 200px"
118
+            @change="handleStationChange"
119
+          >
42 120
             <el-option
43 121
               v-for="station in stations"
44 122
               :key="station.value"
@@ -51,7 +129,12 @@ const saveChanges = () => {
51 129
     </div>
52 130
 
53 131
     <div class="table-container">
54
-      <el-table :data="firstAidItems" border style="width: 100%">
132
+      <el-table 
133
+        v-loading="loading" 
134
+        :data="firstAidItems" 
135
+        border 
136
+        style="width: 100%"
137
+      >
55 138
         <el-table-column prop="name" label="用品名称"/>
56 139
         <el-table-column prop="unit" label="单位"/>
57 140
         <el-table-column prop="standardQty" label="标准数量"/>
@@ -69,7 +152,13 @@ const saveChanges = () => {
69 152
     </div>
70 153
 
71 154
     <div class="action-container">
72
-      <el-button type="primary" @click="saveChanges">保存</el-button>
155
+      <el-button 
156
+        type="primary" 
157
+        @click="saveChanges"
158
+        :loading="loading"
159
+      >
160
+        保存
161
+      </el-button>
73 162
     </div>
74 163
   </div>
75 164
 </template>

+ 95 - 64
apps/web-ele/src/views/oilstation/idphoto/idphoto-data.tsx

@@ -3,8 +3,9 @@ import type { VxeGridProps } from '#/adapter/vxe-table';
3 3
 
4 4
 import { DictEnum } from '@vben/constants';
5 5
 
6
-import { stationInfoList } from '#/api/system/infoEntry/stationInfo/stationInfo';
6
+import { selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
7 7
 import { getSingleImageUploadConfig,getFileUploadConfig } from '#/components/upload';
8
+import { requestClient } from '#/api/request';
8 9
 // import { uploadFile } from '#/api/upload';
9 10
 import { getDictOptions } from '#/utils/dict';
10 11
 import { renderDict } from '#/utils/render';
@@ -21,8 +22,22 @@ const DICT_KEYS = {
21 22
   STATUS: 'status',
22 23
 };
23 24
 
24
-// 获取证照类型字典选项
25
-const getCertificateTypes = () => getDictOptions(DICT_KEYS.ID_PAPERS_NAME);
25
+// 获取证照类型列表
26
+const getCertificateTypes = async () => {
27
+  try {
28
+    const resp = await requestClient.get('/sysLicenseRule/rule/allList');
29
+    const data = resp || [];
30
+    return Array.isArray(data)
31
+      ? data.map((item: any) => ({
32
+          label: item.licenseName,
33
+          value: item.id,
34
+        }))
35
+      : [];
36
+  } catch (error) {
37
+    console.error('获取证照类型失败:', error);
38
+    return [];
39
+  }
40
+};
26 41
 
27 42
 // 获取机构类型字典选项
28 43
 const getOrganizationTypes = () =>
@@ -34,24 +49,34 @@ const getStorageLocations = () => getDictOptions(DICT_KEYS.ID_PAPERS_STORAGE);
34 49
 // 获取状态字典选项
35 50
 const getStatusOptions = () =>
36 51
   getDictOptions(DICT_KEYS.STATUS) || [
37
-    { label: '启用', value: '1' },
38
-    { label: '禁用', value: '0' },
52
+    { label: '启用', value: 1 },
53
+    { label: '禁用', value: 0 },
39 54
   ];
40 55
 
41 56
 export const queryFormSchema: FormSchemaGetter = () => [
42 57
   {
43
-    component: 'Input',
44
-    fieldName: 'stationName',
58
+    component: 'ApiSelect',
59
+    fieldName: 'stationId',
45 60
     label: '油站',
46 61
     componentProps: {
47
-      placeholder: '请输入油站名称',
62
+      placeholder: '请选择油站',
63
+      api: async () => {
64
+        const resp = await selectAllSysStationAreaList();
65
+        const data = resp || [];
66
+        return Array.isArray(data)
67
+          ? data.map((item: any) => ({
68
+              label: item.stationName,
69
+              value: item.id.toString(),
70
+            }))
71
+          : [];
72
+      },
48 73
     },
49 74
   },
50 75
   {
51
-    component: 'Select',
76
+    component: 'ApiSelect',
52 77
     componentProps: {
53 78
       placeholder: '请选择证照名称',
54
-      options: getCertificateTypes(),
79
+      api: getCertificateTypes,
55 80
     },
56 81
     fieldName: 'licenseNameCode',
57 82
     label: '证照名称',
@@ -73,8 +98,8 @@ export const queryFormSchema: FormSchemaGetter = () => [
73 98
     componentProps: {
74 99
       placeholder: '请选择状态',
75 100
       options: [
76
-        { label: '启用', value: '1' },
77
-        { label: '禁用', value: '0' },
101
+        { label: '启用', value: 1 },
102
+        { label: '禁用', value: 0 },
78 103
       ],
79 104
     },
80 105
     fieldName: 'statusCode',
@@ -93,14 +118,9 @@ export const tableColumns: VxeGridProps['columns'] = [
93 118
     minWidth: 120,
94 119
   },
95 120
   {
96
-    field: 'licenseNameCode',
121
+    field: 'licenseName',
97 122
     title: '证照名称',
98 123
     minWidth: 150,
99
-    formatter: (params: { cellValue: string; column: any; row: any }) => {
100
-      const options = getCertificateTypes();
101
-      const option = options.find((item) => item.value === params.cellValue);
102
-      return option ? option.label : params.cellValue;
103
-    },
104 124
   },
105 125
   {
106 126
     field: 'orgTypeCode',
@@ -171,15 +191,9 @@ export const tableColumns: VxeGridProps['columns'] = [
171 191
     minWidth: 100,
172 192
     slots: {
173 193
       default: ({ row }) => {
174
-        return renderDict(row.statusCode, DictEnum.SYS_DISABLED_STATUS);
194
+        return renderDict(row.statusCode.toString(), DictEnum.SYS_DISABLED_STATUS);
175 195
       },
176 196
     },
177
-    // formatter: (params: { cellValue: string; column: any; row: any }) => {
178
-    //   const options = getStatusOptions();
179
-    //   const option = options.find((item) => item.value === params.cellValue);
180
-    //   const color = params.cellValue === '1' ? 'success' : 'danger';
181
-    //   return `<el-tag type="${color}">${option ? option.label : params.cellValue}</el-tag>`;
182
-    // },
183 197
   },
184 198
   {
185 199
     field: 'action',
@@ -201,18 +215,18 @@ export const drawerFormSchema: FormSchemaGetter = () => [
201 215
   },
202 216
   {
203 217
     component: 'ApiSelect',
204
-    fieldName: 'stationName',
218
+    fieldName: 'stationId',
205 219
     label: '油站',
206 220
     componentProps: {
207 221
       placeholder: '请输入油站名称',
208 222
       maxlength: 100,
209 223
       api: async () => {
210
-        const resp = await stationInfoList({});
211
-        const data = resp.rows || [];
224
+        const resp = await selectAllSysStationAreaList();
225
+        const data = resp || [];
212 226
         return Array.isArray(data)
213 227
           ? data.map((item: any) => ({
214 228
               label: item.stationName,
215
-              value: item.id,
229
+              value: item.id.toString(),
216 230
             }))
217 231
           : [];
218 232
       },
@@ -220,12 +234,50 @@ export const drawerFormSchema: FormSchemaGetter = () => [
220 234
     rules: 'required',
221 235
   },
222 236
   {
223
-    component: 'Select',
224
-    componentProps: {
225
-      placeholder: '请选择证照名称',
226
-      options: getCertificateTypes(),
237
+    component: 'Input',
238
+    dependencies: {
239
+      show: () => false,
240
+      triggerFields: [''],
227 241
     },
228
-    fieldName: 'licenseNameCode',
242
+    fieldName: 'licenseName',
243
+  },
244
+  {
245
+    component: 'ApiSelect',
246
+    componentProps: (form: any) => {
247
+      return {
248
+        placeholder: '请选择证照名称',
249
+        api: async () => {
250
+          const resp = await requestClient.get('/sysLicenseRule/rule/allList');
251
+          const data = resp || [];
252
+          return Array.isArray(data)
253
+            ? data.map((item: any) => ({
254
+                label: item.licenseName,
255
+                value: item.id,
256
+                // 存储任务要求信息
257
+                renewalRequirements: item.renewRequirements,
258
+              }))
259
+            : [];
260
+        },
261
+        onChange: async (selectedId: string | number) => {
262
+          if (selectedId && form) {
263
+            try {
264
+              // 获取选中的证照信息
265
+              const resp = await requestClient.get('/sysLicenseRule/rule/allList');
266
+              const data = resp || [];
267
+              const selectedLicense = data.find((item: any) => item.id === selectedId);
268
+              if (selectedLicense) {
269
+                // 设置任务要求
270
+                form.renewalRequirements = selectedLicense.renewRequirements;
271
+                form.licenseName = selectedLicense.licenseName;
272
+              }
273
+            } catch (error) {
274
+              console.error('获取证照详情失败:', error);
275
+            }
276
+          }
277
+        },
278
+      };
279
+    },
280
+    fieldName: 'licenseRuleId',
229 281
     label: '证照名称',
230 282
     rules: 'required',
231 283
   },
@@ -316,28 +368,6 @@ export const drawerFormSchema: FormSchemaGetter = () => [
316 368
     },
317 369
   },
318 370
   {
319
-    component: 'DatePicker',
320
-    componentProps: {
321
-      type: 'date',
322
-      format: 'YYYY-MM-DD HH:mm:ss',
323
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
324
-      placeholder: '请选择下次年审时间',
325
-    },
326
-    fieldName: 'nextAnnualReviewDate',
327
-    label: '下次年审时间',
328
-  },
329
-  {
330
-    component: 'DatePicker',
331
-    componentProps: {
332
-      type: 'date',
333
-      format: 'YYYY-MM-DD HH:mm:ss',
334
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
335
-      placeholder: '请选择下次换证日期',
336
-    },
337
-    fieldName: 'nextRenewalDate',
338
-    label: '下次换证日期',
339
-  },
340
-  {
341 371
     component: 'Input',
342 372
     fieldName: 'certificateScanPath',
343 373
     label: '证件扫描件',
@@ -354,12 +384,13 @@ export const drawerFormSchema: FormSchemaGetter = () => [
354 384
       return {
355 385
         ...getFileUploadConfig('.pdf,.docx,.doc,.txt', 'text', 1, '/common/upload'),
356 386
         onSuccess: (res: any) => {
357
-          if (res.code === 200) {
358
-            row.certificateScanPath = res.data.fileName;
359
-            // form.setFieldValue('certificateScanPath', res.data.fileName);
360
-            row.certificateScanPathUrl = [res.data.url].map((url) => ({ url }));
361
-            return res.data;
362
-          }
387
+          // if (res.code === 200) {
388
+          //   row.certificateScanPath = res.data.fileName;
389
+          //   console.log('处理后的 certificateScanPath:', res.data);
390
+          //   // row.setFieldValue('certificateScanPath', res.data.fileName);
391
+          //   row.certificateScanPathUrl = [res.data.url].map((url) => ({ url }));
392
+          //   return res.data;
393
+          // }
363 394
           // return Promise.reject(res);
364 395
         },
365 396
       };
@@ -375,8 +406,8 @@ export const drawerFormSchema: FormSchemaGetter = () => [
375 406
     componentProps: {
376 407
       // 直接使用具体的选项对象,避免可能的getDictOptions问题
377 408
       options: [
378
-        { label: '启用', value: '1' },
379
-        { label: '禁用', value: '0' },
409
+        { label: '启用', value: 1 },
410
+        { label: '禁用', value: 0 },
380 411
       ],
381 412
       isButton: true,
382 413
     },

+ 223 - 140
apps/web-ele/src/views/oilstation/idphoto/idphoto-drawer.vue

@@ -28,171 +28,254 @@ const DICT_KEYS = {
28 28
   STATUS: 'status',
29 29
 };
30 30
 
31
-const uploadUrlRef = ref<string>('');
31
+// 响应式变量
32
+const isUpdateRef = ref<boolean>(false);
33
+
32 34
 // 获取字典选项函数
33 35
 const getDictOptionsByKey = (key: string) => getDictOptions(key);
34 36
 
37
+// 初始化表单
35 38
 const [Form, formApi] = useVbenForm({
36 39
   showDefaultActions: false,
37 40
   schema: drawerFormSchema(),
38 41
 });
39 42
 
40
-// 获取初始字典数据,确保表单加载时有默认选项
41
-onMounted(() => {
42
-  // 字典数据会在表单schema中动态获取,这里只是为了确保组件挂载时有初始数据
43
-  getDictOptionsByKey(DICT_KEYS.ID_PAPERS_NAME);
44
-  getDictOptionsByKey(DICT_KEYS.ID_PAPERS_ORGANIZATION);
45
-  getDictOptionsByKey(DICT_KEYS.ID_PAPERS_STORAGE);
46
-  getDictOptionsByKey(DICT_KEYS.STATUS);
47
-});
48
-
49
-const isUpdateRef = ref<boolean>(false);
50
-
43
+// 初始化抽屉
51 44
 const [Drawer, drawerApi] = useVbenDrawer({
52 45
   async onOpenChange(isOpen) {
53 46
     if (!isOpen) {
54 47
       return;
55 48
     }
56
-    try {
57
-      drawerApi.drawerLoading(true);
58
-      const { id, isUpdate } = drawerApi.getData();
59
-      isUpdateRef.value = isUpdate;
60
-      if (isUpdate && id) {
61
-        const res = await getIdPhotoDetail(id);
62
-        console.log('获取证照详情数据:', res);
63
-        // 确保从正确的响应结构中获取数据
64
-        const detailData = res?.data || res;
65
-
66
-        uploadUrlRef.value = detailData.certificateScanPath || '';
67
-        // 处理长期有效的布尔值转换并确保字段名映射正确
68
-        const formData = {
69
-          ...detailData,
70
-          isLongTerm:
71
-            detailData.isLongTerm === '1' ||
72
-            detailData.isLongTerm === 1 ||
73
-            detailData.isLongTerm === true,
74
-          // 文件列表格式转换,确保符合Upload组件要求
75
-          certificateScanPath: detailData.certificateScanPath
76
-            ? typeof detailData.certificateScanPath === 'string' &&
77
-              detailData.certificateScanPath.includes(',')
78
-              ? // 如果是逗号分隔的多个URL字符串
79
-                detailData.certificateScanPath
80
-                  .split(',')
81
-                  .map((url: string, index: number) => ({
82
-                    name: url.split('/').pop() || `文件${index + 1}`,
83
-                    url,
84
-                    status: 'success',
85
-                    uid: Date.now() + index,
86
-                  }))
87
-              : // 单个URL字符串
88
-                typeof detailData.certificateScanPath === 'string'
89
-                ? [
90
-                    {
91
-                      name:
92
-                        detailData.certificateScanPath.split('/').pop() ||
93
-                        '未知文件',
94
-                      url: detailData.certificateScanPath,
95
-                      status: 'success',
96
-                      uid: Date.now(),
97
-                    },
98
-                  ]
99
-                : // 已经是数组格式
100
-                  Array.isArray(detailData.certificateScanPath)
101
-                  ? detailData.certificateScanPath.map(
102
-                      (item: any, index: number) => ({
103
-                        name:
104
-                          (item.url || item).split('/').pop() ||
105
-                          `文件${index + 1}`,
106
-                        url: item.url || item,
107
-                        status: 'success',
108
-                        uid: Date.now() + index,
109
-                      }),
110
-                    )
111
-                  : []
112
-            : [],
113
-        };
114
-        // Object.assign(drawerFormRef, formData);
115
-        await formApi.setValues(formData);
116
-      }
117
-    } catch (error) {
118
-      console.error('获取证照详情失败:', error);
119
-    } finally {
120
-      drawerApi.drawerLoading(false);
121
-    }
49
+    await handleDrawerOpen();
122 50
   },
123 51
 
124 52
   async onConfirm() {
125
-    try {
126
-      this.confirmLoading = true;
127
-      const { valid } = await formApi.validate();
128
-      if (!valid) {
129
-        return;
130
-      }
131
-      const data = await formApi.getValues();
132
-      // 处理长期有效的逻辑
133
-      if (data.isLongTerm) {
134
-        data.validDate = null;
135
-      }
136
-      data.isLongTerm = data.isLongTerm ? '1' : '0';
137
-      data.stationId = 1;
138
-      // 确保使用正确的字段名提交数据
139
-      console.log(data.certificateScanPath);
140
-      const submitData = {
141
-        ...data,
142
-        licenseNameCode: data.licenseNameCode || data.certificateName,
143
-        orgTypeCode: data.orgTypeCode || data.organizationType,
144
-        certificateNumber: data.certificateNumber || data.certificateNo,
145
-        storageLocationCode: data.storageLocationCode || data.storageLocation,
146
-        renewalRequirements:
147
-          data.renewalRequirements || data.replacementRequirements,
148
-        // url 数组转换为逗号分隔的字符串
149
-        statusCode: data.statusCode || data.status,
150
-      };
151
-
152
-      console.log('提交数据:', submitData);
153
-      await (isUpdateRef.value
154
-        ? updateIdPhoto(submitData)
155
-        : addIdPhoto(submitData));
156
-      emit('reload');
157
-      drawerApi.close();
158
-    } catch (error) {
159
-      console.error('保存证照信息失败:', error);
160
-    } finally {
161
-      this.confirmLoading = false;
162
-    }
53
+    await handleFormSubmit();
163 54
   },
164 55
 
165 56
   onClosed() {
166 57
     formApi.resetForm();
167 58
   },
168 59
 });
60
+
61
+/**
62
+ * 处理抽屉打开逻辑
63
+ */
64
+async function handleDrawerOpen() {
65
+  try {
66
+    drawerApi.drawerLoading(true);
67
+    const { id, isUpdate } = drawerApi.getData();
68
+    isUpdateRef.value = isUpdate;
69
+    
70
+    // 处理编辑模式的数据回显
71
+    if (isUpdate && id) {
72
+      await loadIdPhotoDetail(id);
73
+    }
74
+  } catch (error) {
75
+    console.error('打开抽屉失败:', error);
76
+  } finally {
77
+    drawerApi.drawerLoading(false);
78
+  }
79
+}
80
+
81
+/**
82
+ * 加载证照详情数据
83
+ * @param id 证照ID
84
+ */
85
+async function loadIdPhotoDetail(id: string | number) {
86
+  try {
87
+    const res = await getIdPhotoDetail(id);
88
+    console.log('获取证照详情数据:', res);
89
+    
90
+    // 确保从正确的响应结构中获取数据
91
+    const detailData = res?.data || res;
92
+    
93
+    // 构建表单数据
94
+    const formData = buildFormData(detailData);
95
+    
96
+    // 设置表单值
97
+    await formApi.setValues(formData);
98
+  } catch (error) {
99
+    console.error('获取证照详情失败:', error);
100
+  }
101
+}
102
+
103
+/**
104
+ * 构建表单数据
105
+ * @param detailData 详情数据
106
+ * @returns 格式化后的表单数据
107
+ */
108
+function buildFormData(detailData: any) {
109
+  // 处理长期有效的布尔值转换
110
+  const isLongTerm = detailData.isLongTerm === '1' || 
111
+                     detailData.isLongTerm === 1 || 
112
+                     detailData.isLongTerm === true;
113
+  
114
+  return {
115
+    ...detailData,
116
+    isLongTerm,
117
+    // 保持 certificateScanPath 为字符串格式,逗号隔开
118
+    certificateScanPath: detailData.certificateScanPath || '',
119
+    // 处理 certificateScanPathUrl 字段,确保为数组格式
120
+    certificateScanPathUrl: formatCertificateScanPathUrl(detailData),
121
+  };
122
+}
123
+
124
+/**
125
+ * 格式化 certificateScanPathUrl 字段
126
+ * @param detailData 详情数据
127
+ * @returns 格式化后的数组
128
+ */
129
+function formatCertificateScanPathUrl(detailData: any) {
130
+  if (!detailData.certificateScanPathUrl) {
131
+    return [];
132
+  }
133
+  
134
+  // 处理数组格式
135
+  if (Array.isArray(detailData.certificateScanPathUrl)) {
136
+    return detailData.certificateScanPathUrl.map((url: string, index: number) => ({
137
+      name: detailData.certificateScanPath?.split(',')[index] || `文件${index + 1}`,
138
+      url,
139
+      status: 'success',
140
+      uid: Date.now() + index,
141
+    }));
142
+  }
143
+  
144
+  // 处理字符串格式
145
+  if (typeof detailData.certificateScanPathUrl === 'string') {
146
+    return [{
147
+      name: detailData.certificateScanPathUrl.split('/').pop() || '未知文件',
148
+      url: detailData.certificateScanPathUrl,
149
+      status: 'success',
150
+      uid: Date.now(),
151
+    }];
152
+  }
153
+  
154
+  return [];
155
+}
156
+
157
+/**
158
+ * 处理表单提交
159
+ */
160
+async function handleFormSubmit() {
161
+  try {
162
+    // 验证表单
163
+    const { valid } = await formApi.validate();
164
+    if (!valid) {
165
+      return;
166
+    }
167
+    
168
+    // 获取表单数据
169
+    const data = await formApi.getValues();
170
+    console.log('表单数据:', data);
171
+    
172
+    // 处理数据
173
+    const processedData = processFormData(data);
174
+    
175
+    // 构建提交数据
176
+    const submitData = buildSubmitData(processedData);
177
+    console.log('提交数据:', submitData);
178
+    
179
+    // 提交请求
180
+    await (isUpdateRef.value ? updateIdPhoto(submitData) : addIdPhoto(submitData));
181
+    
182
+    // 触发重载事件并关闭抽屉
183
+    emit('reload');
184
+    drawerApi.close();
185
+  } catch (error) {
186
+    console.error('保存证照信息失败:', error);
187
+  }
188
+}
189
+
190
+/**
191
+ * 处理表单数据
192
+ * @param data 表单数据
193
+ * @returns 处理后的数据
194
+ */
195
+function processFormData(data: any) {
196
+  // 处理长期有效的逻辑
197
+  if (data.isLongTerm) {
198
+    data.validDate = null;
199
+  }
200
+  
201
+  // 转换长期有效字段格式
202
+  data.isLongTerm = data.isLongTerm ? '1' : '0';
203
+  
204
+  // 设置默认站点ID
205
+  data.stationId = 1;
206
+  
207
+  // 处理证书扫描件路径
208
+  data.certificateScanPath = processCertificateScanPath(data);
209
+  
210
+  return data;
211
+}
212
+
213
+/**
214
+ * 处理证书扫描件路径
215
+ * @param data 表单数据
216
+ * @returns 处理后的路径字符串
217
+ */
218
+function processCertificateScanPath(data: any) {
219
+  // 直接使用 certificateScanPath 字段,上传时已设置为逗号分隔的 fileName 格式
220
+  let certificateScanPath = data.certificateScanPath || '';
221
+  
222
+  // 如果有 certificateScanPathUrl,优先使用其中的 name 构建 certificateScanPath
223
+  if (Array.isArray(data.certificateScanPathUrl) && data.certificateScanPathUrl.length > 0) {
224
+    // 检查是否有上传响应数据
225
+    if (data.certificateScanPathUrl[0].response) {
226
+      certificateScanPath = data.certificateScanPathUrl
227
+        .map((item: any) => item.response.data.fileName)
228
+        .join(',');
229
+    } else if (data.certificateScanPathUrl[0].name) {
230
+      // 检查是否有 name 属性
231
+      certificateScanPath = data.certificateScanPathUrl
232
+        .map((item: any) => item.name)
233
+        .join(',');
234
+    }
235
+  }
236
+  
237
+  return certificateScanPath;
238
+}
239
+
240
+/**
241
+ * 构建提交数据
242
+ * @param data 处理后的数据
243
+ * @returns 提交数据对象
244
+ */
245
+function buildSubmitData(data: any) {
246
+  return {
247
+    // 基础字段
248
+    id: data.id,
249
+    licenseNameCode: data.licenseNameCode || data.certificateName,
250
+    licenseRuleId: data.licenseRuleId || data.licenseRule,
251
+    licenseName: data.licenseName || data.licenseNameCode,
252
+    orgTypeCode: data.orgTypeCode || data.organizationType,
253
+    issuingAuthority: data.issuingAuthority,
254
+    issueDate: data.issueDate,
255
+    certificateNumber: data.certificateNumber || data.certificateNo,
256
+    storageLocationCode: data.storageLocationCode || data.storageLocation,
257
+    renewalRequirements: data.renewalRequirements || data.replacementRequirements,
258
+    statusCode: data.statusCode || data.status,
259
+    validDate: data.validDate,
260
+    isLongTerm: data.isLongTerm,
261
+    stationId: data.stationId,
262
+    // 只传 certificateScanPath,字符串逗号隔开
263
+    certificateScanPath: data.certificateScanPath || '',
264
+  };
265
+}
266
+
267
+// 获取初始字典数据,确保表单加载时有默认选项
268
+onMounted(() => {
269
+  // 字典数据会在表单schema中动态获取,这里只是为了确保组件挂载时有初始数据
270
+  getDictOptionsByKey(DICT_KEYS.ID_PAPERS_NAME);
271
+  getDictOptionsByKey(DICT_KEYS.ID_PAPERS_ORGANIZATION);
272
+  getDictOptionsByKey(DICT_KEYS.ID_PAPERS_STORAGE);
273
+  getDictOptionsByKey(DICT_KEYS.STATUS);
274
+});
169 275
 </script>
170 276
 
171 277
 <template>
172 278
   <Drawer :title="isUpdateRef ? '编辑证照' : '新增证照'">
173
-    <Form>
174
-      <!-- 自定义Upload组件插槽 -->
175
-      <!-- <template #certificateScanPath="scope">
176
-        <ElUpload
177
-          v-model:file-list="scope.modelValue"
178
-          action="#"
179
-          multiple
180
-          accept=".jpg,.jpeg,.png,.pdf"
181
-          list-type="picture-card"
182
-          show-file-list
183
-          :auto-upload="true"
184
-          :drag="false"
185
-          :http-request="handleUpload"
186
-          :on-remove="handleRemove"
187
-          :on-preview="handlePreview"
188
-        >
189
-          <div>
190
-            <ElIcon class="el-upload__icon">
191
-              <Plus size="30" />
192
-            </ElIcon>
193
-          </div>
194
-        </ElUpload>
195
-      </template> -->
196
-    </Form>
279
+    <Form />
197 280
   </Drawer>
198 281
 </template>

+ 3 - 3
apps/web-ele/src/views/system/infoEntry/emergencyInfo/emergencyInfo-data.tsx

@@ -29,7 +29,7 @@ const getAreaList = async () => {
29 29
 // 获取片区名称
30 30
 const getAreaName = (areaId: string | number) => {
31 31
   const area = areaList.find(item => item.id === areaId);
32
-  return area ? area.areaName : areaId;
32
+  return area ? area.stationName : areaId;
33 33
 };
34 34
 
35 35
 // 导出获取片区列表的函数
@@ -49,7 +49,7 @@ export const queryFormSchema: FormSchemaGetter = () => [
49 49
         const data = resp || [];
50 50
         return Array.isArray(data)
51 51
           ? data.map((item: any) => ({
52
-              label: item.areaName,
52
+              label: item.stationName,
53 53
               value: item.id,
54 54
             }))
55 55
           : [];
@@ -150,7 +150,7 @@ export const drawerFormSchema: FormSchemaGetter = () => [
150 150
         const data = resp || [];
151 151
         return Array.isArray(data)
152 152
           ? data.map((item: any) => ({
153
-              label: item.areaName,
153
+              label: item.stationName,
154 154
               value: item.id,
155 155
             }))
156 156
           : [];

+ 197 - 0
apps/web-ele/src/views/workflow/leave/leave-form.vue

@@ -0,0 +1,197 @@
1
+<!--
2
+这个文件用不上  已经更改交互为drawer
3
+-->
4
+
5
+<script setup lang="ts">
6
+import type { StartWorkFlowReqData } from '#/api/workflow/task/model';
7
+
8
+import { onMounted, ref } from 'vue';
9
+import { useRoute, useRouter } from 'vue-router';
10
+
11
+import { useVbenModal } from '@vben/common-ui';
12
+import { useTabs } from '@vben/hooks';
13
+
14
+// import { Card, Spin } from 'ant-design-vue';
15
+import dayjs from 'dayjs';
16
+import { cloneDeep, omit } from 'lodash-es';
17
+
18
+import { useVbenForm } from '#/adapter/form';
19
+import { startWorkFlow } from '#/api/workflow/task';
20
+
21
+import { applyModal } from '../components';
22
+import {
23
+  leaveAdd,
24
+  leaveInfo,
25
+  leaveUpdate,
26
+  submitAndStartWorkflow,
27
+} from './api';
28
+import { formSchema } from './data';
29
+
30
+const route = useRoute();
31
+const id = route.query?.id as string;
32
+
33
+const [BasicForm, formApi] = useVbenForm({
34
+  commonConfig: {
35
+    // 默认占满两列
36
+    formItemClass: 'col-span-2',
37
+    // 默认label宽度 px
38
+    labelWidth: 100,
39
+    // 通用配置项 会影响到所有表单项
40
+    componentProps: {
41
+      class: 'w-full',
42
+    },
43
+  },
44
+  schema: formSchema(),
45
+  showDefaultActions: false,
46
+  wrapperClass: 'grid-cols-2',
47
+});
48
+
49
+const loading = ref(false);
50
+onMounted(async () => {
51
+  // 只读 获取信息赋值
52
+  if (id) {
53
+    loading.value = true;
54
+
55
+    const resp = await leaveInfo(id);
56
+    await formApi.setValues(resp);
57
+    const dateRange = [dayjs(resp.startDate), dayjs(resp.endDate)];
58
+    await formApi.setFieldValue('dateRange', dateRange);
59
+
60
+    loading.value = false;
61
+  }
62
+});
63
+
64
+const router = useRouter();
65
+
66
+/**
67
+ * 获取已经处理好的表单参数
68
+ */
69
+async function getFormData() {
70
+  let data = cloneDeep(await formApi.getValues()) as any;
71
+  data = omit(data, 'flowType', 'type');
72
+  // 处理日期
73
+  data.startDate = dayjs(data.dateRange[0]).format('YYYY-MM-DD HH:mm:ss');
74
+  data.endDate = dayjs(data.dateRange[1]).format('YYYY-MM-DD HH:mm:ss');
75
+  return data;
76
+}
77
+
78
+/**
79
+ * 暂存/提交 提取通用逻辑
80
+ */
81
+async function handleSaveOrUpdate() {
82
+  const data = await getFormData();
83
+  if (id) {
84
+    data.id = id;
85
+    return await leaveUpdate(data);
86
+  } else {
87
+    return await leaveAdd(data);
88
+  }
89
+}
90
+
91
+const [ApplyModal, applyModalApi] = useVbenModal({
92
+  connectedComponent: applyModal,
93
+});
94
+/**
95
+ * 暂存 草稿状态
96
+ */
97
+async function handleTempSave() {
98
+  try {
99
+    await handleSaveOrUpdate();
100
+    router.push('/demo/leave');
101
+  } catch (error) {
102
+    console.error(error);
103
+  }
104
+}
105
+
106
+/**
107
+ * 保存业务 & 发起流程
108
+ */
109
+async function handleStartWorkFlow() {
110
+  loading.value = true;
111
+  try {
112
+    const { valid } = await formApi.validate();
113
+    if (!valid) {
114
+      return;
115
+    }
116
+    // 获取发起类型
117
+    const { type } = await formApi.getValues();
118
+    /**
119
+     * 这里只是demo 实际只会用到一种
120
+     */
121
+    switch (type) {
122
+      // 后端发起流程
123
+      case 'backend': {
124
+        const data = await getFormData();
125
+        await submitAndStartWorkflow(data);
126
+        await handleCompleteOrCancel();
127
+        break;
128
+      }
129
+      // 前端发起流程
130
+      case 'frontend': {
131
+        // 保存业务
132
+        const leaveResp = await handleSaveOrUpdate();
133
+        // 启动流程
134
+        const taskVariables = {
135
+          leaveDays: leaveResp!.leaveDays,
136
+          userList: ['1', '3', '4'],
137
+        };
138
+        const formValues = await formApi.getValues();
139
+        const flowCode = formValues?.flowType ?? 'leave1';
140
+        const startWorkFlowData: StartWorkFlowReqData = {
141
+          businessId: leaveResp!.id,
142
+          flowCode,
143
+          variables: taskVariables,
144
+          flowInstanceBizExtBo: {
145
+            businessTitle: '请假申请 - 自定义标题',
146
+            businessCode: leaveResp!.applyCode,
147
+          },
148
+        };
149
+        const { taskId } = await startWorkFlow(startWorkFlowData);
150
+        // 打开窗口
151
+        applyModalApi.setData({
152
+          taskId,
153
+          taskVariables,
154
+          variables: {},
155
+        });
156
+        applyModalApi.open();
157
+        break;
158
+      }
159
+    }
160
+  } catch (error) {
161
+    console.error(error);
162
+  } finally {
163
+    loading.value = false;
164
+  }
165
+}
166
+
167
+const { closeCurrentTab } = useTabs();
168
+
169
+/**
170
+ * 通用提交/取消回调
171
+ *
172
+ * 提交后点击取消 这时候已经变成草稿状态了
173
+ * 每次点击都会生成新记录 直接跳转回列表
174
+ */
175
+async function handleCompleteOrCancel() {
176
+  formApi.resetForm();
177
+  await closeCurrentTab();
178
+  router.push('/demo/leave');
179
+}
180
+</script>
181
+
182
+<template>
183
+  <Spin :spinning="loading">
184
+    <Card>
185
+      <BasicForm />
186
+      <div class="flex justify-end gap-2">
187
+        <a-button @click="handleTempSave">暂存</a-button>
188
+        <a-button type="primary" @click="handleStartWorkFlow">提交</a-button>
189
+      </div>
190
+      <ApplyModal
191
+        :modal-api="applyModalApi"
192
+        @complete="handleCompleteOrCancel"
193
+        @cancel="handleCompleteOrCancel"
194
+      />
195
+    </Card>
196
+  </Spin>
197
+</template>

+ 42 - 0
apps/web-ele/src/views/workflow/leave/leaveEdit.vue

@@ -0,0 +1,42 @@
1
+<!--
2
+后端版本>=5.4.0  这个从本地路由变为从后台返回
3
+未修改文件名 而是新加了这个文件
4
+-->
5
+<script setup lang="ts">
6
+import { onMounted } from 'vue';
7
+import { useRoute, useRouter } from 'vue-router';
8
+
9
+import { useTabs } from '@vben/hooks';
10
+
11
+// import { Spin } from 'ant-design-vue';
12
+import { useQueryId } from './hook';
13
+
14
+const router = useRouter();
15
+const route = useRoute();
16
+const id = route.query.id as string;
17
+
18
+/**
19
+ * 从我的任务 -> 点击重新编辑会跳转到这里
20
+ * 相当于一个中转 因为我的任务无法获取到列表页的路径(与ele交互不同)
21
+ *
22
+ * 为什么不使用路由的query来实现?
23
+ * 因为刷新后参数不会丢失 且tab存的也是全路径 切换也不会丢失 这不符合预期
24
+ * 可以通过window.history.replaceState来删除query参数 但是tab切换还是会保留
25
+ */
26
+const { closeCurrentTab } = useTabs();
27
+const { businessId } = useQueryId();
28
+onMounted(async () => {
29
+  await closeCurrentTab();
30
+  if (id) {
31
+    // 设置业务ID 存储在内存
32
+    businessId.value = id;
33
+    router.push({ path: '/demo/leave' });
34
+  }
35
+});
36
+</script>
37
+
38
+<template>
39
+  <div>
40
+    <Spin :spinning="true" />
41
+  </div>
42
+</template>

+ 0 - 1
apps/web-ele/src/views/workflow/task/allTaskWaiting.vue

@@ -18,7 +18,6 @@ import {
18 18
   ElPopover,
19 19
   ElTooltip,
20 20
 } from 'element-plus';
21
-
22 21
 import { cloneDeep, debounce, uniqueId } from 'lodash-es';
23 22
 
24 23
 import { categoryTree } from '#/api/workflow/category';