Kaynağa Gözat

修改日程视图页面和日程视图详情页面

chenxiaochao 2 ay önce
ebeveyn
işleme
cf8f0c2ca6

+ 7 - 4
apps/web-ele/src/views/schedule/detail/components/bidding.vue

@@ -68,9 +68,13 @@ const [StationStrategyTable] = useVbenVxeGrid({
68 68
     <!-- 页面标题和操作区 -->
69 69
     <div class="task-header">
70 70
       <div class="left">
71
-        <h3>我方油价:未来路加油站</h3>
71
+        <div style="font-size: 14px; font-weight: 400">
72
+          <span>我方油价:</span>
73
+          <span style="font-size: 14px; font-weight: 500">未来路加油站</span>
74
+        </div>
72 75
         <div class="price-survey-info">
73
-          <span class="survey-date">调查时间:2025-10-29</span>
76
+          <span>调查时间:</span>
77
+          <span style="font-weight: 500">2025-10-29</span>
74 78
         </div>
75 79
       </div>
76 80
       <div class="right">
@@ -116,9 +120,8 @@ const [StationStrategyTable] = useVbenVxeGrid({
116 120
 }
117 121
 
118 122
 .price-survey-info {
119
-  display: flex;
120
-  gap: 20px;
121 123
   font-size: 14px;
124
+  font-weight: 400;
122 125
   color: #666;
123 126
 }
124 127
 

+ 72 - 199
apps/web-ele/src/views/schedule/detail/components/comment.vue

@@ -1,17 +1,18 @@
1 1
 <script lang="ts" setup>
2 2
 import { ref, computed } from 'vue';
3
-import { ElRate, ElInput, ElSelect, ElOption, ElButton, ElIcon, ElUpload, ElMessage, ElImageViewer } from 'element-plus';
3
+import {
4
+  ElRate,
5
+  ElInput,
6
+  ElSelect,
7
+  ElOption,
8
+  ElButton,
9
+  ElIcon,
10
+  ElUpload,
11
+  ElMessage,
12
+  ElImageViewer,
13
+} from 'element-plus';
4 14
 import { Camera, Plus, Message } from '@element-plus/icons-vue';
5
-
6
-// 评分等级映射
7
-const ratingLevelMap = {
8
-  1: '差',
9
-  2: '较差',
10
-  3: '一般',
11
-  4: '良好',
12
-  5: '优秀',
13
-};
14
-
15
+import ConsultComponent from './consult.vue';
15 16
 // 模拟评论数据
16 17
 const comments = ref([
17 18
   {
@@ -48,20 +49,16 @@ const comments = ref([
48 49
     replies: [],
49 50
   },
50 51
 ]);
51
-
52 52
 // 评分
53 53
 const rating = ref(5);
54 54
 // 评价内容
55 55
 const commentContent = ref('');
56
-// 抄送人
57
-const ccPerson = ref('');
58 56
 // 评论图片
59 57
 const commentImages = ref<any[]>([]);
60 58
 
61 59
 // 图片预览相关
62 60
 const previewVisible = ref(false);
63 61
 const previewImages = ref<string[]>([]);
64
-
65 62
 // 处理评论图片上传
66 63
 const handleCommentImageUpload = (options: any) => {
67 64
   // 模拟上传成功处理
@@ -86,68 +83,10 @@ const handleCommentImagePreview = (file: any) => {
86 83
   // TODO: 实现图片预览功能
87 84
 };
88 85
 
89
-// 评论提交
90
-const handleCommentSubmit = () => {
91
-  if (!commentContent.value.trim() && commentImages.value.length === 0) {
92
-    ElMessage.warning('请输入评论内容或上传图片');
93
-    return;
94
-  }
95
-  console.log('提交评论', { rating: rating.value, content: commentContent.value, ccPerson: ccPerson.value, images: commentImages.value });
96
-};
97
-
98
-// 切换回复输入框
99
-const toggleReply = (comment: any) => {
100
-  comment.showReply = !comment.showReply;
101
-};
102
-
103
-// 取消回复
104
-const cancelReply = (comment: any) => {
105
-  comment.showReply = false;
106
-  comment.replyContent = '';
107
-};
108
-
109
-// 提交回复
110
-const submitReply = (comment: any) => {
111
-  if (!comment.replyContent.trim()) {
112
-    ElMessage.warning('请输入回复内容');
113
-    return;
114
-  }
115
-  
116
-  // 模拟提交回复
117
-  const newReply = {
118
-    username: '当前用户',
119
-    content: comment.replyContent,
120
-    createdAt: new Date().toLocaleString(),
121
-  };
122
-  
123
-  // 添加到回复列表
124
-  if (!comment.replies) {
125
-    comment.replies = [];
126
-  }
127
-  comment.replies.push(newReply);
128
-  
129
-  // 清空回复内容并隐藏回复框
130
-  comment.replyContent = '';
131
-  comment.showReply = false;
132
-  
133
-  ElMessage.success('回复提交成功');
134
-};
135
-
136
-// 图片预览
137
-const previewImage = (imageUrl: string) => {
138
-  previewImages.value = [imageUrl];
139
-  previewVisible.value = true;
140
-};
141
-
142 86
 // 关闭图片预览
143 87
 const closePreview = () => {
144 88
   previewVisible.value = false;
145 89
 };
146
-
147
-// 获取评分等级
148
-const getRatingLevel = (rating: number) => {
149
-  return ratingLevelMap[rating as keyof typeof ratingLevelMap] || '';
150
-};
151 90
 </script>
152 91
 
153 92
 <template>
@@ -156,14 +95,28 @@ const getRatingLevel = (rating: number) => {
156 95
     <div class="comment-form">
157 96
       <div class="form-header">
158 97
         <div class="rating-section">
159
-          <span class="rating-text">总体评价:</span>
160
-          <ElRate v-model="rating" class="rating-stars" />
98
+          <span class="rating-text">评价:</span>
99
+          <el-rate
100
+            v-model="rating"
101
+            :texts="['1分', '2分', '3分', '4分', '5分']"
102
+            show-text
103
+          />
161 104
         </div>
162 105
       </div>
163 106
       <div class="form-content">
164 107
         <div class="input-section">
165
-          <!-- 使用ElUpload组件实现多图片上传 -->
166
-          <div class="upload-section">
108
+          <div class="rating-section">
109
+            <span class="rating-text">评价:</span>
110
+            <ElInput
111
+              v-model="commentContent"
112
+              type="textarea"
113
+              :rows="2"
114
+              placeholder="请对执行任务的情况进行点评,您的点评会帮助执行人更好的完善工作哦~"
115
+              class="comment-input"
116
+            />
117
+          </div>
118
+          <div class="rating-section">
119
+            <span class="rating-text">照片:</span>
167 120
             <ElUpload
168 121
               v-model:file-list="commentImages"
169 122
               action="#"
@@ -186,96 +139,15 @@ const getRatingLevel = (rating: number) => {
186 139
               </div>
187 140
             </ElUpload>
188 141
           </div>
189
-          <ElInput
190
-            v-model="commentContent"
191
-            type="textarea"
192
-            :rows="2"
193
-            placeholder="请对执行任务的情况进行点评,您的点评会帮助执行人更好的完善工作哦~"
194
-            class="comment-input"
195
-          />
196
-          <div class="form-footer">
197
-            <div class="footer-left">
198
-              <ElSelect v-model="ccPerson" placeholder="请选择抄送人" class="cc-select">
199
-                <ElOption label="测试抄送人" value="test" />
200
-              </ElSelect>
201
-              <ElButton type="primary" size="small" class="comment-btn" @click="handleCommentSubmit">
202
-                评论
203
-              </ElButton>
204
-            </div>
205
-          </div>
206 142
         </div>
207 143
       </div>
144
+      <el-button style="margin-top: 8px" type="primary">提交</el-button>
208 145
     </div>
209
-
210
-    <!-- 评论列表 -->
211
-    <div class="comment-list">
212
-      <div v-for="comment in comments" :key="comment.id" class="comment-item">
213
-        <div class="comment-header">
214
-          <div class="username-section">
215
-            <span class="username">{{ comment.username }}</span>
216
-            <span class="department">({{ comment.department }})</span>
217
-            <div class="rating-section">
218
-              <ElRate v-model="comment.rating" disabled class="rating-stars" />
219
-              <span class="rating-level">{{ getRatingLevel(comment.rating) }}</span>
220
-            </div>
221
-          </div>
222
-        </div>
223
-        <div class="comment-content">
224
-          {{ comment.content }}
225
-        </div>
226
-        <!-- 评论图片 -->
227
-        <div v-if="comment.images && comment.images.length > 0" class="comment-images">
228
-          <img
229
-            v-for="(image, index) in comment.images"
230
-            :key="index"
231
-            :src="image"
232
-            alt="评论图片"
233
-            class="comment-image"
234
-            @click="previewImage(image)"
235
-          />
236
-        </div>
237
-        <!-- 评论时间 -->
238
-        <div class="comment-time">{{ comment.createdAt }}</div>
239
-        <!-- 评论操作 -->
240
-        <div class="comment-footer">
241
-          <div class="comment-actions">
242
-            <ElIcon class="reply-icon">
243
-              <Message class="h-4 w-4" />
244
-            </ElIcon>
245
-            <span class="reply-btn" @click="toggleReply(comment)">回复</span>
246
-          </div>
247
-        </div>
248
-        
249
-        <!-- 回复输入框 -->
250
-        <div v-if="comment.showReply" class="reply-form">
251
-          <ElInput
252
-            v-model="comment.replyContent"
253
-            type="textarea"
254
-            :rows="2"
255
-            placeholder="请输入回复内容"
256
-            class="reply-input"
257
-          />
258
-          <div class="reply-footer">
259
-            <ElButton type="default" size="small" @click="cancelReply(comment)">取消</ElButton>
260
-            <ElButton type="primary" size="small" @click="submitReply(comment)">提交</ElButton>
261
-          </div>
262
-        </div>
263
-        
264
-        <!-- 回复信息 -->
265
-        <div v-if="comment.replies && comment.replies.length > 0" class="reply-list">
266
-          <div v-for="(reply, index) in comment.replies" :key="index" class="reply-item">
267
-            <div class="reply-header">
268
-              <span class="reply-username">{{ reply.username }}</span>
269
-              <span v-if="reply.department" class="reply-department">({{ reply.department }})</span>
270
-            </div>
271
-            <div class="reply-content">{{ reply.content }}</div>
272
-            <div class="reply-time">{{ reply.createdAt }}</div>
273
-          </div>
274
-        </div>
275
-      </div>
146
+    <div>
147
+      <ConsultComponent />
276 148
     </div>
277 149
   </div>
278
-  
150
+
279 151
   <!-- 图片预览组件 -->
280 152
   <ElImageViewer
281 153
     v-if="previewVisible"
@@ -292,7 +164,7 @@ const getRatingLevel = (rating: number) => {
292 164
   .comment-form {
293 165
     margin-bottom: 24px;
294 166
     padding: 16px 0;
295
-    
167
+
296 168
     .form-header {
297 169
       margin-bottom: 12px;
298 170
     }
@@ -300,13 +172,14 @@ const getRatingLevel = (rating: number) => {
300 172
     .rating-section {
301 173
       display: flex;
302 174
       align-items: center;
303
-      
175
+
304 176
       .rating-text {
305 177
         color: var(--text-color-secondary);
306 178
         font-size: 14px;
307 179
         margin-right: 8px;
180
+        white-space: nowrap;
308 181
       }
309
-      
182
+
310 183
       .rating-stars {
311 184
         margin-right: 0;
312 185
       }
@@ -315,40 +188,40 @@ const getRatingLevel = (rating: number) => {
315 188
     .form-content {
316 189
       .input-section {
317 190
         width: 100%;
318
-        
191
+
319 192
         .upload-section {
320 193
           margin-bottom: 12px;
321
-          
194
+
322 195
           :deep(.el-upload--picture-card) {
323 196
             width: 60px;
324 197
             height: 60px;
325 198
           }
326
-          
199
+
327 200
           :deep(.el-upload-list--picture-card .el-upload-list__item) {
328 201
             width: 60px;
329 202
             height: 60px;
330 203
           }
331 204
         }
332
-        
205
+
333 206
         .comment-input {
334 207
           margin-bottom: 12px;
335
-          
208
+
336 209
           :deep(.el-textarea__inner) {
337 210
             border-radius: 4px;
338 211
             resize: none;
339 212
           }
340 213
         }
341
-        
214
+
342 215
         .form-footer {
343 216
           .footer-left {
344 217
             display: flex;
345 218
             align-items: center;
346
-            
219
+
347 220
             .cc-select {
348 221
               width: 200px;
349 222
               margin-right: 12px;
350 223
             }
351
-            
224
+
352 225
             .comment-btn {
353 226
               padding: 4px 12px;
354 227
             }
@@ -368,31 +241,31 @@ const getRatingLevel = (rating: number) => {
368 241
 
369 242
       .comment-header {
370 243
         margin-bottom: 8px;
371
-        
244
+
372 245
         .username-section {
373 246
           display: flex;
374 247
           align-items: center;
375
-          
248
+
376 249
           .username {
377 250
             font-weight: 500;
378 251
             color: var(--text-color-primary);
379 252
             margin-right: 8px;
380 253
           }
381
-          
254
+
382 255
           .department {
383 256
             color: var(--text-color-secondary);
384 257
             font-size: 13px;
385 258
             margin-right: 16px;
386 259
           }
387
-          
260
+
388 261
           .rating-section {
389 262
             display: flex;
390 263
             align-items: center;
391
-            
264
+
392 265
             .rating-stars {
393 266
               margin-right: 8px;
394 267
             }
395
-            
268
+
396 269
             .rating-level {
397 270
               color: #f7ba2a;
398 271
               font-size: 13px;
@@ -412,7 +285,7 @@ const getRatingLevel = (rating: number) => {
412 285
         display: flex;
413 286
         gap: 12px;
414 287
         margin-bottom: 12px;
415
-        
288
+
416 289
         .comment-image {
417 290
           width: 60px;
418 291
           height: 60px;
@@ -420,49 +293,49 @@ const getRatingLevel = (rating: number) => {
420 293
           object-fit: cover;
421 294
           cursor: pointer;
422 295
           transition: transform 0.2s;
423
-          
296
+
424 297
           &:hover {
425 298
             transform: scale(1.05);
426 299
           }
427 300
         }
428 301
       }
429
-      
302
+
430 303
       /* 评论时间样式 */
431 304
       .comment-time {
432 305
         font-size: 12px;
433 306
         color: #999999;
434 307
         margin-top: 8px;
435 308
       }
436
-      
309
+
437 310
       /* 评论操作样式 */
438 311
       .comment-footer {
439 312
         display: flex;
440 313
         justify-content: flex-start;
441 314
         align-items: center;
442 315
         margin-top: 4px;
443
-        
316
+
444 317
         .comment-actions {
445 318
           display: flex;
446 319
           align-items: center;
447
-          
320
+
448 321
           .reply-icon {
449 322
             margin-right: 4px;
450 323
             color: #409eff;
451 324
             font-size: 12px;
452 325
           }
453
-          
326
+
454 327
           .reply-btn {
455 328
             color: #409eff;
456 329
             font-size: 12px;
457 330
             cursor: pointer;
458
-            
331
+
459 332
             &:hover {
460 333
               text-decoration: underline;
461 334
             }
462 335
           }
463 336
         }
464 337
       }
465
-      
338
+
466 339
       /* 回复表单样式 */
467 340
       .reply-form {
468 341
         margin-top: 12px;
@@ -470,62 +343,62 @@ const getRatingLevel = (rating: number) => {
470 343
         background-color: var(--bg-color-light);
471 344
         border-radius: 4px;
472 345
         border: 1px solid var(--border-color);
473
-        
346
+
474 347
         .reply-input {
475 348
           margin-bottom: 12px;
476
-          
349
+
477 350
           :deep(.el-textarea__inner) {
478 351
             border-radius: 4px;
479 352
             resize: none;
480 353
           }
481 354
         }
482
-        
355
+
483 356
         .reply-footer {
484 357
           display: flex;
485 358
           justify-content: flex-end;
486 359
           gap: 8px;
487
-          
360
+
488 361
           :deep(.el-button) {
489 362
             padding: 4px 12px;
490 363
           }
491 364
         }
492 365
       }
493
-      
366
+
494 367
       /* 回复列表样式 */
495 368
       .reply-list {
496 369
         margin-top: 12px;
497 370
         margin-left: 40px;
498
-        
371
+
499 372
         .reply-item {
500 373
           margin-bottom: 12px;
501 374
           padding: 8px 12px;
502 375
           background-color: var(--bg-color-light);
503 376
           border-radius: 4px;
504 377
           border-left: 3px solid #409eff;
505
-          
378
+
506 379
           .reply-header {
507 380
             margin-bottom: 4px;
508
-            
381
+
509 382
             .reply-username {
510 383
               font-weight: 500;
511 384
               color: var(--text-color-primary);
512 385
               font-size: 13px;
513 386
               margin-right: 4px;
514 387
             }
515
-            
388
+
516 389
             .reply-department {
517 390
               color: var(--text-color-secondary);
518 391
               font-size: 13px;
519 392
             }
520 393
           }
521
-          
394
+
522 395
           .reply-content {
523 396
             color: var(--text-color-primary);
524 397
             font-size: 13px;
525 398
             line-height: 1.4;
526 399
             margin-bottom: 4px;
527 400
           }
528
-          
401
+
529 402
           .reply-time {
530 403
             font-size: 12px;
531 404
             color: #999999;

+ 124 - 24
apps/web-ele/src/views/schedule/detail/components/consult.vue

@@ -3,14 +3,42 @@ import { ref } from 'vue';
3 3
 import { ElTabs, ElTabPane } from 'element-plus';
4 4
 
5 5
 // 当前选中的tab
6
-const activeTab = ref('read');
6
+const activeTab = ref('comment');
7
+//评论模拟数据
8
+const comments = ref([
9
+  {
10
+    name: '张三',
11
+    content:
12
+      '干的不错!12问题解决的很迅速干的不错问题解决的很迅速!干的不错,问题解决的很迅速!干的不错,问题解决的很迅速!',
13
+    time: '一天前',
14
+    child: [
15
+      {
16
+        name: '张三',
17
+        content: '谢谢站长支持!',
18
+      },
19
+    ],
20
+  },
21
+  {
22
+    name: '李四',
23
+    content:
24
+      '干的不错!12问题解决的很迅速干的不错问题解决的很迅速!干的不错,问题解决的很迅速!干的不错,问题解决的很迅速!',
25
+    time: '三天前',
26
+  },
27
+  {
28
+    name: '王五',
29
+  },
30
+]);
7 31
 
32
+const replyOpen = ref({}) as any;
33
+const toggleReply = (index: any) => {
34
+  replyOpen.value[index] = !replyOpen.value[index];
35
+};
8 36
 // 查阅统计数据
9 37
 const consultStats = ref({
10 38
   readCount: 2,
11 39
   unreadCount: 1,
12 40
   readers: ['东冬', '世鹏'],
13
-  unreaders: ['张三']
41
+  unreaders: ['张三'],
14 42
 });
15 43
 
16 44
 // 处理tab切换
@@ -28,32 +56,77 @@ const getLastTwoChars = (name: string) => {
28 56
   <div class="consult-container">
29 57
     <!-- Tabs切换 -->
30 58
     <ElTabs v-model="activeTab" @tab-change="handleTabChange" class="mb-4">
31
-      <ElTabPane 
32
-        :label="`${consultStats.readCount}人已阅`" 
33
-        name="read"
34
-      />
35
-      <ElTabPane 
36
-        :label="`${consultStats.unreadCount}人未阅`" 
37
-        name="unread"
38
-      />
59
+      <ElTabPane :label="'评论'" name="comment" />
60
+      <ElTabPane :label="`${consultStats.readCount}人已阅`" name="read" />
61
+      <ElTabPane :label="`${consultStats.unreadCount}人未阅`" name="unread" />
39 62
     </ElTabs>
40
-    
63
+
41 64
     <!-- 人员列表 -->
42
-    <div v-if="activeTab === 'read'" class="readers-list">
43
-      <div 
44
-        v-for="(reader, index) in consultStats.readers" 
65
+    <div v-if="activeTab === 'comment'" class="readers-list">
66
+      <div v-for="(item, index) in comments" :key="index" class="comment_item">
67
+        <div class="reader-item mb-2 mr-2" style="flex-shrink: 0">
68
+          {{ getLastTwoChars(item.name) }}
69
+        </div>
70
+        <div class="comment_content">
71
+          <span style="font-size: 15px; font-weight: 900">{{ item.name }}</span>
72
+          <div>{{ item.content }}</div>
73
+          <div>
74
+            <span style="color: #a4aab2">{{ item.time }}</span>
75
+            <span class="reply_btn" @click="toggleReply(index)">回复</span>
76
+          </div>
77
+          <div
78
+            v-if="item.child && item.child.length > 0"
79
+            style="
80
+              margin-left: 16px;
81
+              margin-top: 8px;
82
+              border-left: 2px solid #dcdfe6;
83
+              padding-left: 8px;
84
+            "
85
+          >
86
+            <div v-for="value in item.child">
87
+              <div>
88
+                <span>{{ value?.name }}:</span>
89
+                <span>{{ value?.content }}</span>
90
+              </div>
91
+            </div>
92
+          </div>
93
+          <div
94
+            style="margin-left: 16px; margin-top: 8px"
95
+            v-if="replyOpen[index]"
96
+          >
97
+            <el-input
98
+              maxlength="200"
99
+              style="width: 240px"
100
+              placeholder="请输入内容"
101
+              show-word-limit
102
+              type="textarea"
103
+            />
104
+            <div style="margin-top: 8px">
105
+              <el-button type="primary" size="small">提交</el-button>
106
+              <el-button size="small" @click="() => toggleReply(index)"
107
+                >收起</el-button
108
+              >
109
+            </div>
110
+          </div>
111
+        </div>
112
+      </div>
113
+    </div>
114
+
115
+    <div v-else-if="activeTab === 'read'" class="readers-list">
116
+      <div
117
+        v-for="(reader, index) in consultStats.readers"
45 118
         :key="index"
46
-        class="reader-item mr-2 mb-2"
119
+        class="reader-item mb-2 mr-2"
47 120
       >
48 121
         {{ getLastTwoChars(reader) }}
49 122
       </div>
50 123
     </div>
51
-    
124
+
52 125
     <div v-else class="readers-list">
53
-      <div 
54
-        v-for="(unreader, index) in consultStats.unreaders" 
126
+      <div
127
+        v-for="(unreader, index) in consultStats.unreaders"
55 128
         :key="index"
56
-        class="reader-item mr-2 mb-2 unread"
129
+        class="reader-item unread mb-2 mr-2"
57 130
       >
58 131
         {{ getLastTwoChars(unreader) }}
59 132
       </div>
@@ -62,16 +135,43 @@ const getLastTwoChars = (name: string) => {
62 135
 </template>
63 136
 
64 137
 <style scoped lang="scss">
138
+.comment_item {
139
+  display: flex;
140
+  // align-items: center;
141
+  // justify-content: space-between;
142
+  width: 100%;
143
+  // padding: 8px 16px;
144
+  border-radius: 4px;
145
+  // background-color: #f5f7fa;
146
+  margin-bottom: 8px;
147
+  font-size: 12px;
148
+  color: #606266;
149
+
150
+  .comment_content {
151
+    margin-top: 6px;
152
+    display: flex;
153
+    flex-direction: column;
154
+    gap: 8px;
155
+    .reply_btn {
156
+      float: right;
157
+      color: #409eff;
158
+      cursor: pointer;
159
+      &:hover {
160
+        text-decoration: underline;
161
+      }
162
+    }
163
+  }
164
+}
65 165
 .consult-container {
66 166
   width: 100%;
67 167
   padding: 16px 0;
68 168
   font-size: 14px;
69
-  
169
+
70 170
   .readers-list {
71 171
     display: flex;
72 172
     flex-wrap: wrap;
73 173
   }
74
-  
174
+
75 175
   .reader-item {
76 176
     display: flex;
77 177
     align-items: center;
@@ -85,16 +185,16 @@ const getLastTwoChars = (name: string) => {
85 185
     font-weight: 500;
86 186
     cursor: pointer;
87 187
     transition: all 0.3s ease;
88
-    
188
+
89 189
     &:hover {
90 190
       background-color: #66b1ff;
91 191
       transform: scale(1.1);
92 192
     }
93
-    
193
+
94 194
     &.unread {
95 195
       background-color: #dcdfe6;
96 196
       color: #606266;
97
-      
197
+
98 198
       &:hover {
99 199
         background-color: #e4e7ed;
100 200
       }

+ 17 - 9
apps/web-ele/src/views/schedule/detail/components/weekly.vue

@@ -20,16 +20,16 @@ const weeklyData = ref({
20 20
   deadline: '2025-12-14 23:00:00',
21 21
   status: '规划完成',
22 22
   executor: '要智站务',
23
-  organization: '系统'
23
+  organization: '系统',
24 24
 });
25 25
 
26 26
 // 状态标签配置
27 27
 const statusConfig: any = {
28
-  '规划完成': { type: 'success', text: '规划完成' },
29
-  '待处理': { type: 'info', text: '待处理' },
30
-  '处理中': { type: 'warning', text: '处理中' },
31
-  '已完成': { type: 'success', text: '已完成' },
32
-  '已关闭': { type: 'danger', text: '已关闭' }
28
+  规划完成: { type: 'success', text: '规划完成' },
29
+  待处理: { type: 'info', text: '待处理' },
30
+  处理中: { type: 'warning', text: '处理中' },
31
+  已完成: { type: 'success', text: '已完成' },
32
+  已关闭: { type: 'danger', text: '已关闭' },
33 33
 };
34 34
 </script>
35 35
 
@@ -70,7 +70,10 @@ const statusConfig: any = {
70 70
         {{ weeklyData.remark || '-' }}
71 71
       </ElDescriptionsItem>
72 72
       <ElDescriptionsItem label="图片:" :span="4">
73
-        <div v-if="weeklyData.images && weeklyData.images.length > 0" class="weekly-images">
73
+        <div
74
+          v-if="weeklyData.images && weeklyData.images.length > 0"
75
+          class="weekly-images"
76
+        >
74 77
           <img
75 78
             v-for="(image, index) in weeklyData.images"
76 79
             :key="index"
@@ -110,10 +113,15 @@ const statusConfig: any = {
110 113
 
111 114
 .weekly-info {
112 115
   :deep(.el-descriptions__label) {
113
-    font-weight: 500;
116
+    font-size: 14px;
117
+    font-weight: 400;
114 118
     color: var(--text-color-secondary);
115 119
   }
116
-
120
+  :deep(.el-descriptions__content) {
121
+    font-size: 14px;
122
+    font-weight: 500;
123
+    color: var(--text-color-primary);
124
+  }
117 125
   :deep(.el-descriptions__content) {
118 126
     color: var(--text-color-primary);
119 127
   }

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

@@ -14,12 +14,13 @@ import BiddingComponent from './components/bidding.vue';
14 14
 import CheckComponent from './components/check.vue';
15 15
 // 引入检查项组件、评论组件和查阅组件
16 16
 import CommentComponent from './components/comment.vue';
17
-import ConsultComponent from './components/consult.vue';
17
+// import ConsultComponent from './components/consult.vue';
18 18
 import WeeklyComponent from './components/weekly.vue';
19 19
 
20 20
 // 模拟任务数据
21 21
 const taskData = ref({
22 22
   name: '未来路摄像头抓图AI检查',
23
+  username: '张三',
23 24
   status: '待处理',
24 25
   priority: '必做',
25 26
   description: '摄像头自动抓图进行AI检查',
@@ -31,6 +32,7 @@ const taskData = ref({
31 32
   taskOwner: '',
32 33
   frequency: '每天一次',
33 34
   creator: '系统',
35
+  suggestion: '暂无',
34 36
   images: [
35 37
     'https://picsum.photos/200/150?random=1',
36 38
     'https://picsum.photos/200/150?random=2',
@@ -125,40 +127,31 @@ const handleTransferTask = () => {
125 127
         </div>
126 128
       </div>
127 129
     </template>
130
+    <div>
131
+      <span style="font-size: 20px; font-weight: 400">运营异常-任务详情</span>
132
+    </div>
128 133
     <div class="boxdev">
129 134
       <div>
130 135
         <ElCard>
131 136
           <template #header>
132
-            <div class="flex items-center gap-6">
137
+            <div class="flex items-center gap-4">
133 138
               <div
134
-                style="width: 8px; height: 20px; background-color: #215acd"
139
+                style="width: 4px; height: 12px; background-color: #215acd"
135 140
               ></div>
136
-              <span class="text-lg font-bold text-gray-800">任务信息</span>
141
+              <span
142
+                class="text-lg font-bold text-gray-800"
143
+                style="font-size: 14px; font-weight: 600"
144
+                >任务信息</span
145
+              >
137 146
             </div>
138 147
           </template>
139 148
           <ElDescriptions class="task-info" :column="4">
140
-            <ElDescriptionsItem label="任务描述:" :span="4">
149
+            <ElDescriptionsItem label="任务描述:">
141 150
               {{ taskData.description }}
142 151
             </ElDescriptionsItem>
143
-            <ElDescriptionsItem label="标准指引:" :span="4">
152
+            <ElDescriptionsItem label="标准指引:">
144 153
               {{ taskData.standardGuide || '-' }}
145 154
             </ElDescriptionsItem>
146
-            <ElDescriptionsItem label="任务图片:" :span="4">
147
-              <div
148
-                v-if="taskData.images && taskData.images.length > 0"
149
-                class="task-images"
150
-              >
151
-                <img
152
-                  v-for="(image, index) in taskData.images"
153
-                  :key="index"
154
-                  :src="image"
155
-                  alt="任务图片"
156
-                  class="task-image"
157
-                  @click="previewImage(image)"
158
-                />
159
-              </div>
160
-              <span v-else>-</span>
161
-            </ElDescriptionsItem>
162 155
             <ElDescriptionsItem label="执行人:">
163 156
               {{ taskData.executor }}
164 157
             </ElDescriptionsItem>
@@ -177,105 +170,133 @@ const handleTransferTask = () => {
177 170
             <ElDescriptionsItem label="任务频率:">
178 171
               {{ taskData.frequency }}
179 172
             </ElDescriptionsItem>
180
-            <ElDescriptionsItem label="创建:">
173
+            <ElDescriptionsItem label="负责人:">
174
+              {{ taskData.username }}
175
+            </ElDescriptionsItem>
176
+            <ElDescriptionsItem label="创建:" :span="4">
181 177
               {{ taskData.creator }}
182 178
             </ElDescriptionsItem>
183
-            <!-- <ElDescriptionsItem :span="2" class="text-right">
184
-          <template #default>
185
-            <ElButton type="text" class="text-gray-500">收起 ↑</ElButton>
186
-          </template>
187
-        </ElDescriptionsItem> -->
179
+            <ElDescriptionsItem>
180
+              <div style="padding-left: 24px; margin-top: 10px">
181
+                <div>处理建议: {{ taskData.frequency }}</div>
182
+                <div>任务图片:</div>
183
+                <div
184
+                  v-if="taskData.images && taskData.images.length > 0"
185
+                  class="task-images"
186
+                >
187
+                  <img
188
+                    v-for="(image, index) in taskData.images"
189
+                    :key="index"
190
+                    :src="image"
191
+                    alt="任务图片"
192
+                    class="task-image"
193
+                    @click="previewImage(image)"
194
+                  />
195
+                </div>
196
+                <span v-else>-</span>
197
+              </div>
198
+            </ElDescriptionsItem>
188 199
           </ElDescriptions>
189 200
         </ElCard>
190 201
 
191 202
         <!--竞价-->
192 203
         <ElCard>
193 204
           <template #header>
194
-            <div class="flex items-center gap-6">
205
+            <div class="flex items-center gap-4">
195 206
               <div
196
-                style="width: 8px; height: 20px; background-color: #215acd"
207
+                style="width: 4px; height: 12px; background-color: #215acd"
197 208
               ></div>
198
-              <span class="text-lg font-bold text-gray-800">竞价信息</span>
209
+              <span
210
+                class="text-lg font-bold text-gray-800"
211
+                style="font-size: 14px; font-weight: 600"
212
+                >竞价信息</span
213
+              >
199 214
             </div>
200 215
           </template>
201 216
           <BiddingComponent />
202 217
         </ElCard>
203 218
 
204 219
         <!-- 周报信息 -->
205
-        <ElCard class="mt-4">
220
+        <ElCard>
206 221
           <template #header>
207
-            <div class="flex items-center gap-6">
222
+            <div class="flex items-center gap-4">
208 223
               <div
209
-                style="width: 8px; height: 20px; background-color: #215acd"
224
+                style="width: 4px; height: 12px; background-color: #215acd"
210 225
               ></div>
211
-              <span class="text-lg font-bold text-gray-800">周报信息</span>
226
+              <span
227
+                class="text-lg font-bold text-gray-800"
228
+                style="font-size: 14px; font-weight: 600"
229
+                >周报信息</span
230
+              >
212 231
             </div>
213 232
           </template>
214 233
           <WeeklyComponent />
215 234
         </ElCard>
216 235
 
217 236
         <!-- 处理信息组件 -->
218
-        <ElCard class="mt-4">
237
+        <ElCard>
219 238
           <template #header>
220
-            <div class="flex items-center gap-6">
239
+            <div class="flex items-center gap-4">
221 240
               <div
222
-                style="width: 8px; height: 20px; background-color: #215acd"
241
+                style="width: 4px; height: 12px; background-color: #215acd"
223 242
               ></div>
224
-              <span class="text-lg font-bold text-gray-800">处理信息</span>
243
+              <span
244
+                class="text-lg font-bold text-gray-800"
245
+                style="font-size: 14px; font-weight: 600"
246
+                >处理信息</span
247
+              >
225 248
             </div>
226 249
           </template>
227 250
           <ElDescriptions class="task-info" :column="4">
251
+            <ElDescriptionsItem label="处理情况:">
252
+              {{ taskData.handleInfo.handleStatus || '-' }}
253
+            </ElDescriptionsItem>
254
+            <ElDescriptionsItem label="处理时间:">
255
+              {{ taskData.handleInfo.handleTime || '-' }}
256
+            </ElDescriptionsItem>
228 257
             <ElDescriptionsItem label="处理状态:" :span="4">
229
-              <ElTag
230
-                :type="
231
-                  statusConfig[taskData.handleInfo.handleStatus]?.type || 'info'
232
-                "
233
-              >
234
-                {{
235
-                  statusConfig[taskData.handleInfo.handleStatus]?.text ||
236
-                  taskData.handleInfo.handleStatus
237
-                }}
258
+              <ElTag :type="statusConfig[taskData.status]?.type || 'info'">
259
+                {{ statusConfig[taskData.status]?.text || taskData.status }}
238 260
               </ElTag>
239 261
             </ElDescriptionsItem>
240
-            <ElDescriptionsItem label="处理情况:" :span="4">
241
-              {{ taskData.handleInfo.handleSituation || '-' }}
242
-            </ElDescriptionsItem>
243
-            <ElDescriptionsItem label="处理图片:" :span="4">
244
-              <div
245
-                v-if="
246
-                  taskData.handleInfo.handleImages &&
247
-                  taskData.handleInfo.handleImages.length > 0
248
-                "
249
-                class="task-images"
250
-              >
251
-                <img
252
-                  v-for="(image, index) in taskData.handleInfo.handleImages"
253
-                  :key="index"
254
-                  :src="image"
255
-                  alt="处理图片"
256
-                  class="task-image"
257
-                  @click="previewImage(image)"
258
-                />
262
+            <ElDescriptionsItem>
263
+              <div style="padding-left: 24px; margin-top: 10px">
264
+                <div>处理建议: {{ taskData.frequency }}</div>
265
+                <div>任务图片:</div>
266
+                <div
267
+                  v-if="
268
+                    taskData.handleInfo.handleImages &&
269
+                    taskData.handleInfo.handleImages.length > 0
270
+                  "
271
+                  class="task-images"
272
+                >
273
+                  <img
274
+                    v-for="(image, index) in taskData.handleInfo.handleImages"
275
+                    :key="index"
276
+                    :src="image"
277
+                    alt="处理图片"
278
+                    class="task-image"
279
+                    @click="previewImage(image)"
280
+                  />
281
+                </div>
282
+                <span v-else>-</span>
259 283
               </div>
260
-              <span v-else>-</span>
261
-            </ElDescriptionsItem>
262
-            <ElDescriptionsItem label="处理人:">
263
-              {{ taskData.handleInfo.handler || '-' }}
264
-            </ElDescriptionsItem>
265
-            <ElDescriptionsItem label="处理时间:">
266
-              {{ taskData.handleInfo.handleTime || '-' }}
267 284
             </ElDescriptionsItem>
268 285
           </ElDescriptions>
269 286
         </ElCard>
270 287
 
271 288
         <!-- 检查项组件 -->
272
-        <ElCard class="mt-4">
289
+        <ElCard>
273 290
           <template #header>
274
-            <div class="flex items-center gap-6">
291
+            <div class="flex items-center gap-4">
275 292
               <div
276
-                style="width: 8px; height: 20px; background-color: #215acd"
293
+                style="width: 4px; height: 12px; background-color: #215acd"
277 294
               ></div>
278
-              <span class="text-lg font-bold text-gray-800">检查项</span>
295
+              <span
296
+                class="text-lg font-bold text-gray-800"
297
+                style="font-size: 14px; font-weight: 600"
298
+                >检查项</span
299
+              >
279 300
             </div>
280 301
           </template>
281 302
           <CheckComponent />
@@ -285,27 +306,19 @@ const handleTransferTask = () => {
285 306
         <!-- 评论组件 -->
286 307
         <ElCard>
287 308
           <template #header>
288
-            <div class="flex items-center gap-6">
309
+            <div class="flex items-center gap-4">
289 310
               <div
290
-                style="width: 8px; height: 20px; background-color: #215acd"
311
+                style="width: 4px; height: 12px; background-color: #215acd"
291 312
               ></div>
292
-              <span class="text-lg font-bold text-gray-800">评论</span>
313
+              <span
314
+                class="text-lg font-bold text-gray-800"
315
+                style="font-size: 14px; font-weight: 600"
316
+                >评论</span
317
+              >
293 318
             </div>
294 319
           </template>
295 320
           <CommentComponent />
296 321
         </ElCard>
297
-        <!-- 查阅组件 -->
298
-        <ElCard class="mt-4">
299
-          <template #header>
300
-            <div class="flex items-center gap-6">
301
-              <div
302
-                style="width: 8px; height: 20px; background-color: #215acd"
303
-              ></div>
304
-              <span class="text-lg font-bold text-gray-800">查阅</span>
305
-            </div>
306
-          </template>
307
-          <ConsultComponent />
308
-        </ElCard>
309 322
       </div>
310 323
     </div>
311 324
   </Page>
@@ -323,6 +336,24 @@ const handleTransferTask = () => {
323 336
   display: flex;
324 337
   gap: 20px;
325 338
 }
339
+.boxdev :deep(.el-card) {
340
+  border: none !important;
341
+  box-shadow: none !important;
342
+  background: transparent !important;
343
+}
344
+.boxdev :deep(.el-card__header) {
345
+  padding-top: 18px !important;
346
+  padding-bottom: 4px !important;
347
+  padding-left: 0px !important;
348
+
349
+  border-bottom: none !important;
350
+}
351
+.boxdev :deep(.el-card__body) {
352
+  padding-top: 0px !important;
353
+}
354
+::v-deep .el-descriptions__body {
355
+  background: #ffffff00 !important;
356
+}
326 357
 .boxdev > div:nth-child(1) {
327 358
   flex: 1;
328 359
   min-width: 0;
@@ -348,18 +379,21 @@ const handleTransferTask = () => {
348 379
 }
349 380
 
350 381
 .task-info {
382
+  // border: 1px solid red;
351 383
   :deep(.el-descriptions__label) {
352
-    font-weight: 500;
384
+    font-size: 14px;
385
+    font-weight: 400;
353 386
     color: var(--text-color-secondary);
354 387
   }
355 388
 
356 389
   :deep(.el-descriptions__content) {
390
+    font-size: 14px;
391
+    font-weight: 500;
357 392
     color: var(--text-color-primary);
358 393
   }
359
-
360
-  // :deep(.el-descriptions-item__content) {
361
-  //   padding: 8px 0;
362
-  // }
394
+  :deep(.el-descriptions__table) {
395
+    background: transparent !important;
396
+  }
363 397
 }
364 398
 
365 399
 .task-images {

+ 118 - 34
apps/web-ele/src/views/schedule/view/components/month/index.vue

@@ -1,22 +1,22 @@
1 1
 <script setup>
2
-import { ref, computed } from 'vue';
3
-import { ElCalendar } from 'element-plus';
2
+import { ref, computed, watch } from 'vue';
3
+import { ElCalendar, ElTooltip } from 'element-plus';
4 4
 
5 5
 // Props from parent component
6 6
 const props = defineProps({
7 7
   month: {
8 8
     type: Number,
9 9
     required: true,
10
-    default: ''
10
+    default: '',
11 11
   },
12 12
 });
13
-
14 13
 // 模拟任务数据
15 14
 const tasks = ref([
16 15
   {
17 16
     id: 1,
18 17
     name: '未来路摄像头抓图AI检查',
19 18
     date: '2025-12-15',
19
+    start: '23:59',
20 20
     status: 'processable',
21 21
     department: '管理部',
22 22
   },
@@ -24,6 +24,7 @@ const tasks = ref([
24 24
     id: 2,
25 25
     name: '龙飞街摄像头抓图AI检查',
26 26
     date: '2025-12-15',
27
+    start: '23:59',
27 28
     status: 'processable',
28 29
     department: '管理部',
29 30
   },
@@ -31,6 +32,7 @@ const tasks = ref([
31 32
     id: 3,
32 33
     name: '中州大道监控设备维护',
33 34
     date: '2025-12-15',
35
+    start: '07:59',
34 36
     status: 'not-started',
35 37
     department: '技术部',
36 38
   },
@@ -38,6 +40,7 @@ const tasks = ref([
38 40
     id: 4,
39 41
     name: '农业路交通流量分析',
40 42
     date: '2025-12-15',
43
+    start: '09:30',
41 44
     status: 'cancelled',
42 45
     department: '数据分析部',
43 46
   },
@@ -45,6 +48,7 @@ const tasks = ref([
45 48
     id: 5,
46 49
     name: '未来路摄像头抓图AI检查',
47 50
     date: '2025-12-16',
51
+    start: '08:15',
48 52
     status: 'processable',
49 53
     department: '管理部',
50 54
   },
@@ -52,6 +56,7 @@ const tasks = ref([
52 56
     id: 6,
53 57
     name: '龙飞街摄像头抓图AI检查',
54 58
     date: '2025-12-16',
59
+    start: '09:45',
55 60
     status: 'processable',
56 61
     department: '管理部',
57 62
   },
@@ -59,6 +64,7 @@ const tasks = ref([
59 64
     id: 7,
60 65
     name: '文化路监控系统升级',
61 66
     date: '2025-12-16',
67
+    start: '07:00',
62 68
     status: 'completed',
63 69
     department: '技术部',
64 70
   },
@@ -66,6 +72,7 @@ const tasks = ref([
66 72
     id: 8,
67 73
     name: '纬五路设备巡检',
68 74
     date: '2025-12-16',
75
+    start: '08:30',
69 76
     status: 'overdue',
70 77
     department: '运维部',
71 78
   },
@@ -73,6 +80,7 @@ const tasks = ref([
73 80
     id: 9,
74 81
     name: '未来路摄像头抓图AI检查',
75 82
     date: '2025-12-17',
83
+    start: '10:00',
76 84
     status: 'processable',
77 85
     department: '管理部',
78 86
   },
@@ -80,6 +88,7 @@ const tasks = ref([
80 88
     id: 10,
81 89
     name: '龙飞街摄像头抓图AI检查',
82 90
     date: '2025-12-17',
91
+    start: '11:20',
83 92
     status: 'processable',
84 93
     department: '管理部',
85 94
   },
@@ -87,6 +96,7 @@ const tasks = ref([
87 96
     id: 11,
88 97
     name: '经三路摄像头调试',
89 98
     date: '2025-12-17',
99
+    start: '13:15',
90 100
     status: 'not-started',
91 101
     department: '技术部',
92 102
   },
@@ -94,6 +104,7 @@ const tasks = ref([
94 104
     id: 12,
95 105
     name: '东风路设备更新计划',
96 106
     date: '2025-12-17',
107
+    start: '14:00',
97 108
     status: 'cancelled',
98 109
     department: '采购部',
99 110
   },
@@ -101,6 +112,7 @@ const tasks = ref([
101 112
     id: 13,
102 113
     name: '未来路摄像头抓图AI检查',
103 114
     date: '2025-12-18',
115
+    start: '09:10',
104 116
     status: 'processable',
105 117
     department: '管理部',
106 118
   },
@@ -108,6 +120,7 @@ const tasks = ref([
108 120
     id: 14,
109 121
     name: '龙飞街摄像头抓图AI检查',
110 122
     date: '2025-12-18',
123
+    start: '10:05',
111 124
     status: 'processable',
112 125
     department: '管理部',
113 126
   },
@@ -115,6 +128,7 @@ const tasks = ref([
115 128
     id: 15,
116 129
     name: '花园路监控中心改造',
117 130
     date: '2025-12-18',
131
+    start: '15:00',
118 132
     status: 'completed',
119 133
     department: '技术部',
120 134
   },
@@ -122,6 +136,7 @@ const tasks = ref([
122 136
     id: 16,
123 137
     name: '桐柏路设备维护',
124 138
     date: '2025-12-18',
139
+    start: '16:30',
125 140
     status: 'overdue',
126 141
     department: '运维部',
127 142
   },
@@ -129,6 +144,7 @@ const tasks = ref([
129 144
     id: 17,
130 145
     name: '未来路摄像头抓图AI检查',
131 146
     date: '2025-12-19',
147
+    start: '08:20',
132 148
     status: 'processable',
133 149
     department: '管理部',
134 150
   },
@@ -136,6 +152,7 @@ const tasks = ref([
136 152
     id: 18,
137 153
     name: '龙飞街摄像头抓图AI检查',
138 154
     date: '2025-12-19',
155
+    start: '09:05',
139 156
     status: 'processable',
140 157
     department: '管理部',
141 158
   },
@@ -143,6 +160,7 @@ const tasks = ref([
143 160
     id: 19,
144 161
     name: '大学路监控设备安装',
145 162
     date: '2025-12-19',
163
+    start: '10:00',
146 164
     status: 'not-started',
147 165
     department: '技术部',
148 166
   },
@@ -150,6 +168,7 @@ const tasks = ref([
150 168
     id: 20,
151 169
     name: '汝河路系统测试',
152 170
     date: '2025-12-19',
171
+    start: '11:10',
153 172
     status: 'cancelled',
154 173
     department: '质量部',
155 174
   },
@@ -157,6 +176,7 @@ const tasks = ref([
157 176
     id: 21,
158 177
     name: '未来路摄像头抓图AI检查',
159 178
     date: '2025-12-20',
179
+    start: '14:30',
160 180
     status: 'processable',
161 181
     department: '管理部',
162 182
   },
@@ -164,6 +184,7 @@ const tasks = ref([
164 184
     id: 22,
165 185
     name: '龙飞街摄像头抓图AI检查',
166 186
     date: '2025-12-20',
187
+    start: '15:00',
167 188
     status: 'processable',
168 189
     department: '管理部',
169 190
   },
@@ -171,6 +192,7 @@ const tasks = ref([
171 192
     id: 23,
172 193
     name: '航海路监控数据分析',
173 194
     date: '2025-12-20',
195
+    start: '09:00',
174 196
     status: 'completed',
175 197
     department: '数据分析部',
176 198
   },
@@ -178,6 +200,7 @@ const tasks = ref([
178 200
     id: 24,
179 201
     name: '长江路设备巡检',
180 202
     date: '2025-12-20',
203
+    start: '16:45',
181 204
     status: 'overdue',
182 205
     department: '运维部',
183 206
   },
@@ -185,6 +208,7 @@ const tasks = ref([
185 208
     id: 25,
186 209
     name: '未来路摄像头抓图AI检查',
187 210
     date: '2025-12-21',
211
+    start: '08:40',
188 212
     status: 'processable',
189 213
     department: '管理部',
190 214
   },
@@ -192,6 +216,7 @@ const tasks = ref([
192 216
     id: 26,
193 217
     name: '龙飞街摄像头抓图AI检查',
194 218
     date: '2025-12-21',
219
+    start: '09:25',
195 220
     status: 'processable',
196 221
     department: '管理部',
197 222
   },
@@ -199,6 +224,7 @@ const tasks = ref([
199 224
     id: 27,
200 225
     name: '嵩山路监控系统优化',
201 226
     date: '2025-12-21',
227
+    start: '10:50',
202 228
     status: 'not-started',
203 229
     department: '技术部',
204 230
   },
@@ -206,6 +232,7 @@ const tasks = ref([
206 232
     id: 28,
207 233
     name: '紫荆山路设备调试',
208 234
     date: '2025-12-21',
235
+    start: '11:30',
209 236
     status: 'completed',
210 237
     department: '技术部',
211 238
   },
@@ -213,6 +240,7 @@ const tasks = ref([
213 240
     id: 29,
214 241
     name: '商城路设备维护计划',
215 242
     date: '2025-12-21',
243
+    start: '13:05',
216 244
     status: 'overdue',
217 245
     department: '运维部',
218 246
   },
@@ -220,6 +248,7 @@ const tasks = ref([
220 248
     id: 30,
221 249
     name: '金水路交通管理培训',
222 250
     date: '2025-12-21',
251
+    start: '09:15',
223 252
     status: 'cancelled',
224 253
     department: '人力资源部',
225 254
   },
@@ -250,7 +279,7 @@ const getTaskStatusClass = (task) => {
250 279
 // Get tasks for a specific date
251 280
 const getTasksForDate = (date) => {
252 281
   const dateStr = date.toISOString().split('T')[0];
253
-  return tasks.value.filter(task => {
282
+  return tasks.value.filter((task) => {
254 283
     if (typeof task.date === 'string') {
255 284
       return task.date === dateStr;
256 285
     }
@@ -258,6 +287,22 @@ const getTasksForDate = (date) => {
258 287
   });
259 288
 };
260 289
 
290
+// 状态对应颜色(与其他视图保持一致)
291
+const statusColor = (status) => {
292
+  switch (status) {
293
+    case 'overdue':
294
+      return '#FF4D4F';
295
+    case 'completed':
296
+      return '#909399';
297
+    case 'processable':
298
+      return '#67C23A';
299
+    case 'not-started':
300
+    case 'cancelled':
301
+    default:
302
+      return '#CCCCCC';
303
+  }
304
+};
305
+
261 306
 // Set initial calendar value based on props
262 307
 const initialCalendarValue = computed(() => {
263 308
   if (props.month) {
@@ -271,39 +316,32 @@ const initialCalendarValue = computed(() => {
271 316
 
272 317
 <template>
273 318
   <div class="month-schedule">
274
-    <div class="status-legend">
275
-      <div class="legend-item">
276
-        <span class="status-indicator not-started"></span>
277
-        <span>灰色任务名:任务未开始/任务取消</span>
278
-      </div>
279
-      <div class="legend-item">
280
-        <span class="status-indicator processable"></span>
281
-        <span>黑色任务名:任务可处理</span>
282
-      </div>
283
-      <div class="legend-item">
284
-        <span class="status-indicator overdue"></span>
285
-        <span>红色任务名:任务过期未完成</span>
286
-      </div>
287
-      <div class="legend-item">
288
-        <span class="status-indicator completed"></span>
289
-        <span>黑色任务名:任务已完成</span>
290
-      </div>
291
-    </div>
292
-    
293
-    <ElCalendar :value="initialCalendarValue">
294
-      <template #header="{ date }">
295
-        <span></span>
296
-      </template>
319
+    <ElCalendar :model-value="initialCalendarValue">
297 320
       <template #date-cell="{ data }">
298 321
         <div class="calendar-cell">
322
+          <div class="cell-date-number">{{ data.date.getDate() }}</div>
299 323
           <div class="tasks-container">
300
-            <div 
301
-              v-for="task in getTasksForDate(data.date)" 
302
-              :key="task.id" 
324
+            <div
325
+              v-for="task in getTasksForDate(data.date)"
326
+              :key="task.id"
303 327
               class="task-item"
304 328
               :class="getTaskStatusClass(task)"
305 329
             >
306
-              <div class="task-name">{{ task.name }}</div>
330
+              <ElTooltip
331
+                :content="`${task.start ? task.start + ' ' : ''}${task.name}${task.department ? ' — ' + task.department : ''}`"
332
+                placement="top"
333
+              >
334
+                <div class="task-row">
335
+                  <span
336
+                    class="task-dot"
337
+                    :style="{ backgroundColor: statusColor(task.status) }"
338
+                  ></span>
339
+                  <span v-if="task.start || task.time" class="task-time">{{
340
+                    task.start || task.time
341
+                  }}</span>
342
+                  <span class="task-name">{{ task.name }}</span>
343
+                </div>
344
+              </ElTooltip>
307 345
             </div>
308 346
           </div>
309 347
         </div>
@@ -313,11 +351,37 @@ const initialCalendarValue = computed(() => {
313 351
 </template>
314 352
 
315 353
 <style scoped>
354
+:deep(.el-calendar__button-group) {
355
+  display: none;
356
+}
316 357
 .month-schedule {
317 358
   width: 100%;
318 359
   overflow-x: auto;
319 360
 }
320 361
 
362
+.calendar-cell {
363
+  position: relative;
364
+  height: 150px;
365
+  padding: 6px 6px 4px 6px;
366
+  box-sizing: border-box;
367
+  display: flex;
368
+  flex-direction: column;
369
+}
370
+
371
+.cell-date-number {
372
+  position: absolute;
373
+  top: 6px;
374
+  left: 8px;
375
+  font-size: 12px;
376
+  color: #666;
377
+  font-weight: 600;
378
+  z-index: 3;
379
+}
380
+
381
+.tasks-container {
382
+  margin-top: 22px;
383
+}
384
+
321 385
 .status-legend {
322 386
   display: flex;
323 387
   gap: 20px;
@@ -405,9 +469,29 @@ const initialCalendarValue = computed(() => {
405 469
 }
406 470
 
407 471
 .task-name {
472
+  font-size: 12px;
473
+  line-height: 1.2;
474
+  text-overflow: ellipsis;
475
+  overflow: hidden;
476
+  white-space: nowrap;
477
+}
478
+
479
+.task-row {
480
+  display: flex;
481
+  align-items: center;
482
+  gap: 4px;
483
+}
484
+.task-dot {
485
+  width: 8px;
486
+  height: 8px;
487
+  border-radius: 50%;
488
+  flex: 0 0 8px;
489
+}
490
+.task-time {
408 491
   font-size: 11px;
409
-  line-height: 1.3;
410
-  text-align: center;
492
+  color: #666;
493
+  width: 40px;
494
+  flex: 0 0 40px;
411 495
 }
412 496
 
413 497
 /* Task status styles */

+ 2 - 21
apps/web-ele/src/views/schedule/view/components/week/index.vue

@@ -300,25 +300,6 @@ const hexToRgba = (hex, alpha = 0.08) => {
300 300
 </script>
301 301
 <template>
302 302
   <div class="week-schedule">
303
-    <div class="status-legend">
304
-      <div class="legend-item">
305
-        <span class="status-indicator not-started"></span>
306
-        <span>灰色任务名:任务未开始/任务取消</span>
307
-      </div>
308
-      <div class="legend-item">
309
-        <span class="status-indicator processable"></span>
310
-        <span>黑色任务名:任务可处理</span>
311
-      </div>
312
-      <div class="legend-item">
313
-        <span class="status-indicator overdue"></span>
314
-        <span>红色任务名:任务过期未完成</span>
315
-      </div>
316
-      <div class="legend-item">
317
-        <span class="status-indicator completed"></span>
318
-        <span>黑色任务名:任务已完成</span>
319
-      </div>
320
-    </div>
321
-
322 303
     <div class="calendar">
323 304
       <div class="time-column">
324 305
         <div class="time-header">&nbsp;</div>
@@ -333,14 +314,14 @@ const hexToRgba = (hex, alpha = 0.08) => {
333 314
           </div>
334 315
         </div>
335 316
         <!-- 横向小时网格覆盖层(跨列) -->
336
-        <div class="hours-overlay">
317
+        <!-- <div class="hours-overlay">
337 318
           <div
338 319
             v-for="(h, i) in hours"
339 320
             :key="h"
340 321
             class="hours-line"
341 322
             :style="{ height: hourHeight + 'px' }"
342 323
           ></div>
343
-        </div>
324
+        </div> -->
344 325
         <div class="days-body">
345 326
           <div v-for="day in weekDays" :key="day.date" class="day-column">
346 327
             <div class="day-body-inner">

+ 2 - 0
apps/web-ele/src/views/schedule/view/index.vue

@@ -160,6 +160,8 @@ const nextMonth = () => {
160 160
 
161 161
 // 选择日期
162 162
 const selectDate = (date: string) => {
163
+  console.log(date);
164
+  
163 165
   searchParams.value.date = date;
164 166
 };
165 167