闪电 1 месяц назад
Родитель
Сommit
4fc9066925

+ 1 - 0
.trae/rules/project_rules.md

@@ -274,3 +274,4 @@
274 274
     },
275 275
   ]
276 276
 ```
277
+- 生成过程中不可以执行任何命令,如果需要执行请列出来,由我手动执行或跳过

+ 30 - 0
apps/web-ele/src/api/task/index.ts

@@ -1,13 +1,16 @@
1 1
 import { requestClient } from '#/api/request';
2 2
 
3 3
 enum Api {
4
+  attendanceMeetingHandle = '/formAttendanceMeetings/meetings/handle',
4 5
   emergencyWySubmit = '/formEmergencyDrill/drill/submit',
5 6
   emergencyWySubmitReport = '/formEmergencyDrill/drill/submitReport',
6 7
   groupLogBase = '/formTeamShiftLog/log/handle',
8
+  joinEmergencyHandle = '/formEmergencyDrillParticipation/participation/handle',
7 9
   marketingSurveyHandle = '/formCompetitorMarketingSurvey/survey/handle',
8 10
   meetingBase = '/formMeetingRecords/records/handle',
9 11
   salesSurveyHandle = '/formCompetitorSalesSurvey/survey/handle',
10 12
   scheduleShiftManagementList = '/scheduleShiftManagement/management/list',
13
+  tankWaterHandle = '/formTankWater/water/handle',
11 14
   turnInRateSurveyHandle = '/formTurnInRateSurvey/survey/handle',
12 15
   weeklyEvaluationHandle = '/formEmployeeWeeklyEvaluation/evaluation/handle',
13 16
   // childBase = '/taskCheckSubItem/item',
@@ -92,3 +95,30 @@ export function handleTurnInRateSurvey(params: any) {
92 95
 export function handleMarketingSurvey(params: any) {
93 96
   return requestClient.put(`${Api.marketingSurveyHandle}`, params);
94 97
 }
98
+
99
+/**
100
+ * 参与紧急情况处理
101
+ * @param params 处理参数
102
+ * @returns
103
+ */
104
+export function handleJoinEmergency(params: any) {
105
+  return requestClient.put(`${Api.joinEmergencyHandle}`, params);
106
+}
107
+
108
+/**
109
+ * 参与出勤会议处理
110
+ * @param params 处理参数
111
+ * @returns
112
+ */
113
+export function handleAttendanceMeeting(params: any) {
114
+  return requestClient.put(`${Api.attendanceMeetingHandle}`, params);
115
+}
116
+
117
+/**
118
+ * 量缸试水处理
119
+ * @param params 处理参数
120
+ * @returns
121
+ */
122
+export function handleTankWater(params: any) {
123
+  return requestClient.put(`${Api.tankWaterHandle}`, params);
124
+}

+ 139 - 0
apps/web-ele/src/views/schedule/detail/components/join-emergency.vue

@@ -0,0 +1,139 @@
1
+<script lang="ts" setup>
2
+// @ts-ignore
3
+
4
+import {
5
+  ElCard,
6
+  ElDescriptions,
7
+  ElDescriptionsItem,
8
+  ElImage,
9
+} from 'element-plus';
10
+
11
+// 定义组件的Props接口
12
+interface JoinEmergencyProps {
13
+  taskDetail: any;
14
+}
15
+
16
+// 接收父组件传递的任务详情数据
17
+defineProps<JoinEmergencyProps>();
18
+</script>
19
+
20
+<template>
21
+  <ElCard>
22
+    <template #header>
23
+      <div class="flex items-center gap-4">
24
+        <div style="width: 4px; height: 12px; background-color: #215acd"></div>
25
+        <span
26
+          class="text-lg font-bold text-gray-800"
27
+          style="font-size: 14px; font-weight: 600"
28
+        >
29
+          {{
30
+            taskDetail?.subFormType === 'participate_emergency_wy'
31
+              ? '参与应急演练详情'
32
+              : '参与油站会议详情'
33
+          }}
34
+        </span>
35
+      </div>
36
+    </template>
37
+
38
+    <div class="task-info">
39
+      <ElDescriptions :column="4" class="mb-6">
40
+        <ElDescriptionsItem label="参与时间:">
41
+          {{ taskDetail?.participationTime || '-' }}
42
+        </ElDescriptionsItem>
43
+      </ElDescriptions>
44
+
45
+      <ElDescriptions :column="4" class="mb-6">
46
+        <ElDescriptionsItem label="参与详情:" :span="4">
47
+          {{ taskDetail?.participationRecord || '-' }}
48
+        </ElDescriptionsItem>
49
+      </ElDescriptions>
50
+
51
+      <ElDescriptions :column="4" class="mb-6">
52
+        <ElDescriptionsItem
53
+          v-if="taskDetail?.imagesUrl?.length > 0"
54
+          label="参与现场图片:"
55
+          :span="4"
56
+        >
57
+          <div class="task-images">
58
+            <ElImage
59
+              v-for="(image, index) in taskDetail?.imagesUrl"
60
+              :key="index"
61
+              :src="image"
62
+              :preview-src-list="taskDetail?.imagesUrl"
63
+              :initial-index="+index"
64
+              fit="cover"
65
+              alt="参与照片"
66
+              class="task-image"
67
+            />
68
+          </div>
69
+        </ElDescriptionsItem>
70
+        <ElDescriptionsItem v-else label="参与现场图片:" :span="4">
71
+          -
72
+        </ElDescriptionsItem>
73
+      </ElDescriptions>
74
+    </div>
75
+  </ElCard>
76
+</template>
77
+
78
+<style scoped lang="scss">
79
+.task-info {
80
+  .section-title {
81
+    display: flex;
82
+    align-items: center;
83
+    gap: 8px;
84
+    margin: 20px 0 12px 0;
85
+
86
+    .section-bar {
87
+      width: 4px;
88
+      height: 12px;
89
+      background-color: #215acd;
90
+    }
91
+
92
+    .section-text {
93
+      font-size: 14px;
94
+      font-weight: 600;
95
+      color: var(--text-color-primary);
96
+    }
97
+  }
98
+
99
+  :deep(.el-descriptions) {
100
+    margin-bottom: 0 !important;
101
+  }
102
+
103
+  :deep(.el-descriptions__label) {
104
+    font-size: 14px;
105
+    font-weight: 400;
106
+    color: var(--text-color-secondary);
107
+  }
108
+
109
+  :deep(.el-descriptions__content) {
110
+    font-size: 14px;
111
+    font-weight: 500;
112
+    color: var(--text-color-primary);
113
+  }
114
+
115
+  :deep(.el-descriptions__table) {
116
+    background: transparent !important;
117
+  }
118
+}
119
+
120
+.task-images {
121
+  display: flex;
122
+  gap: 12px;
123
+  margin-top: 4px;
124
+  flex-wrap: wrap;
125
+
126
+  .task-image {
127
+    width: 80px;
128
+    height: 80px;
129
+    cursor: pointer;
130
+    object-fit: cover;
131
+    border-radius: 4px;
132
+    transition: transform 0.2s;
133
+
134
+    &:hover {
135
+      transform: scale(1.05);
136
+    }
137
+  }
138
+}
139
+</style>

+ 147 - 0
apps/web-ele/src/views/schedule/detail/components/tank-water.vue

@@ -0,0 +1,147 @@
1
+<script lang="ts" setup>
2
+// @ts-ignore
3
+
4
+import {
5
+  ElCard,
6
+  ElDescriptions,
7
+  ElDescriptionsItem,
8
+  ElTable,
9
+  ElTableColumn,
10
+} from 'element-plus';
11
+
12
+// 定义组件的Props接口
13
+interface TankWaterProps {
14
+  taskDetail: any;
15
+}
16
+
17
+// 接收父组件传递的任务详情数据
18
+defineProps<TankWaterProps>();
19
+</script>
20
+
21
+<template>
22
+  <ElCard>
23
+    <template #header>
24
+      <div class="flex items-center gap-4">
25
+        <div style="width: 4px; height: 12px; background-color: #215acd"></div>
26
+        <span
27
+          class="text-lg font-bold text-gray-800"
28
+          style="font-size: 14px; font-weight: 600"
29
+        >
30
+          量缸试水详情
31
+        </span>
32
+      </div>
33
+    </template>
34
+
35
+    <div class="task-info">
36
+      <ElDescriptions :column="4" class="mb-6">
37
+        <ElDescriptionsItem label="开始测量时间:">
38
+          {{ taskDetail?.measurementStartTime || '-' }}
39
+        </ElDescriptionsItem>
40
+        <ElDescriptionsItem label="异常记录:">
41
+          {{ taskDetail?.abnormalDescription || '-' }}
42
+        </ElDescriptionsItem>
43
+      </ElDescriptions>
44
+
45
+      <div class="section-title">
46
+        <div class="section-bar"></div>
47
+        <div class="section-text">测量信息</div>
48
+      </div>
49
+
50
+      <ElTable
51
+        :data="taskDetail?.tankWaterDetailList || []"
52
+        border
53
+        style="width: 100%"
54
+        class="mt-4"
55
+      >
56
+        <ElTableColumn prop="tankNumber" label="罐号" align="center" />
57
+        <ElTableColumn prop="oilProduct" label="油品名称" align="center" />
58
+        <ElTableColumn label="液位仪数据" align="center">
59
+          <ElTableColumn
60
+            prop="levelGaugeOilHeightH1"
61
+            label="油高h1(mm)"
62
+            align="center"
63
+          />
64
+          <ElTableColumn
65
+            prop="levelGaugeWaterHeight"
66
+            label="水高(mm)"
67
+            align="center"
68
+          />
69
+        </ElTableColumn>
70
+        <ElTableColumn label="手工量缸数据" align="center">
71
+          <ElTableColumn
72
+            prop="manualTankOilHeightH2"
73
+            label="油高h2(mm)"
74
+            align="center"
75
+          />
76
+          <ElTableColumn
77
+            prop="manualTankWaterHeight"
78
+            label="水高(mm)"
79
+            align="center"
80
+          />
81
+        </ElTableColumn>
82
+        <ElTableColumn
83
+          prop="heightDifference"
84
+          label="高度差(mm)(h2-h1)"
85
+          align="center"
86
+        />
87
+        <ElTableColumn prop="tankTemperature" label="油罐温度" align="center" />
88
+      </ElTable>
89
+    </div>
90
+  </ElCard>
91
+</template>
92
+
93
+<style scoped lang="scss">
94
+.task-info {
95
+  .section-title {
96
+    display: flex;
97
+    align-items: center;
98
+    gap: 8px;
99
+    margin: 20px 0 12px 0;
100
+
101
+    .section-bar {
102
+      width: 4px;
103
+      height: 12px;
104
+      background-color: #215acd;
105
+    }
106
+
107
+    .section-text {
108
+      font-size: 14px;
109
+      font-weight: 600;
110
+      color: var(--text-color-primary);
111
+    }
112
+  }
113
+
114
+  :deep(.el-descriptions) {
115
+    margin-bottom: 0 !important;
116
+  }
117
+
118
+  :deep(.el-descriptions__label) {
119
+    font-size: 14px;
120
+    font-weight: 400;
121
+    color: var(--text-color-secondary);
122
+  }
123
+
124
+  :deep(.el-descriptions__content) {
125
+    font-size: 14px;
126
+    font-weight: 500;
127
+    color: var(--text-color-primary);
128
+  }
129
+
130
+  :deep(.el-descriptions__table) {
131
+    background: transparent !important;
132
+  }
133
+
134
+  :deep(.el-table) {
135
+    margin-top: 12px;
136
+  }
137
+
138
+  :deep(.el-table__header-wrapper) {
139
+    background-color: #f5f7fa;
140
+  }
141
+
142
+  :deep(.el-table th) {
143
+    font-weight: 600;
144
+    color: var(--text-color-primary);
145
+  }
146
+}
147
+</style>

+ 6 - 0
apps/web-ele/src/views/schedule/detail/drawer/index.ts

@@ -4,6 +4,8 @@ export { default as EntranceDrawer } from './entrance/index.vue';
4 4
 
5 5
 export { default as GroupLogDrawer } from './groupLog/index.vue';
6 6
 
7
+export { default as JoinEmergencyDrawer } from './joinEmergency/index.vue';
8
+
7 9
 export { default as MeetingDrawer } from './meeting/index.vue';
8 10
 
9 11
 export { default as OperatingPlanDrawer } from './operatingPlan/index.vue';
@@ -12,6 +14,10 @@ export { default as ManagementPlanDrawer } from './plan/index.vue';
12 14
 
13 15
 export { default as SalesSurveyDrawer } from './salesSurvey/index.vue';
14 16
 
17
+export { default as TankWaterDrawer } from './tankWater/index.vue';
18
+
15 19
 export { default as UploadDrawer } from './upload/index.vue';
16 20
 
21
+// export { default as WeeklyDrawer } from './weekly/index.vue';
22
+
17 23
 export { default as WeeklyEvaluationDrawer } from './weeklyEvaluation/index.vue';

+ 72 - 0
apps/web-ele/src/views/schedule/detail/drawer/joinEmergency/config-data.tsx

@@ -0,0 +1,72 @@
1
+// @ts-ignore: 忽略
2
+import type { FormSchemaGetter } from '#/adapter/form';
3
+
4
+// @ts-ignore: 忽略
5
+import { getMultipleImageUploadConfig } from '#/components/upload';
6
+
7
+// 抽屉表单配置
8
+export const drawerFormSchema: any | FormSchemaGetter = () => [
9
+  {
10
+    component: 'DatePicker',
11
+    componentProps: {
12
+      placeholder: '请选择参与时间',
13
+      type: 'datetime',
14
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
15
+    },
16
+    fieldName: 'participationTime',
17
+    label: '参与时间',
18
+    rules: 'required',
19
+  },
20
+  {
21
+    component: 'Input',
22
+    componentProps: {
23
+      placeholder: '请输入参与记录',
24
+      type: 'textarea',
25
+      rows: 4,
26
+    },
27
+    fieldName: 'participationRecord',
28
+    label: '参与记录',
29
+    rules: 'required',
30
+  },
31
+  {
32
+    component: 'Input',
33
+    fieldName: 'images',
34
+    label: '图片',
35
+    componentProps: {
36
+      maxlength: 30,
37
+    },
38
+    dependencies: {
39
+      show: () => false,
40
+      triggerFields: [''],
41
+    },
42
+  },
43
+  {
44
+    component: 'Upload',
45
+    fieldName: 'imagesPaths',
46
+    label: '图片',
47
+    componentProps: (row: any) => {
48
+      return {
49
+        ...getMultipleImageUploadConfig(5),
50
+        multiple: true,
51
+        onSuccess: (res: any, uploadFile: any, uploadFiles: any) => {
52
+          if (res.code === 200) {
53
+            const paths: string[] = [];
54
+            uploadFiles.forEach((item: any) => {
55
+              if (item.response?.code === 200) {
56
+                paths.push(item.response.data.fileName);
57
+              }
58
+            });
59
+            row.images = paths.join(',');
60
+
61
+            return res.data;
62
+          }
63
+        },
64
+      };
65
+    },
66
+    renderComponentContent: () => {
67
+      return {
68
+        default: () => '点击上传',
69
+      };
70
+    },
71
+  },
72
+];

+ 112 - 0
apps/web-ele/src/views/schedule/detail/drawer/joinEmergency/index.vue

@@ -0,0 +1,112 @@
1
+<script setup lang="ts">
2
+// @ts-ignore
3
+
4
+import { ref } from 'vue';
5
+
6
+// @ts-ignore
7
+import { useVbenDrawer, useVbenForm } from '@vben/common-ui';
8
+
9
+// @ts-ignore
10
+// 这里需要替换为实际的API,如果没有可以先注释
11
+import { handleAttendanceMeeting, handleJoinEmergency } from '#/api/task';
12
+
13
+// @ts-ignore
14
+import { drawerFormSchema } from './config-data';
15
+
16
+const emit = defineEmits<{ reload: [] }>();
17
+
18
+// 初始化表单配置
19
+const [Form, formApi] = useVbenForm({
20
+  showDefaultActions: false,
21
+  schema: drawerFormSchema(),
22
+});
23
+
24
+// 初始化任务参数
25
+const taskParams = ref({
26
+  taskId: '',
27
+  taskName: '',
28
+  taskList: '',
29
+  subFormType: '',
30
+});
31
+
32
+// 初始化抽屉组件
33
+const [Drawer, drawerApi] = useVbenDrawer({
34
+  async onOpenChange(isOpen: boolean) {
35
+    if (!isOpen) {
36
+      return;
37
+    }
38
+    try {
39
+      drawerApi.drawerLoading(true);
40
+      const { taskId, taskName, taskList, subFormType } = drawerApi.getData();
41
+      taskParams.value.taskId = taskId;
42
+      taskParams.value.taskName = taskName;
43
+      taskParams.value.taskList = taskList;
44
+      taskParams.value.subFormType = subFormType;
45
+
46
+      // 如果有任务数据,填充表单
47
+      if (taskList && taskList.length > 0) {
48
+        formApi.setValues(taskList[0]);
49
+      } else {
50
+        formApi.resetForm();
51
+      }
52
+    } catch (error) {
53
+      console.error(error);
54
+    } finally {
55
+      drawerApi.drawerLoading(false);
56
+    }
57
+  },
58
+  onClosed() {
59
+    formApi.resetForm();
60
+  },
61
+  async onConfirm() {
62
+    try {
63
+      this.confirmLoading = true;
64
+
65
+      // 验证表单
66
+      const { valid } = await formApi.validate();
67
+      if (!valid) {
68
+        return;
69
+      }
70
+
71
+      // 获取表单数据
72
+      const values = await formApi.getValues();
73
+
74
+      // 构建提交数据
75
+      const params = {
76
+        id: drawerApi.getData().taskId,
77
+        ...values,
78
+      };
79
+
80
+      // 调用API提交数据
81
+      if (taskParams.value.subFormType === 'participate_emergency_wy') {
82
+        await handleJoinEmergency(params);
83
+      } else if (
84
+        taskParams.value.subFormType === 'participate_oil_station_meeting'
85
+      ) {
86
+        await handleAttendanceMeeting(params);
87
+      }
88
+
89
+      // 触发刷新事件
90
+      emit('reload');
91
+      // 关闭抽屉
92
+      drawerApi.close();
93
+    } catch (error) {
94
+      console.error(error);
95
+    } finally {
96
+      this.confirmLoading = false;
97
+    }
98
+  },
99
+});
100
+</script>
101
+
102
+<template>
103
+  <Drawer :title="taskParams.taskName">
104
+    <Form />
105
+  </Drawer>
106
+</template>
107
+
108
+<style scoped lang="scss">
109
+:deep(.el-input-number) {
110
+  width: 100%;
111
+}
112
+</style>

+ 200 - 0
apps/web-ele/src/views/schedule/detail/drawer/operatingPlan/config-data.tsx

@@ -198,5 +198,205 @@ export const defaultExternalFactors = [
198 198
   { item: '其它', example: '', threat: '', opportunity: '' },
199 199
 ];
200 200
 
201
+// 业绩提升计划表格列配置
202
+export const performancePlanColumns: VxeGridProps['columns'] = [
203
+  {
204
+    field: 'actionPlan',
205
+    title: '行动计划',
206
+    width: 200,
207
+    editRender: { name: 'textarea' },
208
+  },
209
+  {
210
+    field: 'executor',
211
+    title: '执行人',
212
+    width: 100,
213
+    editRender: { name: 'input' },
214
+  },
215
+  {
216
+    field: 'measurementStandard',
217
+    title: '衡量标准',
218
+    width: 200,
219
+    editRender: { name: 'input' },
220
+  },
221
+  {
222
+    field: 'requiredResources',
223
+    title: '需要的资源',
224
+    width: 200,
225
+    editRender: { name: 'input' },
226
+  },
227
+  {
228
+    field: 'startDate',
229
+    title: '开始时间',
230
+    width: 150,
231
+    editRender: { name: 'inpt', props: { type: 'date' } },
232
+  },
233
+  {
234
+    field: 'endDate',
235
+    title: '结束时间',
236
+    width: 150,
237
+    editRender: { name: 'inpt', props: { type: 'date' } },
238
+    slots: {
239
+      // default: ,
240
+    },
241
+  },
242
+];
243
+
244
+// 业绩提升计划默认数据
245
+export const defaultPerformancePlanData = [
246
+  {
247
+    actionPlan: '',
248
+    executor: '',
249
+    measurementStandard: '',
250
+    requiredResources: '',
251
+    startDate: '',
252
+    endDate: '',
253
+  },
254
+];
255
+
256
+// 油品销量提升表单配置
257
+export const oilSalesPlanSchema = () => [
258
+  {
259
+    component: 'SectionTitle',
260
+    fieldName: '_section_title',
261
+    hideLabel: true,
262
+    componentProps: {
263
+      title: '油品销量提升',
264
+    },
265
+  },
266
+  {
267
+    component: 'Input',
268
+    componentProps: {
269
+      placeholder: '请输入可能的障碍',
270
+      type: 'textarea',
271
+      rows: 3,
272
+    },
273
+    fieldName: 'oilPossibleObstacle',
274
+    label: '可能的障碍',
275
+  },
276
+  {
277
+    component: 'Input',
278
+    componentProps: {
279
+      placeholder: '请输入何时或如何',
280
+      type: 'textarea',
281
+      rows: 3,
282
+    },
283
+    fieldName: 'oilActionPlan',
284
+    label: '何时或如何',
285
+  },
286
+  {
287
+    component: 'Input',
288
+    componentProps: {
289
+      placeholder: '请输入应变计划',
290
+      type: 'textarea',
291
+      rows: 3,
292
+    },
293
+    fieldName: 'oilContingencyPlan',
294
+    label: '应变计划',
295
+  },
296
+  {
297
+    component: 'Input',
298
+    componentProps: {
299
+      placeholder: '请输入执行人',
300
+    },
301
+    fieldName: 'oilExecutor',
302
+    label: '执行人',
303
+  },
304
+  {
305
+    component: 'Input',
306
+    componentProps: {
307
+      placeholder: '请输入衡量的标准',
308
+      type: 'textarea',
309
+      rows: 2,
310
+    },
311
+    fieldName: 'oilMeasurementStandard',
312
+    label: '衡量的标准',
313
+  },
314
+  {
315
+    fieldName: 'oilPerformancePlanTable',
316
+    label: '油品销量提升何时或如何表',
317
+    hideLabel: true,
318
+    renderComponentContent: () => {
319
+      return {
320
+        default: () => [],
321
+      };
322
+    },
323
+  },
324
+];
325
+
326
+// 非油品销量提升表单配置
327
+export const nonOilSalesPlanSchema = () => [
328
+  {
329
+    component: 'SectionTitle',
330
+    fieldName: '_section_title',
331
+    hideLabel: true,
332
+    componentProps: {
333
+      title: '非油品销量提升',
334
+    },
335
+  },
336
+  {
337
+    component: 'Input',
338
+    componentProps: {
339
+      placeholder: '请输入可能的障碍',
340
+      type: 'textarea',
341
+      rows: 3,
342
+    },
343
+    fieldName: 'nonOilPossibleObstacle',
344
+    label: '可能的障碍',
345
+  },
346
+  {
347
+    component: 'Input',
348
+    componentProps: {
349
+      placeholder: '请输入何时或如何',
350
+      type: 'textarea',
351
+      rows: 3,
352
+    },
353
+    fieldName: 'nonOilActionPlan',
354
+    label: '何时或如何',
355
+  },
356
+  {
357
+    component: 'Input',
358
+    componentProps: {
359
+      placeholder: '请输入应变计划',
360
+      type: 'textarea',
361
+      rows: 3,
362
+    },
363
+    fieldName: 'nonOilContingencyPlan',
364
+    label: '应变计划',
365
+  },
366
+  {
367
+    component: 'Input',
368
+    componentProps: {
369
+      placeholder: '请输入执行人',
370
+    },
371
+    fieldName: 'nonOilExecutor',
372
+    label: '执行人',
373
+  },
374
+  {
375
+    component: 'Input',
376
+    componentProps: {
377
+      placeholder: '请输入衡量的标准',
378
+      type: 'textarea',
379
+      rows: 2,
380
+    },
381
+    fieldName: 'nonOilMeasurementStandard',
382
+    label: '衡量的标准',
383
+  },
384
+  {
385
+    fieldName: 'nonOilPerformancePlanTable',
386
+    label: '非油品销量提升何时或如何表',
387
+    hideLabel: true,
388
+    renderComponentContent: () => {
389
+      return {
390
+        default: () => [],
391
+      };
392
+    },
393
+  },
394
+];
395
+
396
+// 业绩提升计划表单配置
397
+export const performancePlanSchema = () => {
398
+  return [...oilSalesPlanSchema(), ...nonOilSalesPlanSchema()];
399
+};
400
+
201 401
 // 默认表格列配置(保留兼容)
202 402
 export const defautTableColumns: VxeGridProps['columns'] = [];

+ 137 - 11
apps/web-ele/src/views/schedule/detail/drawer/operatingPlan/index.vue

@@ -15,9 +15,13 @@ import { useVbenVxeGrid } from '#/adapter/vxe-table';
15 15
 import {
16 16
   defaultExternalFactors,
17 17
   defaultInternalFactors,
18
+  defaultPerformancePlanData,
18 19
   drawerFormSchema,
19 20
   externalFactorsColumns,
20 21
   internalFactorsColumns,
22
+  nonOilSalesPlanSchema,
23
+  oilSalesPlanSchema,
24
+  performancePlanColumns,
21 25
   // @ts-ignore: 忽略
22 26
 } from './config-data';
23 27
 
@@ -66,9 +70,13 @@ const [Drawer, drawerApi] = useVbenDrawer({
66 70
   },
67 71
   onClosed() {
68 72
     formApi.resetForm();
73
+    oilSalesPlanFormApi.resetForm();
74
+    nonOilSalesPlanFormApi.resetForm();
69 75
     // 重置表格数据
70 76
     internalFactorsData.value = [...defaultInternalFactors];
71 77
     externalFactorsData.value = [...defaultExternalFactors];
78
+    oilPerformancePlanData.value = [...defaultPerformancePlanData];
79
+    nonOilPerformancePlanData.value = [...defaultPerformancePlanData];
72 80
   },
73 81
   async onConfirm() {
74 82
     try {
@@ -167,6 +175,90 @@ const [ExternalFactorsTable, externalFactorsApi] = useVbenVxeGrid({
167 175
   gridOptions: externalFactorsGridOptions,
168 176
 });
169 177
 
178
+// 初始化油品销量提升计划表单
179
+const [OilSalesPlanForm, oilSalesPlanFormApi] = useVbenForm({
180
+  showDefaultActions: false,
181
+  schema: oilSalesPlanSchema(),
182
+});
183
+
184
+// 初始化非油品销量提升计划表单
185
+const [NonOilSalesPlanForm, nonOilSalesPlanFormApi] = useVbenForm({
186
+  showDefaultActions: false,
187
+  schema: nonOilSalesPlanSchema(),
188
+});
189
+
190
+// 初始化油品销量提升表格数据
191
+const oilPerformancePlanData = ref(defaultPerformancePlanData);
192
+// 初始化非油品销量提升表格数据
193
+const nonOilPerformancePlanData = ref(defaultPerformancePlanData);
194
+
195
+// 初始化油品销量提升表格配置
196
+const oilPerformancePlanGridOptions: VxeGridProps = {
197
+  size: 'medium',
198
+  toolbarConfig: {
199
+    custom: false,
200
+    refresh: false,
201
+    zoom: false,
202
+  },
203
+  pagerConfig: {
204
+    enabled: false,
205
+  },
206
+  proxyConfig: {
207
+    ajax: {
208
+      query: async () => {
209
+        return {
210
+          items: oilPerformancePlanData.value,
211
+        };
212
+      },
213
+    },
214
+  },
215
+  columns: performancePlanColumns,
216
+  editConfig: {
217
+    mode: 'cell',
218
+    trigger: 'click',
219
+  },
220
+};
221
+
222
+// 初始化非油品销量提升表格配置
223
+const nonOilPerformancePlanGridOptions: VxeGridProps = {
224
+  size: 'medium',
225
+  toolbarConfig: {
226
+    custom: false,
227
+    refresh: false,
228
+    zoom: false,
229
+  },
230
+  pagerConfig: {
231
+    enabled: false,
232
+  },
233
+  proxyConfig: {
234
+    ajax: {
235
+      query: async () => {
236
+        return {
237
+          items: nonOilPerformancePlanData.value,
238
+        };
239
+      },
240
+    },
241
+  },
242
+  columns: performancePlanColumns,
243
+  editConfig: {
244
+    mode: 'cell',
245
+    trigger: 'click',
246
+  },
247
+};
248
+
249
+// 初始化油品销量提升表格组件
250
+const [OilPerformancePlanTable, oilPerformancePlanApi] = useVbenVxeGrid({
251
+  gridOptions: oilPerformancePlanGridOptions,
252
+});
253
+
254
+// 初始化非油品销量提升表格组件
255
+const [NonOilPerformancePlanTable, nonOilPerformancePlanApi] = useVbenVxeGrid({
256
+  gridOptions: nonOilPerformancePlanGridOptions,
257
+});
258
+
259
+// 初始化激活标签页
260
+const activeTab = ref('swot');
261
+
170 262
 // 确认事件
171 263
 const confirmEvent = (row: any) => {
172 264
   // 处理确认事件
@@ -175,17 +267,51 @@ const confirmEvent = (row: any) => {
175 267
 
176 268
 <template>
177 269
   <Drawer :title="taskParams.taskName">
178
-    <Form>
179
-      <!-- 内在因素评估表格插槽 -->
180
-      <template #internalFactorsTable>
181
-        <InternalFactorsTable table-title="" class="w-full" />
182
-      </template>
183
-
184
-      <!-- 外在因素评估表格插槽 -->
185
-      <template #externalFactorsTable>
186
-        <ExternalFactorsTable table-title="" class="w-full" />
187
-      </template>
188
-    </Form>
270
+    <el-tabs v-model="activeTab" class="w-full">
271
+      <!-- SWOT分析标签页 -->
272
+      <el-tab-pane label="SWOT分析" name="swot">
273
+        <Form>
274
+          <!-- 内在因素评估表格插槽 -->
275
+          <template #internalFactorsTable>
276
+            <InternalFactorsTable table-title="" class="w-full" />
277
+          </template>
278
+
279
+          <!-- 外在因素评估表格插槽 -->
280
+          <template #externalFactorsTable>
281
+            <ExternalFactorsTable table-title="" class="w-full" />
282
+          </template>
283
+        </Form>
284
+      </el-tab-pane>
285
+
286
+      <!-- 业绩提升计划标签页 -->
287
+      <el-tab-pane label="业绩提升计划" name="performancePlan">
288
+        <!-- 油品销量提升计划 -->
289
+        <OilSalesPlanForm>
290
+          <!-- 油品销量提升行动计划表插槽 -->
291
+          <template #oilPerformancePlanTable>
292
+            <OilPerformancePlanTable table-title="" class="w-full" />
293
+          </template>
294
+        </OilSalesPlanForm>
295
+
296
+        <!-- 非油品销量提升计划 -->
297
+        <NonOilSalesPlanForm>
298
+          <!-- 非油品销量提升行动计划表插槽 -->
299
+          <template #nonOilPerformancePlanTable>
300
+            <NonOilPerformancePlanTable table-title="" class="w-full" />
301
+          </template>
302
+        </NonOilSalesPlanForm>
303
+      </el-tab-pane>
304
+
305
+      <!-- 上次SWOT分析标签页 -->
306
+      <el-tab-pane label="上次SWOT分析" name="lastSwot">
307
+        <!-- 上次SWOT分析内容 -->
308
+      </el-tab-pane>
309
+
310
+      <!-- 上次业绩提升计划标签页 -->
311
+      <el-tab-pane label="上次业绩提升计划" name="lastPerformancePlan">
312
+        <!-- 上次业绩提升计划内容 -->
313
+      </el-tab-pane>
314
+    </el-tabs>
189 315
   </Drawer>
190 316
 </template>
191 317
 

+ 119 - 0
apps/web-ele/src/views/schedule/detail/drawer/tankWater/config-data.ts

@@ -0,0 +1,119 @@
1
+// @ts-ignore: 忽略
2
+import type { FormSchemaGetter } from '#/adapter/form';
3
+// @ts-ignore: 忽略
4
+import type { VxeGridProps } from '#/adapter/vxe-table';
5
+
6
+/**
7
+ * 量缸试水抽屉表单配置
8
+ */
9
+export const drawerFormSchema: any | FormSchemaGetter = () => [
10
+  {
11
+    component: 'DatePicker',
12
+    fieldName: 'measurementStartTime',
13
+    label: '开始测量时间',
14
+    componentProps: {
15
+      placeholder: '请选择开始测量时间',
16
+      type: 'datetime',
17
+      format: 'YYYY-MM-DD HH:mm:ss',
18
+    },
19
+    rules: 'required',
20
+  },
21
+  {
22
+    component: 'Input',
23
+    fieldName: 'abnormalDescription',
24
+    label: '异常记录',
25
+    componentProps: {
26
+      placeholder: '请输入异常记录',
27
+      type: 'textarea',
28
+      rows: 4,
29
+    },
30
+  },
31
+  {
32
+    fieldName: 'tankWaterDetailList',
33
+    label: '测量信息',
34
+    hideLabel: true,
35
+    renderComponentContent: () => {
36
+      return {
37
+        default: () => [],
38
+      };
39
+    },
40
+  },
41
+];
42
+
43
+/**
44
+ * 默认表格列配置
45
+ */
46
+export const defautTableColumns: VxeGridProps['columns'] = [
47
+  {
48
+    field: 'tankNumber',
49
+    title: '罐号',
50
+    width: 100,
51
+    fixed: 'left',
52
+    editRender: { name: 'input' },
53
+  },
54
+  {
55
+    field: 'oilProduct',
56
+    title: '油品名称',
57
+    width: 120,
58
+    editRender: { name: 'input' },
59
+  },
60
+  {
61
+    field: 'levelGauge',
62
+    title: '液位仪',
63
+    width: 200,
64
+    children: [
65
+      {
66
+        field: 'levelGaugeOilHeightH1',
67
+        title: '油高h1(mm)',
68
+        width: 150,
69
+        editRender: {
70
+          name: 'input',
71
+        },
72
+        // slots: { default: 'levelGaugeOilHeightH1' },
73
+      },
74
+      {
75
+        field: 'levelGaugeWaterHeight',
76
+        title: '水高(mm)',
77
+        width: 150,
78
+        editRender: { name: 'input' },
79
+      },
80
+    ],
81
+  },
82
+  {
83
+    field: 'manualTank',
84
+    title: '手工量缸',
85
+    width: 250,
86
+    children: [
87
+      {
88
+        field: 'manualTankOilHeightH2',
89
+        title: '油高h2(mm)',
90
+        width: 150,
91
+        editRender: { name: 'input' },
92
+      },
93
+      {
94
+        field: 'manualTankWaterHeight',
95
+        title: '水高(mm)',
96
+        width: 150,
97
+        editRender: { name: 'input' },
98
+      },
99
+    ],
100
+  },
101
+  {
102
+    field: 'heightDifference',
103
+    title: '高度差(mm)(h2-h1)',
104
+    width: 250,
105
+  },
106
+  {
107
+    field: 'tankTemperature',
108
+    title: '油罐温度',
109
+    width: 100,
110
+    editRender: { name: 'input' },
111
+  },
112
+  {
113
+    field: 'action',
114
+    title: '操作',
115
+    width: 100,
116
+    fixed: 'right',
117
+    slots: { default: 'action' },
118
+  },
119
+];

+ 172 - 0
apps/web-ele/src/views/schedule/detail/drawer/tankWater/index.vue

@@ -0,0 +1,172 @@
1
+<script setup lang="ts">
2
+// @ts-ignore: 忽略
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { ref } from 'vue';
6
+
7
+// @ts-ignore: 忽略
8
+import { useVbenDrawer, useVbenForm } from '@vben/common-ui';
9
+
10
+// @ts-ignore: 忽略
11
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
12
+// @ts-ignore: 忽略
13
+// 这里需要替换为实际的API,如果没有可以先注释
14
+import { handleTankWater } from '#/api/task';
15
+
16
+// @ts-ignore: 忽略
17
+import { defautTableColumns, drawerFormSchema } from './config-data';
18
+
19
+const emit = defineEmits<{ reload: [] }>();
20
+
21
+// 初始化表单配置
22
+const [Form, formApi] = useVbenForm({
23
+  showDefaultActions: false,
24
+  schema: drawerFormSchema(),
25
+});
26
+
27
+// 初始化任务参数
28
+const taskParams: any = ref({
29
+  taskId: '',
30
+  taskName: '',
31
+  taskList: null,
32
+  subFormType: '',
33
+});
34
+
35
+// 初始化抽屉组件
36
+const [Drawer, drawerApi] = useVbenDrawer({
37
+  async onOpenChange(isOpen: boolean) {
38
+    if (!isOpen) {
39
+      return;
40
+    }
41
+    try {
42
+      drawerApi.drawerLoading(true);
43
+      const { taskId, taskName, taskList, subFormType } = drawerApi.getData();
44
+      taskParams.value.taskId = taskId;
45
+      taskParams.value.taskName = taskName;
46
+      taskParams.value.taskList = taskList;
47
+      taskParams.value.subFormType = subFormType;
48
+
49
+      // 如果有任务数据,填充表单
50
+      if (taskList && taskList.length > 0) {
51
+        formApi.setValues(taskList[0]);
52
+      } else {
53
+        formApi.resetForm();
54
+      }
55
+    } catch (error) {
56
+      console.error(error);
57
+    } finally {
58
+      drawerApi.drawerLoading(false);
59
+    }
60
+  },
61
+  onClosed() {
62
+    formApi.resetForm();
63
+  },
64
+  async onConfirm() {
65
+    try {
66
+      this.confirmLoading = true;
67
+
68
+      // 验证表单
69
+      const { valid } = await formApi.validate();
70
+      if (!valid) {
71
+        return;
72
+      }
73
+
74
+      // 获取表单数据
75
+      const values = await formApi.getValues();
76
+
77
+      // 获取表格数据
78
+      const list = basicTableApi.grid.getData();
79
+
80
+      // 计算高度差
81
+      if (list && list.length > 0) {
82
+        list.forEach((item: any) => {
83
+          item.heightDifference =
84
+            item.manualTankOilHeightH2 - item.levelGaugeOilHeightH1;
85
+        });
86
+      }
87
+
88
+      // 构建提交数据
89
+      const params = {
90
+        id: drawerApi.getData().taskId,
91
+        ...values,
92
+        tankWaterDetailList: list,
93
+      };
94
+
95
+      // 调用API提交数据
96
+      await handleTankWater(params);
97
+
98
+      // 触发刷新事件
99
+      emit('reload');
100
+      // 关闭抽屉
101
+      drawerApi.close();
102
+    } catch (error) {
103
+      console.error(error);
104
+    } finally {
105
+      this.confirmLoading = false;
106
+    }
107
+  },
108
+});
109
+
110
+// 初始化表格配置
111
+const gridOptions: VxeGridProps = {
112
+  size: 'medium',
113
+  toolbarConfig: {
114
+    custom: false,
115
+    refresh: false,
116
+    zoom: false,
117
+  },
118
+  pagerConfig: {
119
+    enabled: false,
120
+  },
121
+  proxyConfig: {
122
+    ajax: {
123
+      query: async () => {
124
+        // 这里可以调用API获取表格数据
125
+        return {
126
+          items: taskParams.value.taskList?.[0]?.formTankWaterRecords || [], // 初始数据
127
+        };
128
+      },
129
+    },
130
+  },
131
+  columns: defautTableColumns,
132
+  editConfig: {
133
+    mode: 'cell',
134
+    trigger: 'click',
135
+  },
136
+};
137
+
138
+// 初始化表格组件
139
+const [BasicTable, basicTableApi] = useVbenVxeGrid({
140
+  gridOptions,
141
+});
142
+</script>
143
+
144
+<template>
145
+  <Drawer :title="taskParams.taskName">
146
+    <Form>
147
+      <!-- 测量信息表格插槽 -->
148
+      <template #tankWaterDetailList>
149
+        <BasicTable table-title="" class="w-full">
150
+          <template #bottom>
151
+            <ElButton class="mt-2 w-full">
152
+              + 新增行(无法读取到油站管号和油品时使用)
153
+            </ElButton>
154
+          </template>
155
+        </BasicTable>
156
+      </template>
157
+      <template #action="scope">
158
+        <ElButton type="primary"> 删除 </ElButton>
159
+      </template>
160
+    </Form>
161
+  </Drawer>
162
+</template>
163
+
164
+<style scoped lang="scss">
165
+:deep(.el-input-number) {
166
+  width: 100%;
167
+}
168
+
169
+:deep(.el-form-item__label) {
170
+  font-weight: 500;
171
+}
172
+</style>

+ 39 - 52
apps/web-ele/src/views/schedule/detail/index.vue

@@ -53,12 +53,16 @@ import EntranceComponent from './components/entrance.vue';
53 53
 // @ts-ignore
54 54
 import GroupLogComponent from './components/group-log.vue';
55 55
 // @ts-ignore
56
+import JoinEmergencyComponent from './components/join-emergency.vue';
57
+// @ts-ignore
56 58
 import MeetingComponent from './components/meeting.vue';
57 59
 // @ts-ignore
58 60
 import ManagementPlanComponent from './components/plan.vue';
59 61
 // @ts-ignore
60 62
 import SalesSurveyComponent from './components/sales-survey.vue';
61 63
 // @ts-ignore
64
+import TankWaterComponent from './components/tank-water.vue';
65
+// @ts-ignore
62 66
 import WeeklyEvaluationComponent from './components/weekly-evaluation.vue';
63 67
 // @ts-ignore
64 68
 import WeeklyComponent from './components/weekly.vue';
@@ -68,10 +72,12 @@ import {
68 72
   EmergencyWyDrawer,
69 73
   EntranceDrawer,
70 74
   GroupLogDrawer,
75
+  JoinEmergencyDrawer,
71 76
   ManagementPlanDrawer,
72 77
   MeetingDrawer,
73 78
   OperatingPlanDrawer,
74 79
   SalesSurveyDrawer,
80
+  TankWaterDrawer,
75 81
   UploadDrawer,
76 82
   WeeklyEvaluationDrawer,
77 83
 } from './drawer';
@@ -315,6 +321,15 @@ const DynamicDrawerComponent = defineComponent({
315 321
             Component = OperatingPlanDrawer;
316 322
             break;
317 323
           }
324
+          case 'participate_emergency_wy':
325
+          case 'participate_oil_station_meeting': {
326
+            Component = JoinEmergencyDrawer;
327
+            break;
328
+          }
329
+          case 'tank_water': {
330
+            Component = TankWaterDrawer;
331
+            break;
332
+          }
318 333
           default: {
319 334
             // ElMessage.error('当前任务无法处理');
320 335
             Component = null;
@@ -373,6 +388,7 @@ const dealEvent = async () => {
373 388
         taskName: taskInfo.value.taskName,
374 389
         taskList: taskInfo.value.taskList || [],
375 390
         remark: taskResult.value.content,
391
+        subFormType: taskInfo.value.subFormType,
376 392
         attachmentUrl: taskResult.value.images,
377 393
       };
378 394
 
@@ -759,58 +775,29 @@ onMounted(async () => {
759 775
           "
760 776
         />
761 777
 
762
-        <!-- 处理信息组件 -->
763
-        <!-- <ElCard v-if="taskInfo.status === 3">
764
-          <template #header>
765
-            <div class="flex items-center gap-4">
766
-              <div
767
-                style="width: 4px; height: 12px; background-color: #215acd"
768
-              ></div>
769
-              <span
770
-                class="text-lg font-bold text-gray-800"
771
-                style="font-size: 14px; font-weight: 600"
772
-              >
773
-                处理信息
774
-              </span>
775
-            </div>
776
-          </template>
777
-          <ElDescriptions class="task-info" :column="4">
778
-            <ElDescriptionsItem
779
-              v-if="taskResult.handleContent || taskInfo.cancelReason"
780
-              label="处理情况:"
781
-              :span="4"
782
-            >
783
-              {{ taskResult.handleContent || taskInfo.cancelReason || '' }}
784
-            </ElDescriptionsItem>
785
-            <ElDescriptionsItem label="处理时间:" :span="4">
786
-              {{ taskInfo.completeTime || taskInfo.cancelTime || '-' }}
787
-            </ElDescriptionsItem>
788
-            <ElDescriptionsItem
789
-              v-if="taskResult.files && taskResult.files.length > 0"
790
-              label="处理附件:"
791
-              :span="4"
792
-            >
793
-              <div class="attachment-list">
794
-                <div
795
-                  v-for="(file, index) in taskResult.files"
796
-                  :key="index"
797
-                  class="attachment-item"
798
-                  @click="
799
-                    () =>
800
-                      downloadFile(
801
-                        file,
802
-                        taskResult.fileNames[index] || `附件${+index + 1}`,
803
-                      )
804
-                  "
805
-                >
806
-                  <span class="attachment-name">{{
807
-                    taskResult.fileNames[index] || `附件${+index + 1}`
808
-                  }}</span>
809
-                </div>
810
-              </div>
811
-            </ElDescriptionsItem>
812
-          </ElDescriptions>
813
-        </ElCard> -->
778
+        <!-- 参与紧急情况组件 -->
779
+        <JoinEmergencyComponent
780
+          :task-detail="{
781
+            ...taskInfo.taskList[0],
782
+            subFormType: taskInfo.subFormType,
783
+          }"
784
+          v-if="
785
+            taskInfo.formType === 'form' &&
786
+            [
787
+              'participate_oil_station_meeting',
788
+              'participate_emergency_wy',
789
+            ].includes(taskInfo.subFormType)
790
+          "
791
+        />
792
+
793
+        <!-- 量缸试水组件 -->
794
+        <TankWaterComponent
795
+          :task-detail="taskInfo.taskList[0]"
796
+          v-if="
797
+            taskInfo.formType === 'form' &&
798
+            taskInfo.subFormType === 'tank_water'
799
+          "
800
+        />
814 801
       </div>
815 802
 
816 803
       <div style="width: 412px">