闪电 1 mese fa
parent
commit
1071fd5b36

+ 138 - 2
apps/web-ele/src/adapter/component/index.ts

@@ -3,12 +3,14 @@
3 3
  * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
4 4
  */
5 5
 
6
+import type { UploadFile } from 'element-plus';
7
+
6 8
 import type { Component } from 'vue';
7 9
 
8 10
 import type { BaseFormComponentType } from '@vben/common-ui';
9 11
 import type { Recordable } from '@vben/types';
10 12
 
11
-import { defineComponent, getCurrentInstance, h, ref } from 'vue';
13
+import { defineComponent, getCurrentInstance, h, ref, watch } from 'vue';
12 14
 
13 15
 import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
14 16
 import { $t } from '@vben/locales';
@@ -20,6 +22,7 @@ import {
20 22
   ElCheckboxGroup,
21 23
   ElDatePicker,
22 24
   ElDivider,
25
+  ElImageViewer,
23 26
   ElInput,
24 27
   ElInputNumber,
25 28
   ElInputTag,
@@ -37,6 +40,139 @@ import {
37 40
 
38 41
 import { Tinymce as RichTextarea } from '#/components/tinymce';
39 42
 
43
+const withPreviewUpload = () => {
44
+  return defineComponent({
45
+    name: 'UploadWithPreview',
46
+    emits: ['update:modelValue'],
47
+    setup: (
48
+      props: any,
49
+      { attrs, slots, emit }: { attrs: any; emit: any; slots: any },
50
+    ) => {
51
+      const previewVisible = ref<boolean>(false);
52
+      const previewImageUrl = ref<string>('');
53
+      const fileList = ref<UploadFile[]>(
54
+        attrs?.fileList || attrs?.['file-list'] || [],
55
+      );
56
+
57
+      const handleBeforeUpload = (file: UploadFile) => {
58
+        if (attrs.maxSize && (file.size || 0) / 1024 / 1024 > attrs.maxSize) {
59
+          ElNotification({
60
+            title: $t('ui.formRules.sizeLimitTitle'),
61
+            message: $t('ui.formRules.sizeLimit', [attrs.maxSize]),
62
+            type: 'error',
63
+          });
64
+          return false;
65
+        }
66
+        return attrs.beforeUpload?.(file) ?? true;
67
+      };
68
+
69
+      const handleChange = (
70
+        uploadFile: UploadFile,
71
+        uploadFiles: UploadFile[],
72
+      ) => {
73
+        fileList.value = uploadFiles.filter(
74
+          (file) => file.status !== 'removed',
75
+        );
76
+        emit(
77
+          'update:modelValue',
78
+          fileList.value.length > 0 ? fileList.value : undefined,
79
+        );
80
+      };
81
+
82
+      const handlePreview = (file: UploadFile) => {
83
+        // 阻止默认行为,避免新页面打开
84
+        event?.preventDefault();
85
+        event?.stopPropagation();
86
+
87
+        // 检查是否为图片文件
88
+        const isImageFile = (file: UploadFile): boolean => {
89
+          const imageExtensions = new Set([
90
+            'bmp',
91
+            'gif',
92
+            'jpeg',
93
+            'jpg',
94
+            'png',
95
+            'webp',
96
+          ]);
97
+
98
+          // 优先检查 file.type,对于 blob URL 来说,file.type 会包含正确的 MIME 类型
99
+          if (file.type && file.type.startsWith('image/')) {
100
+            return true;
101
+          }
102
+
103
+          // 检查 file.name 的扩展名
104
+          if (file.name) {
105
+            const ext = file.name.split('.').pop()?.toLowerCase();
106
+            if (ext && imageExtensions.has(ext)) {
107
+              return true;
108
+            }
109
+          }
110
+
111
+          // 最后检查 file.url 的扩展名(非 blob URL)
112
+          if (file.url && !file.url.startsWith('blob:')) {
113
+            const ext = file.url.split('.').pop()?.toLowerCase();
114
+            if (ext && imageExtensions.has(ext)) {
115
+              return true;
116
+            }
117
+          }
118
+
119
+          return false;
120
+        };
121
+
122
+        // 如果是图片文件,使用 ElImageViewer 预览
123
+        if (isImageFile(file)) {
124
+          previewImageUrl.value = file.url || file.preview || '';
125
+          previewVisible.value = true;
126
+        } else {
127
+          // 非图片文件直接在新窗口打开
128
+          if (file.url) {
129
+            window.open(file.url, '_blank');
130
+          } else if (file.preview) {
131
+            window.open(file.preview, '_blank');
132
+          } else {
133
+            ElNotification({
134
+              title: $t('ui.formRules.previewWarningTitle'),
135
+              message: $t('ui.formRules.previewWarning'),
136
+              type: 'warning',
137
+            });
138
+          }
139
+        }
140
+      };
141
+
142
+      // 监听表单 API 设置的值
143
+      watch(
144
+        () => attrs.modelValue,
145
+        (res) => {
146
+          fileList.value = res || [];
147
+        },
148
+      );
149
+
150
+      return () => {
151
+        const uploadProps = {
152
+          ...props,
153
+          ...attrs,
154
+          fileList: fileList.value,
155
+          beforeUpload: handleBeforeUpload,
156
+          onChange: handleChange,
157
+          onPreview: handlePreview,
158
+        };
159
+
160
+        return h('div', {}, [
161
+          h(ElUpload, uploadProps, slots),
162
+          previewVisible.value &&
163
+            h(ElImageViewer, {
164
+              urlList: [previewImageUrl.value],
165
+              showProgress: true,
166
+              onClose: () => {
167
+                previewVisible.value = false;
168
+              },
169
+            }),
170
+        ]);
171
+      };
172
+    },
173
+  });
174
+};
175
+
40 176
 const withDefaultPlaceholder = <T extends Component>(
41 177
   component: T,
42 178
   type: 'input' | 'select',
@@ -257,7 +393,7 @@ async function initComponentAdapter() {
257 393
       );
258 394
     },
259 395
     TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'),
260
-    Upload: ElUpload,
396
+    Upload: withPreviewUpload(),
261 397
     RichTextarea,
262 398
     SectionTitle: (props, { attrs, slots }) => {
263 399
       // 获取标题文本,优先使用props.title,其次使用attrs.title,最后使用默认值

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

@@ -210,10 +210,6 @@ const formatDateTime = (dateTime: string) => {
210 210
     object-fit: cover;
211 211
     border-radius: 4px;
212 212
     transition: transform 0.2s;
213
-
214
-    &:hover {
215
-      transform: scale(1.05);
216
-    }
217 213
   }
218 214
 }
219 215
 </style>

+ 11 - 7
apps/web-ele/src/views/schedule/detail/components/group-log.vue

@@ -1,7 +1,7 @@
1 1
 <script lang="ts" setup>
2 2
 // @ts-ignore
3 3
 
4
-import { computed, onMounted, ref } from 'vue';
4
+import { computed, onMounted, ref, watch } from 'vue';
5 5
 
6 6
 import {
7 7
   ElCard,
@@ -168,6 +168,14 @@ const init = () => {
168 168
   basicTableApi.query();
169 169
 };
170 170
 
171
+// 监听一下状态变化,变化之后也加载 init
172
+watch(
173
+  () => props.taskDetail.status,
174
+  () => {
175
+    init();
176
+  },
177
+);
178
+
171 179
 // 组件挂载时,设置表格数据
172 180
 onMounted(() => {
173 181
   init();
@@ -370,11 +378,11 @@ onMounted(() => {
370 378
       <div class="mb-6">
371 379
         <BasicTable table-title="" class="w-full" />
372 380
       </div>
373
-      <ElDescriptions :column="4" class="mb-6">
381
+      <!-- <ElDescriptions :column="4" class="mb-6">
374 382
         <ElDescriptionsItem label="其它信息:" :span="4">
375 383
           {{ groupLogData.otherInfo || '-' }}
376 384
         </ElDescriptionsItem>
377
-      </ElDescriptions>
385
+      </ElDescriptions> -->
378 386
     </div>
379 387
   </ElCard>
380 388
 </template>
@@ -434,10 +442,6 @@ onMounted(() => {
434 442
     object-fit: cover;
435 443
     border-radius: 4px;
436 444
     transition: transform 0.2s;
437
-
438
-    &:hover {
439
-      transform: scale(1.05);
440
-    }
441 445
   }
442 446
 }
443 447
 </style>

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

@@ -130,10 +130,6 @@ defineProps<JoinEmergencyProps>();
130 130
     object-fit: cover;
131 131
     border-radius: 4px;
132 132
     transition: transform 0.2s;
133
-
134
-    &:hover {
135
-      transform: scale(1.05);
136
-    }
137 133
   }
138 134
 }
139 135
 </style>

+ 0 - 4
apps/web-ele/src/views/schedule/detail/components/meeting.vue

@@ -211,10 +211,6 @@ const formatDateTime = (dateTime: string) => {
211 211
     object-fit: cover;
212 212
     border-radius: 4px;
213 213
     transition: transform 0.2s;
214
-
215
-    &:hover {
216
-      transform: scale(1.05);
217
-    }
218 214
   }
219 215
 }
220 216
 </style>

+ 0 - 4
apps/web-ele/src/views/schedule/detail/components/plan.vue

@@ -434,10 +434,6 @@ onMounted(() => {
434 434
     object-fit: cover;
435 435
     border-radius: 4px;
436 436
     transition: transform 0.2s;
437
-
438
-    &:hover {
439
-      transform: scale(1.05);
440
-    }
441 437
   }
442 438
 }
443 439
 </style>

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

@@ -173,10 +173,6 @@ const weeklyReportData = computed(() => {
173 173
     object-fit: cover;
174 174
     border-radius: 4px;
175 175
     transition: transform 0.2s;
176
-
177
-    &:hover {
178
-      transform: scale(1.05);
179
-    }
180 176
   }
181 177
 }
182 178
 </style>

+ 25 - 3
apps/web-ele/src/views/schedule/detail/drawer/groupLog/index.vue

@@ -1,4 +1,4 @@
1
-<script setup lang="ts">
1
+<script setup lang="tsx">
2 2
 import type { ElIcon } from 'element-plus';
3 3
 
4 4
 // @ts-ignore
@@ -12,7 +12,7 @@ import { useVbenDrawer, useVbenForm, useVbenModal } from '@vben/common-ui';
12 12
 // @ts-ignore
13 13
 import { Delete } from '@element-plus/icons-vue';
14 14
 // @ts-ignore
15
-import { ElMessage } from 'element-plus';
15
+import { ElInputNumber, ElMessage } from 'element-plus';
16 16
 
17 17
 // @ts-ignore
18 18
 import { useVbenVxeGrid } from '#/adapter/vxe-table';
@@ -252,8 +252,30 @@ const init = async () => {
252 252
       gridOptions.columns.push({
253 253
         field: `id_${item.id}`,
254 254
         title: `${item.itemName}(${item.standardScore})`,
255
-        editRender: { name: 'input' },
255
+        // editRender: { name: 'input' },
256 256
         // cellType: 'number',
257
+        editRender: {
258
+          name: 'input',
259
+          immediate: true,
260
+          defaultValue: 20,
261
+        },
262
+        slots: {
263
+          // default: (data: any) => {
264
+          //   return data.row.machineValueFirst || '-';
265
+          // },
266
+          edit: (data: any) => {
267
+            return (
268
+              <ElInputNumber
269
+                controls-position="right"
270
+                max={item.standardScore}
271
+                min={0}
272
+                precision={3}
273
+                step={0.1}
274
+                v-model={data.row[`id_${item.id}`]}
275
+              />
276
+            );
277
+          },
278
+        },
257 279
         width: 150,
258 280
       });
259 281
     });

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

@@ -917,6 +917,10 @@ onMounted(async () => {
917 917
         :params="{
918 918
           stationId: taskInfo.stationId,
919 919
         }"
920
+        :only-users="true"
921
+        :user-params="{
922
+          stationId: taskInfo.stationId,
923
+        }"
920 924
       />
921 925
     </ExecutorModal>
922 926
 
@@ -1017,10 +1021,6 @@ onMounted(async () => {
1017 1021
     object-fit: cover;
1018 1022
     border-radius: 4px;
1019 1023
     transition: transform 0.2s;
1020
-
1021
-    &:hover {
1022
-      transform: scale(1.05);
1023
-    }
1024 1024
   }
1025 1025
 }
1026 1026
 

+ 5 - 1
apps/web-ele/src/views/schedule/view/components/day/index.vue

@@ -122,7 +122,11 @@ const todaylist = computed(() => {
122 122
               mainbackcolor: '',
123 123
             },
124 124
           };
125
-          if (days > 0) {
125
+          if (item.status === 0) {
126
+            remainingTime.dayobj.day += `还剩${days}天截止`;
127
+            remainingTime.dayobj.topbackcolor = '#86909C';
128
+            remainingTime.dayobj.mainbackcolor = '#F1F1F1';
129
+          } else if (days > 0) {
126 130
             remainingTime.dayobj.day += `还剩${days}天截止`;
127 131
             if (days >= 30) {
128 132
               remainingTime.dayobj.topbackcolor = '#86909C';

+ 58 - 63
apps/web-ele/src/views/schedule/view/components/month/index.vue

@@ -1,7 +1,8 @@
1 1
 <script setup>
2
-import { ref, computed, watch, defineEmits } from 'vue';
3
-import { ElCalendar, ElTooltip } from 'element-plus';
2
+import { computed, ref } from 'vue';
3
+
4 4
 import dayjs from 'dayjs';
5
+import { ElCalendar, ElTooltip } from 'element-plus';
5 6
 // Props from parent component
6 7
 const props = defineProps(['month', 'daylist', 'overduedaylist']);
7 8
 // const emit = defineEmits(['update:month']);
@@ -296,24 +297,50 @@ const moonlist = computed(() => {
296 297
   const daylists = [...props.daylist];
297 298
   return daylists
298 299
     .filter((item) => item.isOverdue !== '1')
299
-    .map((item) => ({
300
-      id: item.id,
301
-      name: item.taskName,
302
-      date: dayjs(new Date(item?.displayDate))
303
-        .format('YYYY-MM-DD HH:mm:ss')
304
-        .split(' ')[0],
305
-      start: dayjs(new Date(item?.displayDate))
306
-        .format('YYYY-MM-DD HH:mm:ss')
307
-        .split(' ')[1],
308
-      status:
309
-        item?.authStatus == '0' && item?.isLicensable == '1'
310
-          ? 'Authorizable'
311
-          : item?.authStatus == '2'
312
-            ? 'Authorized'
313
-            : item?.authStatus == '1'
314
-              ? 'Authorized1'
315
-              : '',
316
-    }));
300
+    .map((item) => {
301
+      let status = '#215acd';
302
+      switch (item.status) {
303
+        case 0: {
304
+          status = '#8c8c8c'; // 任务未开始或取消
305
+          break;
306
+        }
307
+        case 1: {
308
+          if (item?.endTime) {
309
+            const endTime = new Date(item.endTime).getTime();
310
+            const currentTime = Date.now();
311
+            if (endTime <= currentTime) {
312
+              status = '#d34b27';
313
+            } else if (
314
+              endTime > currentTime &&
315
+              endTime - currentTime <= 24 * 60 * 60 * 1000
316
+            ) {
317
+              status = '#ff9429';
318
+            }
319
+          }
320
+          break;
321
+        }
322
+        case 2: {
323
+          status = '#d34b27';
324
+          break;
325
+        }
326
+        case 3: {
327
+          status = '#339169';
328
+          break;
329
+        }
330
+        default: {
331
+          break;
332
+        }
333
+      }
334
+      return {
335
+        id: item.id,
336
+        name: item.taskName,
337
+        date: dayjs(new Date(item?.displayDate))
338
+          .format('YYYY-MM-DD HH:mm:ss')
339
+          .split(' ')[0],
340
+        start: dayjs(new Date(item?.displayDate)).format('HH:mm'),
341
+        status,
342
+      };
343
+    });
317 344
 });
318 345
 const overduelist = computed(() => {
319 346
   const daylists = [...props.overduedaylist];
@@ -332,29 +359,11 @@ const overduelist = computed(() => {
332 359
 const tasks = computed(() => {
333 360
   return [...moonlist.value, ...overduelist.value];
334 361
 });
335
-// const getTaskStatusClass = (task) => {
336
-//   switch (task.status) {
337
-//     case 'cancelled':
338
-//     case 'not-started': {
339
-//       return 'not-started';
340
-//     }
341
-//     case 'completed': {
342
-//       return 'completed';
343
-//     }
344
-//     case 'overdue': {
345
-//       return 'overdue';
346
-//     }
347
-//     case 'processable': {
348
-//       return 'processable';
349
-//     }
350
-//     default: {
351
-//       return 'not-started';
352
-//     }
353
-//   }
354
-// };
355
-// Get tasks for a specific date
362
+
356 363
 const getTasksForDate = (date) => {
357
-  const dateStr = date.toISOString().split('T')[0];
364
+  // console.log(date, 'data');
365
+  // const dateStr = date.toISOString().split('T')[0];
366
+  const dateStr = dayjs(date).format('YYYY-MM-DD');
358 367
   return tasks.value.filter((task) => {
359 368
     if (typeof task.date === 'string') {
360 369
       return task.date === dateStr;
@@ -384,21 +393,7 @@ const isDateExpanded = (date) => {
384 393
   const dateStr = date.toISOString().split('T')[0];
385 394
   return expandedDates.value[dateStr] || false;
386 395
 };
387
-// 左侧圆点颜色
388
-const statusColor = (status) => {
389
-  switch (status) {
390
-    case 'overdue': //逾期颜色
391
-      return '#D34B27';
392
-    case 'Authorizable': //可授权颜色
393
-      return '#215ACD';
394
-    case 'Authorized': //被授权颜色
395
-      return '#FF9428';
396
-    case 'Authorized1': //已授权颜色
397
-      return '#339169';
398
-    default:
399
-      return '#333333';
400
-  }
401
-};
396
+
402 397
 const todayWeek = computed(() => dayjs().day() - 1);
403 398
 </script>
404 399
 
@@ -421,13 +416,13 @@ const todayWeek = computed(() => dayjs().day() - 1);
421 416
               class="task-item"
422 417
             >
423 418
               <ElTooltip
424
-                :content="`${task.start ? task.start + ' ' : ''}${task.name}${task.department ? ' — ' + task.department : ''}`"
419
+                :content="`${task.start ? `${task.start} ` : ''}${task.name}${task.department ? ` — ${task.department}` : ''}`"
425 420
                 placement="top"
426 421
               >
427 422
                 <div class="task-row">
428 423
                   <span
429 424
                     class="task-dot"
430
-                    :style="{ backgroundColor: statusColor(task.status) }"
425
+                    :style="{ backgroundColor: task.status }"
431 426
                   ></span>
432 427
                   <span v-if="task.start || task.time" class="task-time">
433 428
                     {{ task.start || task.time }}
@@ -680,7 +675,7 @@ const todayWeek = computed(() => dayjs().day() - 1);
680 675
 
681 676
 .task-name {
682 677
   font-size: 12px;
683
-  color: #31373D;
678
+  color: #31373d;
684 679
   line-height: 1.2;
685 680
   text-overflow: ellipsis;
686 681
   overflow: hidden;
@@ -701,9 +696,9 @@ const todayWeek = computed(() => dayjs().day() - 1);
701 696
 .task-time {
702 697
   font-size: 11px;
703 698
   /* color: #666; */
704
-  color: #31373D;
705
-  width: 40px;
706
-  flex: 0 0 40px;
699
+  color: #31373d;
700
+  width: 30px;
701
+  /* flex: 0 0 40px; */
707 702
 }
708 703
 
709 704
 /* Expand button styles */

+ 72 - 56
apps/web-ele/src/views/schedule/view/components/week/index.vue

@@ -1,6 +1,8 @@
1 1
 <script setup>
2
-import { computed, ref, onMounted } from 'vue';
2
+import { computed, ref } from 'vue';
3
+
3 4
 import dayjs from 'dayjs';
5
+
4 6
 const props = defineProps({
5 7
   year: {
6 8
     type: Number,
@@ -31,24 +33,52 @@ const weeklist = computed(() => {
31 33
   const daylists = [...props.daylist];
32 34
   return daylists
33 35
     .filter((item) => item.isOverdue !== '1')
34
-    .map((item) => ({
35
-      id: item.id,
36
-      name: item.taskName,
37
-      date: dayjs(new Date(item?.displayDate))
38
-        .format('YYYY-MM-DD HH:mm:ss')
39
-        .split(' ')[0],
40
-      start: dayjs(new Date(item?.displayDate))
41
-        .format('YYYY-MM-DD HH:mm:ss')
42
-        .split(' ')[1],
43
-      status:
44
-        item?.authStatus == '0' && item?.isLicensable == '1'
45
-          ? 'Authorizable'
46
-          : item?.authStatus == '2'
47
-            ? 'Authorized'
48
-            : item?.authStatus == '1'
49
-              ? 'Authorized1'
50
-              : '',
51
-    }));
36
+    .map((item) => {
37
+      let status = 'Authorizable';
38
+      switch (item.status) {
39
+        case 0: {
40
+          status = ''; // 任务未开始或取消
41
+          break;
42
+        }
43
+        case 1: {
44
+          if (item?.endTime) {
45
+            const endTime = new Date(item.endTime).getTime();
46
+            const currentTime = Date.now();
47
+            if (endTime <= currentTime) {
48
+              status = 'overdue';
49
+            } else if (
50
+              endTime > currentTime &&
51
+              endTime - currentTime <= 24 * 60 * 60 * 1000
52
+            ) {
53
+              status = 'Authorized';
54
+            }
55
+          }
56
+          break;
57
+        }
58
+        case 2: {
59
+          status = 'overdue';
60
+          break;
61
+        }
62
+        case 3: {
63
+          status = 'Authorized1';
64
+          break;
65
+        }
66
+        default: {
67
+          break;
68
+        }
69
+      }
70
+      return {
71
+        id: item.id,
72
+        name: item.taskName,
73
+        date: dayjs(new Date(item?.displayDate))
74
+          .format('YYYY-MM-DD HH:mm:ss')
75
+          .split(' ')[0],
76
+        start: dayjs(new Date(item?.displayDate))
77
+          .format('YYYY-MM-DD HH:mm:ss')
78
+          .split(' ')[1],
79
+        status,
80
+      };
81
+    });
52 82
 });
53 83
 const overduelist = computed(() => {
54 84
   const daylists = [...props.overduedaylist];
@@ -115,8 +145,6 @@ const getTasksForDay = (date) => {
115 145
   const dayFull = weekDays.value.find((d) => d.date === date)?.fullDate;
116 146
   if (!dayFull) return { timeSlots: {}, allTasks: [] };
117 147
   const list = tasks.value.filter((task) => task.date === dayFull);
118
-  // 调试:打印任务数量
119
-  // console.log(`Date: ${date}, FullDate: ${dayFull}, Task count: ${list.length}`);
120 148
 
121 149
   // 对任务进行排序,将overdue状态的任务放在最前面,然后按start时间排序
122 150
   const sortedList = [...list].sort((a, b) => {
@@ -224,22 +252,6 @@ const getTasksForDay = (date) => {
224 252
 //     }
225 253
 //   }
226 254
 // };
227
-const getTaskStatusClass = (task) => {
228
-  switch (task.status) {
229
-    case 'Authorized1': {
230
-      return 'Authorized1'; //已授权
231
-    }
232
-    case 'overdue': {
233
-      return 'overdue'; // 已逾期
234
-    }
235
-    case 'Authorizable': {
236
-      return 'Authorizable'; //可授权
237
-    }
238
-    case 'Authorized': {
239
-      return 'Authorized'; //被授权
240
-    }
241
-  }
242
-};
243 255
 
244 256
 // 计算当前时间线的位置
245 257
 const currentTimeLineStyle = computed(() => {
@@ -249,7 +261,7 @@ const currentTimeLineStyle = computed(() => {
249 261
   const totalMinutes = hours * 60 + minutes;
250 262
   const top = (totalMinutes / (24 * 60)) * (hourHeight * 3); // 因为有3个小时槽
251 263
   return {
252
-    top: top + 'px',
264
+    top: `${top}px`,
253 265
   };
254 266
 });
255 267
 
@@ -302,13 +314,13 @@ const getExpandButtonPosition = (date, slotKey) => {
302 314
     '16:00': 720,
303 315
   }[slotKey];
304 316
 
305
-  if (!slotTasks.length) return slotStart;
317
+  if (slotTasks.length === 0) return slotStart;
306 318
 
307 319
   if (
308 320
     isExpanded(weekDays.value.find((d) => d.date === date)?.fullDate, slotKey)
309 321
   ) {
310 322
     // 如果展开,找到当前时间段最后一个任务的位置,在其下方放置按钮
311
-    const lastTask = allTasks.filter((task) => task.slotKey === slotKey).pop();
323
+    const lastTask = allTasks.findLast((task) => task.slotKey === slotKey);
312 324
     return lastTask.top + lastTask.height + 4; // 4px间距,使按钮更靠近任务
313 325
   } else {
314 326
     // 如果未展开,在当前时间段第8个任务下方放置按钮(如果有8个任务的话)
@@ -320,7 +332,7 @@ const getExpandButtonPosition = (date, slotKey) => {
320 332
     }
321 333
 
322 334
     // 如果任务不足8个(理论上不会发生,因为按钮只在>8时显示)
323
-    const lastTask = allTasks.filter((task) => task.slotKey === slotKey).pop();
335
+    const lastTask = allTasks.findLast((task) => task.slotKey === slotKey);
324 336
     return lastTask.top + lastTask.height + 4;
325 337
   }
326 338
 };
@@ -330,7 +342,7 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
330 342
   const { allTasks } = getTasksForDay(date);
331 343
   const slotTasks = allTasks.filter((task) => task.slotKey === slotKey);
332 344
 
333
-  if (!slotTasks.length) return {};
345
+  if (slotTasks.length === 0) return {};
334 346
 
335 347
   // 找到该时间段第一个任务的位置
336 348
   const firstTask = slotTasks[0];
@@ -351,9 +363,9 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
351 363
   }[slotKey];
352 364
 
353 365
   return {
354
-    top: top + 'px',
355
-    height: height + 'px',
356
-    width: width + 'px',
366
+    top: `${top}px`,
367
+    height: `${height}px`,
368
+    width: `${width}px`,
357 369
     zIndex: baseZIndex,
358 370
   };
359 371
 };
@@ -396,7 +408,7 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
396 408
                   v-for="(h, i) in hours"
397 409
                   :key="h"
398 410
                   class="hour-line"
399
-                  :style="{ height: hourHeight + 'px' }"
411
+                  :style="{ height: `${hourHeight}px` }"
400 412
                 ></div>
401 413
               </div>
402 414
               <!-- tasks positioned -->
@@ -424,10 +436,10 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
424 436
                       )"
425 437
                       :key="task.id"
426 438
                       class="task-block"
427
-                      :class="getTaskStatusClass(task)"
439
+                      :class="task.status"
428 440
                       :style="{
429
-                        top: task.top + 'px',
430
-                        height: task.height + 'px',
441
+                        top: `${task.top}px`,
442
+                        height: `${task.height}px`,
431 443
                         width: '160px',
432 444
                         color: '#333',
433 445
                         display:
@@ -440,7 +452,9 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
440 452
                       title="{{ task.name }}"
441 453
                     >
442 454
                       <div class="task-content">
443
-                        <div class="task-title">{{ task.name }}</div>
455
+                        <div class="task-title">
456
+                          {{ task.name }}
457
+                        </div>
444 458
                       </div>
445 459
                     </div>
446 460
 
@@ -452,7 +466,7 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
452 466
                       "
453 467
                       class="expand-btn"
454 468
                       :style="{
455
-                        top: getExpandButtonPosition(day.date, slotKey) + 'px',
469
+                        top: `${getExpandButtonPosition(day.date, slotKey)}px`,
456 470
                         width: '160px',
457 471
                       }"
458 472
                       @click="toggleExpand(day.fullDate, slotKey)"
@@ -649,12 +663,14 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
649 663
   border-left: 3px solid;
650 664
   background-clip: padding-box;
651 665
   margin-bottom: 2px;
666
+  background-color: #f1f1f1;
667
+  border-left-color: #8c8c8c;
652 668
 }
653 669
 
654 670
 /* Task status background colors */
655 671
 .task-block.Authorizable {
656
-  background-color: #e6f7ff;
657
-  border-left-color: #1890ff;
672
+  background-color: #e4edff;
673
+  border-left-color: #215acd;
658 674
 }
659 675
 
660 676
 .task-block.overdue {
@@ -663,12 +679,12 @@ const getExpandedTimeSlotStyle = (date, slotKey) => {
663 679
 }
664 680
 
665 681
 .task-block.Authorized1 {
666
-  background-color: #f6ffed;
667
-  border-left-color: #52c41a;
682
+  background-color: #d6efe6;
683
+  border-left-color: #339169;
668 684
 }
669 685
 .task-block.Authorized {
670 686
   background-color: #ffead6;
671
-  border-left-color: #ff9428;
687
+  border-left-color: #ff9429;
672 688
 }
673 689
 /* .task-block.not-started {
674 690
   background-color: #f5f5f5;

+ 4 - 14
apps/web-ele/src/views/schedule/view/index.vue

@@ -628,26 +628,16 @@ const createWorkOrderDrawerEvent = () => {
628 628
               </el-checkbox-group>
629 629
             </div>
630 630
           </div>
631
-          <div
632
-            style="display: flex; flex-direction: column; gap: 12px"
633
-            v-if="searchParams.timeType === 'day'"
634
-          >
631
+
632
+          <!-- <div style="width: 50px;height: 50px; background-color: #339169;"></div> -->
633
+
634
+          <div style="display: flex; flex-direction: column; gap: 12px">
635 635
             <div style="color: #409eff">蓝色任务:任务可处理</div>
636 636
             <div style="color: #67c23a">绿色任务: 任务已完成</div>
637 637
             <div style="color: #e6a23c">黄色任务:即将到期任务</div>
638 638
             <div style="color: #909399">灰色任务:任务未开始/任务取消</div>
639 639
             <div style="color: #f56c6c">红色任务:任务过期未完成</div>
640 640
           </div>
641
-          <!-- <div style="width: 50px;height: 50px; background-color: #339169;"></div> -->
642
-          <div
643
-            style="display: flex; flex-direction: column; gap: 12px"
644
-            v-if="searchParams.timeType === 'month'"
645
-          >
646
-            <div style="color: #409eff">蓝色圆点:可授权任务</div>
647
-            <div style="color: #67c23a">绿色圆点:已授权任务</div>
648
-            <div style="color: #e6a23c">黄色圆点:被授权任务</div>
649
-            <div style="color: #f56c6c">红色圆点:已逾期任务</div>
650
-          </div>
651 641
         </div>
652 642
         <!--新增任务按钮固定在底部-->
653 643
         <div class="p-4">

+ 34 - 9
apps/web-ele/src/views/system/taskDesign/formDesign/index.vue

@@ -1,7 +1,7 @@
1 1
 <script setup lang="ts">
2 2
 import type { CheckItem, SubItem } from './formDesign-data';
3 3
 
4
-import { onMounted, reactive, ref, watch } from 'vue';
4
+import { computed, onMounted, reactive, ref, watch } from 'vue';
5 5
 import { useRoute } from 'vue-router';
6 6
 
7 7
 import { Page } from '@vben/common-ui';
@@ -46,7 +46,7 @@ import { getUploadAction } from '#/components/upload/config';
46 46
 // import { tr } from 'element-plus/lib/locale/index.js';
47 47
 const accessStore = useAccessStore();
48 48
 const route = useRoute();
49
-const formId = ref((route.query.id as string) || '');
49
+const formId = computed(() => (route.query.id as string) || '');
50 50
 // const querydata = JSON.parse((route.query.data as string) || '{}');
51 51
 // console.log(querydata);
52 52
 const querydata: any = ref({});
@@ -61,7 +61,11 @@ const selectedSubItemId = ref<string>('');
61 61
 // 查询子项列表
62 62
 const querysubItemlist = async () => {
63 63
   try {
64
-    const res = await querysubItembaseApilist({ mainId: querydata.value.id });
64
+    const res = await querysubItembaseApilist({
65
+      mainId: querydata.value.id,
66
+      pageNum: 1,
67
+      pageSize: 1000,
68
+    });
65 69
     subItems.value = res.rows || [];
66 70
     if (subItems.value.length > 0 && !selectedSubItemId.value) {
67 71
       selectedSubItemId.value = subItems.value[0].id;
@@ -95,16 +99,37 @@ const getFormData = async () => {
95 99
   }
96 100
 };
97 101
 
98
-onMounted(() => {
99
-  getFormData();
100
-  querysubItemlist();
101
-  taglistfn();
102
+const init = async () => {
103
+  // 重置选中的子项ID,确保不会引用旧数据
104
+  selectedSubItemId.value = '';
105
+  await getFormData();
106
+  await querysubItemlist();
107
+  await taglistfn();
108
+};
109
+
110
+// 检测 id 变化
111
+watch(
112
+  () => route.query.id,
113
+  async (newVal, oldVal) => {
114
+    if (newVal !== oldVal) {
115
+      await init();
116
+    }
117
+  },
118
+  {
119
+    immediate: true,
120
+  },
121
+);
122
+
123
+onMounted(async () => {
124
+  await init();
102 125
 });
103 126
 const queryinspectionItemlist = async (subItemId: any) => {
104 127
   try {
105 128
     const res = await queryinspectionItemApilist({
106 129
       mainId: querydata.value.id,
107 130
       subItemId,
131
+      pageNum: 1,
132
+      pageSize: 1000,
108 133
     });
109 134
     checkItems.value = res.rows || [];
110 135
   } catch (error) {
@@ -620,7 +645,7 @@ function handleDrawerOpen() {
620 645
         </div>
621 646
 
622 647
         <!-- 表格内容 -->
623
-        <div class="space-y-0">
648
+        <div class="max-h-[calc(100vh-300px)] space-y-0 overflow-y-auto">
624 649
           <div
625 650
             v-for="subItem in subItems"
626 651
             :key="subItem.id"
@@ -708,7 +733,7 @@ function handleDrawerOpen() {
708 733
         </div>
709 734
 
710 735
         <!-- 表格内容 -->
711
-        <div class="space-y-0">
736
+        <div class="max-h-[calc(100vh-450px)] space-y-0 overflow-y-auto">
712 737
           <div
713 738
             v-for="checkItem in checkItems"
714 739
             :key="checkItem.id"