瀏覽代碼

add: 运营周报

weieryang 1 月之前
父節點
當前提交
9d41aa373e

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

@@ -9,6 +9,7 @@ enum Api {
9 9
   joinEmergencyHandle = '/formEmergencyDrillParticipation/participation/handle',
10 10
   marketingSurveyHandle = '/formCompetitorMarketingSurvey/survey/handle',
11 11
   meetingBase = '/formMeetingRecords/records/handle',
12
+  operationalWeeklyReportHandle = '/formOperationalWeeklyReport/report/handle',
12 13
   salesSurveyHandle = '/formCompetitorSalesSurvey/survey/handle',
13 14
   scheduleShiftManagementList = '/scheduleShiftManagement/management/list',
14 15
   tankWaterHandle = '/formTankWater/water/handle',
@@ -132,3 +133,12 @@ export function handleTankWater(params: any) {
132 133
 export function handleAdditiveInventory(params: any) {
133 134
   return requestClient.put(`${Api.additiveInventoryHandle}`, params);
134 135
 }
136
+
137
+/**
138
+ * 运营周报处理
139
+ * @param params 处理参数
140
+ * @returns
141
+ */
142
+export function handleOperationalWeeklyReport(params: any) {
143
+  return requestClient.put(`${Api.operationalWeeklyReportHandle}`, params);
144
+}

+ 182 - 0
apps/web-ele/src/views/schedule/detail/components/weekly-report.vue

@@ -0,0 +1,182 @@
1
+<script lang="ts" setup>
2
+import { computed } from 'vue';
3
+
4
+import {
5
+  ElCard,
6
+  ElDescriptions,
7
+  ElDescriptionsItem,
8
+  ElImage,
9
+} from 'element-plus';
10
+
11
+// 定义组件的Props接口
12
+interface WeeklyReportProps {
13
+  taskDetail: any;
14
+}
15
+
16
+// 接收父组件传递的任务详情数据
17
+const props = defineProps<WeeklyReportProps>();
18
+
19
+// 计算属性,获取运营周报数据
20
+const weeklyReportData = computed(() => {
21
+  return props.taskDetail || {};
22
+});
23
+</script>
24
+
25
+<template>
26
+  <ElCard>
27
+    <template #header>
28
+      <div class="flex items-center gap-4">
29
+        <div style="width: 4px; height: 12px; background-color: #215acd"></div>
30
+        <span
31
+          class="text-lg font-bold text-gray-800"
32
+          style="font-size: 14px; font-weight: 600"
33
+        >
34
+          运营周报详情
35
+        </span>
36
+      </div>
37
+    </template>
38
+
39
+    <div class="task-info">
40
+      <!-- 基本信息 -->
41
+      <div class="section-title">
42
+        <div class="section-bar"></div>
43
+        <span class="section-text">策略</span>
44
+      </div>
45
+      <ElDescriptions :column="4" class="mb-6">
46
+        <ElDescriptionsItem label="本站价格策略:" :span="4">
47
+          {{ weeklyReportData.sitePriceStrategy || '-' }}
48
+        </ElDescriptionsItem>
49
+        <ElDescriptionsItem label="本站策略变化:" :span="4">
50
+          {{ weeklyReportData.siteStrategyChange || '-' }}
51
+        </ElDescriptionsItem>
52
+        <ElDescriptionsItem label="竞对油站策略:" :span="4">
53
+          {{ weeklyReportData.competitorStrategy || '-' }}
54
+        </ElDescriptionsItem>
55
+        <ElDescriptionsItem label="竞对策略变化:" :span="4">
56
+          {{ weeklyReportData.competitorStrategyChange || '-' }}
57
+        </ElDescriptionsItem>
58
+      </ElDescriptions>
59
+
60
+      <!-- 本周工作 -->
61
+      <div class="section-title">
62
+        <div class="section-bar"></div>
63
+        <span class="section-text">本周工作</span>
64
+      </div>
65
+      <ElDescriptions :column="4" class="mb-6">
66
+        <ElDescriptionsItem label="本周完成工作:" :span="4">
67
+          {{ weeklyReportData.weekCompletedWork || '-' }}
68
+        </ElDescriptionsItem>
69
+        <ElDescriptionsItem label="本周工作总结:" :span="4">
70
+          {{ weeklyReportData.weekSummary || '-' }}
71
+        </ElDescriptionsItem>
72
+      </ElDescriptions>
73
+
74
+      <!-- 下周计划 -->
75
+      <div class="section-title">
76
+        <div class="section-bar"></div>
77
+        <span class="section-text">下周计划</span>
78
+      </div>
79
+      <ElDescriptions :column="4" class="mb-6">
80
+        <ElDescriptionsItem label="下周工作计划:" :span="4">
81
+          {{ weeklyReportData.nextWeekPlan || '-' }}
82
+        </ElDescriptionsItem>
83
+        <ElDescriptionsItem label="需协调与帮助:" :span="4">
84
+          {{ weeklyReportData.coordinationHelp || '-' }}
85
+        </ElDescriptionsItem>
86
+        <ElDescriptionsItem label="安全、内控、合规、其它事项:" :span="4">
87
+          {{ weeklyReportData.securityInternalComplianceOther || '-' }}
88
+        </ElDescriptionsItem>
89
+      </ElDescriptions>
90
+
91
+      <!-- 附件图片 -->
92
+      <div class="section-title">
93
+        <div class="section-bar"></div>
94
+        <span class="section-text">附件</span>
95
+      </div>
96
+      <ElDescriptions :column="4" class="mb-6">
97
+        <ElDescriptionsItem
98
+          v-if="
99
+            weeklyReportData.imagesUrl && weeklyReportData.imagesUrl.length > 0
100
+          "
101
+          label="图片:"
102
+        >
103
+          <div class="task-images">
104
+            <ElImage
105
+              v-for="(image, index) in weeklyReportData.imagesUrl"
106
+              :key="index"
107
+              :src="image"
108
+              :preview-src-list="weeklyReportData.imagesUrl"
109
+              fit="cover"
110
+              alt="运营周报图片"
111
+              class="task-image"
112
+            />
113
+          </div>
114
+        </ElDescriptionsItem>
115
+        <ElDescriptionsItem v-else label="图片:"> - </ElDescriptionsItem>
116
+      </ElDescriptions>
117
+    </div>
118
+  </ElCard>
119
+</template>
120
+
121
+<style scoped lang="scss">
122
+.task-info {
123
+  .section-title {
124
+    display: flex;
125
+    align-items: center;
126
+    gap: 8px;
127
+    margin: 20px 0 12px 0;
128
+
129
+    .section-bar {
130
+      width: 4px;
131
+      height: 12px;
132
+      background-color: #215acd;
133
+    }
134
+
135
+    .section-text {
136
+      font-size: 14px;
137
+      font-weight: 600;
138
+      color: var(--text-color-primary);
139
+    }
140
+  }
141
+
142
+  :deep(.el-descriptions) {
143
+    margin-bottom: 0 !important;
144
+  }
145
+
146
+  :deep(.el-descriptions__label) {
147
+    font-size: 14px;
148
+    font-weight: 400;
149
+    color: var(--text-color-secondary);
150
+  }
151
+
152
+  :deep(.el-descriptions__content) {
153
+    font-size: 14px;
154
+    font-weight: 500;
155
+    color: var(--text-color-primary);
156
+  }
157
+
158
+  :deep(.el-descriptions__table) {
159
+    background: transparent !important;
160
+  }
161
+}
162
+
163
+.task-images {
164
+  display: flex;
165
+  gap: 12px;
166
+  margin-top: 4px;
167
+  flex-wrap: wrap;
168
+
169
+  .task-image {
170
+    width: 80px;
171
+    height: 80px;
172
+    cursor: pointer;
173
+    object-fit: cover;
174
+    border-radius: 4px;
175
+    transition: transform 0.2s;
176
+
177
+    &:hover {
178
+      transform: scale(1.05);
179
+    }
180
+  }
181
+}
182
+</style>

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

@@ -22,4 +22,6 @@ export { default as UploadDrawer } from './upload/index.vue';
22 22
 
23 23
 // export { default as WeeklyDrawer } from './weekly/index.vue';
24 24
 
25
+export { default as WeeklyReportDrawer } from './weekly-report/index.vue';
26
+
25 27
 export { default as WeeklyEvaluationDrawer } from './weeklyEvaluation/index.vue';

+ 184 - 0
apps/web-ele/src/views/schedule/detail/drawer/weekly-report/config-data.tsx

@@ -0,0 +1,184 @@
1
+// 运营周报抽屉配置数据
2
+// @ts-ignore: 忽略
3
+import type { FormSchemaGetter } from '#/adapter/form';
4
+
5
+// @ts-ignore: 忽略
6
+import { getMultipleImageUploadConfig } from '#/components/upload';
7
+
8
+export const drawerFormSchema: any | FormSchemaGetter = () => [
9
+  {
10
+    component: 'SectionTitle',
11
+    fieldName: '_section_title',
12
+    hideLabel: true,
13
+    componentProps: {
14
+      title: '基本信息',
15
+    },
16
+  },
17
+  {
18
+    component: 'Input',
19
+    componentProps: {
20
+      placeholder: '请输入本站价格策略',
21
+      type: 'textarea',
22
+      rows: 3,
23
+      maxlength: 200,
24
+    },
25
+    fieldName: 'sitePriceStrategy',
26
+    label: '本站价格策略',
27
+    rules: 'required',
28
+  },
29
+  {
30
+    component: 'Input',
31
+    componentProps: {
32
+      placeholder: '请输入本站策略变化',
33
+      type: 'textarea',
34
+      rows: 3,
35
+      maxlength: 200,
36
+    },
37
+    fieldName: 'siteStrategyChange',
38
+    label: '本站策略变化',
39
+    rules: 'required',
40
+  },
41
+  {
42
+    component: 'Input',
43
+    componentProps: {
44
+      placeholder: '请输入竞对油站策略',
45
+      type: 'textarea',
46
+      rows: 3,
47
+      maxlength: 200,
48
+    },
49
+    fieldName: 'competitorStrategy',
50
+    label: '竞对油站策略',
51
+    rules: 'required',
52
+  },
53
+  {
54
+    component: 'Input',
55
+    componentProps: {
56
+      placeholder: '请输入竞对策略变化',
57
+      type: 'textarea',
58
+      rows: 3,
59
+      maxlength: 200,
60
+    },
61
+    fieldName: 'competitorStrategyChange',
62
+    label: '竞对策略变化',
63
+    rules: 'required',
64
+  },
65
+  {
66
+    component: 'SectionTitle',
67
+    fieldName: '_section_title',
68
+    hideLabel: true,
69
+    componentProps: {
70
+      title: '本周工作',
71
+    },
72
+  },
73
+  {
74
+    component: 'Input',
75
+    componentProps: {
76
+      placeholder: '请输入本周完成工作',
77
+      type: 'textarea',
78
+      rows: 3,
79
+      maxlength: 200,
80
+    },
81
+    fieldName: 'weekCompletedWork',
82
+    label: '本周完成工作',
83
+    rules: 'required',
84
+  },
85
+  {
86
+    component: 'Input',
87
+    componentProps: {
88
+      placeholder: '请输入本周工作总结',
89
+      type: 'textarea',
90
+      rows: 3,
91
+      maxlength: 200,
92
+    },
93
+    fieldName: 'weekSummary',
94
+    label: '本周工作总结',
95
+    rules: 'required',
96
+  },
97
+  {
98
+    component: 'SectionTitle',
99
+    fieldName: '_section_title',
100
+    hideLabel: true,
101
+    componentProps: {
102
+      title: '下周计划',
103
+    },
104
+  },
105
+  {
106
+    component: 'Input',
107
+    componentProps: {
108
+      placeholder: '请输入下周工作计划',
109
+      type: 'textarea',
110
+      rows: 3,
111
+      maxlength: 200,
112
+    },
113
+    fieldName: 'nextWeekPlan',
114
+    label: '下周工作计划',
115
+    rules: 'required',
116
+  },
117
+  {
118
+    component: 'Input',
119
+    componentProps: {
120
+      placeholder: '请输入需协调与帮助',
121
+      type: 'textarea',
122
+      rows: 3,
123
+      maxlength: 200,
124
+    },
125
+    fieldName: 'coordinationHelp',
126
+    label: '需协调与帮助',
127
+    rules: 'required',
128
+  },
129
+  {
130
+    component: 'Input',
131
+    componentProps: {
132
+      placeholder: '请输入安全、内控、合规、其它事项',
133
+      type: 'textarea',
134
+      rows: 3,
135
+      maxlength: 200,
136
+    },
137
+    fieldName: 'securityInternalComplianceOther',
138
+    label: '安全、内控、合规、其它事项',
139
+  },
140
+  {
141
+    component: 'SectionTitle',
142
+    fieldName: '_section_title',
143
+    hideLabel: true,
144
+    componentProps: {
145
+      title: '附件',
146
+    },
147
+  },
148
+  {
149
+    component: 'Input',
150
+    fieldName: 'images',
151
+    dependencies: {
152
+      show: () => false,
153
+      triggerFields: [''],
154
+    },
155
+  },
156
+  {
157
+    component: 'Upload',
158
+    fieldName: 'imagePaths',
159
+    label: '图片',
160
+    componentProps: (row: any) => {
161
+      return {
162
+        ...getMultipleImageUploadConfig(6),
163
+        multiple: true,
164
+        onSuccess: (res: any, uploadFile: any, uploadFiles: any) => {
165
+          if (res.code === 200) {
166
+            const paths: string[] = [];
167
+            uploadFiles.forEach((item: any) => {
168
+              if (item.response?.code === 200) {
169
+                paths.push(item.response.data.fileName);
170
+              }
171
+            });
172
+            row.images = paths.join(',');
173
+            return res.data;
174
+          }
175
+        },
176
+      };
177
+    },
178
+    renderComponentContent: () => {
179
+      return {
180
+        default: () => '点击上传',
181
+      };
182
+    },
183
+  },
184
+];

+ 118 - 0
apps/web-ele/src/views/schedule/detail/drawer/weekly-report/index.vue

@@ -0,0 +1,118 @@
1
+<script setup lang="ts">
2
+import { ref } from 'vue';
3
+
4
+// @ts-ignore
5
+import { useVbenDrawer, useVbenForm } from '@vben/common-ui';
6
+
7
+// @ts-ignore
8
+import { ElMessage } from 'element-plus';
9
+
10
+// @ts-ignore
11
+import { handleOperationalWeeklyReport } from '#/api/task/index';
12
+
13
+// @ts-ignore
14
+import { drawerFormSchema } from './config-data';
15
+
16
+// 定义emit
17
+const emit = defineEmits<{ reload: [] }>();
18
+
19
+// 运营周报参数
20
+const weeklyReportParams = ref({
21
+  taskId: '',
22
+  taskName: '',
23
+});
24
+
25
+// 初始化表单数据
26
+const initialFormData = ref({
27
+  competitorStrategy: '',
28
+  competitorStrategyChange: '',
29
+  coordinationHelp: '',
30
+  id: undefined,
31
+  images: '',
32
+  nextWeekPlan: '',
33
+  securityInternalComplianceOther: '',
34
+  sitePriceStrategy: '',
35
+  siteStrategyChange: '',
36
+  weekCompletedWork: '',
37
+  weekSummary: '',
38
+});
39
+
40
+// 创建表单实例
41
+const [Form, formApi] = useVbenForm({
42
+  showDefaultActions: false,
43
+  schema: drawerFormSchema(),
44
+});
45
+
46
+// 创建抽屉实例
47
+const [Drawer, drawerApi] = useVbenDrawer({
48
+  async onOpenChange(isOpen: boolean) {
49
+    if (!isOpen) {
50
+      return;
51
+    }
52
+    try {
53
+      drawerApi.drawerLoading(true);
54
+      const { taskId, taskName } = drawerApi.getData();
55
+      weeklyReportParams.value.taskId = taskId;
56
+      weeklyReportParams.value.taskName = taskName;
57
+
58
+      // 重置表单
59
+      formApi.resetForm(initialFormData.value);
60
+    } catch (error) {
61
+      console.error(error);
62
+      ElMessage.error('加载运营周报数据失败');
63
+    } finally {
64
+      drawerApi.drawerLoading(false);
65
+    }
66
+  },
67
+  onClosed() {
68
+    formApi.resetForm(initialFormData.value);
69
+  },
70
+  async onConfirm() {
71
+    try {
72
+      this.confirmLoading = true;
73
+
74
+      // 表单验证
75
+      const { valid } = await formApi.validate();
76
+      if (!valid) {
77
+        return;
78
+      }
79
+
80
+      // 获取表单值
81
+      const values = await formApi.getValues();
82
+
83
+      // 处理图片字段
84
+      delete values.imagePaths;
85
+
86
+      // 构造请求参数
87
+      const params = {
88
+        id: weeklyReportParams.value.taskId,
89
+        ...values,
90
+      };
91
+
92
+      // 调用API保存运营周报数据
93
+      await handleOperationalWeeklyReport(params);
94
+
95
+      ElMessage.success('运营周报处理成功');
96
+      emit('reload');
97
+      drawerApi.close();
98
+    } catch (error) {
99
+      console.error(error);
100
+      ElMessage.error('运营周报处理失败');
101
+    } finally {
102
+      this.confirmLoading = false;
103
+    }
104
+  },
105
+});
106
+</script>
107
+
108
+<template>
109
+  <Drawer :title="weeklyReportParams.taskName">
110
+    <Form />
111
+  </Drawer>
112
+</template>
113
+
114
+<style scoped lang="scss">
115
+:deep(.el-input-number) {
116
+  width: 100%;
117
+}
118
+</style>

+ 14 - 0
apps/web-ele/src/views/schedule/detail/index.vue

@@ -66,6 +66,7 @@ import SalesSurveyComponent from './components/sales-survey.vue';
66 66
 import TankWaterComponent from './components/tank-water.vue';
67 67
 // @ts-ignore
68 68
 import WeeklyEvaluationComponent from './components/weekly-evaluation.vue';
69
+import WeeklyReportComponent from './components/weekly-report.vue';
69 70
 // @ts-ignore
70 71
 import WeeklyComponent from './components/weekly.vue';
71 72
 import { mobileTaskTypes } from './config-data';
@@ -83,6 +84,7 @@ import {
83 84
   TankWaterDrawer,
84 85
   UploadDrawer,
85 86
   WeeklyEvaluationDrawer,
87
+  WeeklyReportDrawer,
86 88
 } from './drawer';
87 89
 
88 90
 const route = useRoute();
@@ -329,6 +331,10 @@ const DynamicDrawerComponent = defineComponent({
329 331
             Component = OperatingPlanDrawer;
330 332
             break;
331 333
           }
334
+          case 'operating_weekly_report': {
335
+            Component = WeeklyReportDrawer;
336
+            break;
337
+          }
332 338
           case 'participate_emergency_wy':
333 339
           case 'participate_oil_station_meeting': {
334 340
             Component = JoinEmergencyDrawer;
@@ -817,6 +823,14 @@ onMounted(async () => {
817 823
           "
818 824
         />
819 825
 
826
+        <WeeklyReportComponent
827
+          :task-detail="taskInfo.taskList[0]"
828
+          v-if="
829
+            taskInfo.formType === 'form' &&
830
+            taskInfo.subFormType === 'operating_weekly_report'
831
+          "
832
+        />
833
+
820 834
         <!-- 处理信息组件 -->
821 835
         <!-- <ElCard v-if="taskInfo.status === 3">
822 836
           <template #header>