vue3-admin-gpt 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.env.development +14 -0
  2. package/.env.production +14 -0
  3. package/LICENSE +21 -0
  4. package/README.en.md +106 -0
  5. package/README.md +104 -0
  6. package/build-zip.cjs +53 -0
  7. package/cli.js +110 -0
  8. package/jsconfig.json +9 -0
  9. package/package.json +92 -0
  10. package/public/index.html +20 -0
  11. package/public/robots.txt +2 -0
  12. package/rspack.config.js +282 -0
  13. package/rspack.js +162 -0
  14. package/src/App.vue +9 -0
  15. package/src/api/icon.js +9 -0
  16. package/src/api/router.js +9 -0
  17. package/src/api/table.js +25 -0
  18. package/src/api/tree.js +9 -0
  19. package/src/api/user.js +34 -0
  20. package/src/assets/error_images/401.png +0 -0
  21. package/src/assets/error_images/404.png +0 -0
  22. package/src/assets/error_images/cloud.png +0 -0
  23. package/src/assets/login_images/background.jpg +0 -0
  24. package/src/assets/logo.png +0 -0
  25. package/src/assets/qr_logo/lqr_logo.png +0 -0
  26. package/src/assets/vuejs-fill.svg +4 -0
  27. package/src/components/VabPageHeader/index.vue +133 -0
  28. package/src/config/index.js +7 -0
  29. package/src/config/net.config.js +20 -0
  30. package/src/config/permission.js +136 -0
  31. package/src/config/setting.config.js +62 -0
  32. package/src/config/settings.js +6 -0
  33. package/src/config/theme.config.js +14 -0
  34. package/src/layouts/EmptyLayout.vue +3 -0
  35. package/src/layouts/components/VabAppMain/index.vue +109 -0
  36. package/src/layouts/components/VabAvatar/index.vue +255 -0
  37. package/src/layouts/components/VabBreadcrumb/index.vue +61 -0
  38. package/src/layouts/components/VabFullScreen/index.vue +61 -0
  39. package/src/layouts/components/VabLogo/index.vue +94 -0
  40. package/src/layouts/components/VabNav/index.vue +176 -0
  41. package/src/layouts/components/VabSide/components/VabMenuItem.vue +80 -0
  42. package/src/layouts/components/VabSide/components/VabSideItem.vue +100 -0
  43. package/src/layouts/components/VabSide/components/VabSubmenu.vue +56 -0
  44. package/src/layouts/components/VabSide/index.vue +123 -0
  45. package/src/layouts/components/VabTabs/index.vue +500 -0
  46. package/src/layouts/components/VabTheme/index.vue +603 -0
  47. package/src/layouts/components/VabTop/index.vue +286 -0
  48. package/src/layouts/export.js +29 -0
  49. package/src/layouts/index.vue +339 -0
  50. package/src/main.js +40 -0
  51. package/src/plugins/echarts.js +4 -0
  52. package/src/plugins/index.js +44 -0
  53. package/src/plugins/support.js +16 -0
  54. package/src/router/index.js +400 -0
  55. package/src/store/index.js +26 -0
  56. package/src/store/modules/errorLog.js +27 -0
  57. package/src/store/modules/routes.js +60 -0
  58. package/src/store/modules/settings.js +73 -0
  59. package/src/store/modules/table.js +22 -0
  60. package/src/store/modules/tabsBar.js +109 -0
  61. package/src/store/modules/user.js +131 -0
  62. package/src/styles/element-variables.scss +13 -0
  63. package/src/styles/loading.scss +345 -0
  64. package/src/styles/nav-icons.scss +52 -0
  65. package/src/styles/normalize.scss +353 -0
  66. package/src/styles/spinner/dots.css +68 -0
  67. package/src/styles/spinner/gauge.css +104 -0
  68. package/src/styles/spinner/inner-circles.css +51 -0
  69. package/src/styles/spinner/plus.css +341 -0
  70. package/src/styles/themes/default.scss +1 -0
  71. package/src/styles/transition.scss +18 -0
  72. package/src/styles/vab.scss +476 -0
  73. package/src/styles/variables.scss +69 -0
  74. package/src/utils/accessToken.js +56 -0
  75. package/src/utils/eventBus.js +8 -0
  76. package/src/utils/handleRoutes.js +100 -0
  77. package/src/utils/index.js +231 -0
  78. package/src/utils/message.js +67 -0
  79. package/src/utils/pageTitle.js +11 -0
  80. package/src/utils/password.js +43 -0
  81. package/src/utils/permission.js +19 -0
  82. package/src/utils/request.js +187 -0
  83. package/src/utils/static.js +81 -0
  84. package/src/utils/vab.js +218 -0
  85. package/src/utils/validate.js +48 -0
  86. package/src/views/401.vue +302 -0
  87. package/src/views/404.vue +302 -0
  88. package/src/views/demo/index.vue +591 -0
  89. package/src/views/index/index.vue +1489 -0
  90. package/src/views/login/index.vue +456 -0
  91. package/src/views/register/index.vue +524 -0
  92. package/src/views/vab/calendar.vue +488 -0
  93. package/src/views/vab/campaign.vue +1006 -0
  94. package/src/views/vab/chart.vue +189 -0
  95. package/src/views/vab/customer.vue +666 -0
  96. package/src/views/vab/editor.vue +84 -0
  97. package/src/views/vab/form.vue +151 -0
  98. package/src/views/vab/help.vue +390 -0
  99. package/src/views/vab/icon.vue +113 -0
  100. package/src/views/vab/knowledge.vue +820 -0
  101. package/src/views/vab/nested/menu1/menu2/menu3.vue +29 -0
  102. package/src/views/vab/nested/menu1/menu2.vue +33 -0
  103. package/src/views/vab/nested/menu1.vue +33 -0
  104. package/src/views/vab/nested.vue +97 -0
  105. package/src/views/vab/notification.vue +416 -0
  106. package/src/views/vab/order.vue +507 -0
  107. package/src/views/vab/permissions.vue +214 -0
  108. package/src/views/vab/product.vue +724 -0
  109. package/src/views/vab/project.vue +559 -0
  110. package/src/views/vab/settings.vue +319 -0
  111. package/src/views/vab/statistics.vue +431 -0
  112. package/src/views/vab/table.vue +110 -0
  113. package/src/views/vab/task.vue +613 -0
  114. package/src/views/vab/team.vue +662 -0
  115. package/src/views/vab/tree.vue +44 -0
  116. package/src/views/vab/upload.vue +180 -0
  117. package/src/views/vab/vue3Demo/index.vue +103 -0
  118. package/src/views/vab/workflow.vue +863 -0
@@ -0,0 +1,613 @@
1
+ <template>
2
+ <div class="task-container">
3
+ <el-card shadow="never">
4
+ <template #header>
5
+ <div class="card-header">
6
+ <span>任务管理</span>
7
+ <div class="header-actions">
8
+ <el-input
9
+ v-model="searchText"
10
+ placeholder="搜索任务..."
11
+ clearable
12
+ style="width: 200px; margin-right: 10px"
13
+ >
14
+ <template #prefix>
15
+ <el-icon><Search /></el-icon>
16
+ </template>
17
+ </el-input>
18
+ <el-select
19
+ v-model="filterStatus"
20
+ placeholder="状态筛选"
21
+ style="width: 120px; margin-right: 10px"
22
+ >
23
+ <el-option label="全部" value=""></el-option>
24
+ <el-option label="待办" value="pending"></el-option>
25
+ <el-option label="进行中" value="in-progress"></el-option>
26
+ <el-option label="已完成" value="completed"></el-option>
27
+ </el-select>
28
+ <el-button type="primary" @click="showAddTaskDialog">添加任务</el-button>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <el-tabs v-model="activeTab" @tab-change="handleTabChange">
34
+ <el-tab-pane label="全部任务" name="all">
35
+ <el-table
36
+ :data="filteredTasks"
37
+ style="width: 100%"
38
+ row-key="id"
39
+ v-loading="loading"
40
+ >
41
+ <el-table-column prop="title" label="任务标题" min-width="200">
42
+ <template #default="{ row }">
43
+ <div class="task-title">
44
+ <el-checkbox
45
+ v-model="row.completed"
46
+ @change="toggleTaskStatus(row)"
47
+ ></el-checkbox>
48
+ <span
49
+ :class="{ 'completed-task': row.completed }"
50
+ style="margin-left: 10px"
51
+ >
52
+ {{ row.title }}
53
+ </span>
54
+ </div>
55
+ </template>
56
+ </el-table-column>
57
+ <el-table-column prop="description" label="描述" min-width="200">
58
+ <template #default="{ row }">
59
+ <div class="task-description">{{ row.description }}</div>
60
+ </template>
61
+ </el-table-column>
62
+ <el-table-column label="状态" width="100">
63
+ <template #default="{ row }">
64
+ <el-tag :type="getStatusType(row.status)">
65
+ {{ getStatusText(row.status) }}
66
+ </el-tag>
67
+ </template>
68
+ </el-table-column>
69
+ <el-table-column prop="assignee" label="负责人" width="120" />
70
+ <el-table-column prop="dueDate" label="截止日期" width="120" />
71
+ <el-table-column prop="priority" label="优先级" width="100">
72
+ <template #default="{ row }">
73
+ <el-tag :type="getPriorityType(row.priority)">
74
+ {{ getPriorityText(row.priority) }}
75
+ </el-tag>
76
+ </template>
77
+ </el-table-column>
78
+ <el-table-column label="操作" width="200">
79
+ <template #default="{ row }">
80
+ <el-button type="text" @click="editTask(row)">编辑</el-button>
81
+ <el-button type="text" @click="viewTask(row)">查看</el-button>
82
+ <el-button type="text" @click="deleteTask(row)">删除</el-button>
83
+ </template>
84
+ </el-table-column>
85
+ </el-table>
86
+ </el-tab-pane>
87
+
88
+ <el-tab-pane label="待办任务" name="pending">
89
+ <el-table
90
+ :data="pendingTasks"
91
+ style="width: 100%"
92
+ row-key="id"
93
+ >
94
+ <el-table-column prop="title" label="任务标题" min-width="200">
95
+ <template #default="{ row }">
96
+ <div class="task-title">
97
+ <el-checkbox
98
+ v-model="row.completed"
99
+ @change="toggleTaskStatus(row)"
100
+ ></el-checkbox>
101
+ <span style="margin-left: 10px">{{ row.title }}</span>
102
+ </div>
103
+ </template>
104
+ </el-table-column>
105
+ <el-table-column prop="description" label="描述" min-width="200" />
106
+ <el-table-column prop="assignee" label="负责人" width="120" />
107
+ <el-table-column prop="dueDate" label="截止日期" width="120" />
108
+ <el-table-column label="优先级" width="100">
109
+ <template #default="{ row }">
110
+ <el-tag :type="getPriorityType(row.priority)">
111
+ {{ getPriorityText(row.priority) }}
112
+ </el-tag>
113
+ </template>
114
+ </el-table-column>
115
+ <el-table-column label="操作" width="150">
116
+ <template #default="{ row }">
117
+ <el-button type="text" @click="editTask(row)">编辑</el-button>
118
+ <el-button type="text" @click="startTask(row)">开始</el-button>
119
+ </template>
120
+ </el-table-column>
121
+ </el-table>
122
+ </el-tab-pane>
123
+
124
+ <el-tab-pane label="进行中任务" name="in-progress">
125
+ <el-table
126
+ :data="inProgressTasks"
127
+ style="width: 100%"
128
+ row-key="id"
129
+ >
130
+ <el-table-column prop="title" label="任务标题" min-width="200" />
131
+ <el-table-column prop="description" label="描述" min-width="200" />
132
+ <el-table-column prop="assignee" label="负责人" width="120" />
133
+ <el-table-column prop="startDate" label="开始日期" width="120" />
134
+ <el-table-column prop="dueDate" label="截止日期" width="120" />
135
+ <el-table-column label="优先级" width="100">
136
+ <template #default="{ row }">
137
+ <el-tag :type="getPriorityType(row.priority)">
138
+ {{ getPriorityText(row.priority) }}
139
+ </el-tag>
140
+ </template>
141
+ </el-table-column>
142
+ <el-table-column label="操作" width="150">
143
+ <template #default="{ row }">
144
+ <el-button type="text" @click="editTask(row)">编辑</el-button>
145
+ <el-button type="text" @click="completeTask(row)">完成</el-button>
146
+ </template>
147
+ </el-table-column>
148
+ </el-table>
149
+ </el-tab-pane>
150
+
151
+ <el-tab-pane label="已完成任务" name="completed">
152
+ <el-table
153
+ :data="completedTasks"
154
+ style="width: 100%"
155
+ row-key="id"
156
+ >
157
+ <el-table-column prop="title" label="任务标题" min-width="200" />
158
+ <el-table-column prop="description" label="描述" min-width="200" />
159
+ <el-table-column prop="assignee" label="负责人" width="120" />
160
+ <el-table-column prop="completedDate" label="完成日期" width="120" />
161
+ <el-table-column label="操作" width="100">
162
+ <template #default="{ row }">
163
+ <el-button type="text" @click="viewTask(row)">查看</el-button>
164
+ </template>
165
+ </el-table-column>
166
+ </el-table>
167
+ </el-tab-pane>
168
+ </el-tabs>
169
+
170
+ <div class="pagination-container">
171
+ <el-pagination
172
+ v-model:current-page="currentPage"
173
+ v-model:page-size="pageSize"
174
+ :page-sizes="[10, 20, 50, 100]"
175
+ :total="totalTasks"
176
+ layout="total, sizes, prev, pager, next, jumper"
177
+ @size-change="handleSizeChange"
178
+ @current-change="handleCurrentChange"
179
+ />
180
+ </div>
181
+ </el-card>
182
+
183
+ <!-- 添加/编辑任务对话框 -->
184
+ <el-dialog
185
+ v-model="taskDialogVisible"
186
+ :title="editingTask ? '编辑任务' : '添加任务'"
187
+ width="600px"
188
+ >
189
+ <el-form
190
+ ref="taskFormRef"
191
+ :model="taskForm"
192
+ :rules="taskRules"
193
+ label-width="100px"
194
+ >
195
+ <el-form-item label="任务标题" prop="title">
196
+ <el-input v-model="taskForm.title" />
197
+ </el-form-item>
198
+
199
+ <el-form-item label="任务描述" prop="description">
200
+ <el-input
201
+ v-model="taskForm.description"
202
+ type="textarea"
203
+ :rows="3"
204
+ />
205
+ </el-form-item>
206
+
207
+ <el-form-item label="负责人" prop="assignee">
208
+ <el-select v-model="taskForm.assignee" placeholder="请选择负责人" style="width: 100%">
209
+ <el-option
210
+ v-for="user in users"
211
+ :key="user.id"
212
+ :label="user.name"
213
+ :value="user.name"
214
+ />
215
+ </el-select>
216
+ </el-form-item>
217
+
218
+ <el-form-item label="截止日期" prop="dueDate">
219
+ <el-date-picker
220
+ v-model="taskForm.dueDate"
221
+ type="date"
222
+ placeholder="选择截止日期"
223
+ format="YYYY年MM月DD日"
224
+ value-format="YYYY-MM-DD"
225
+ style="width: 100%"
226
+ />
227
+ </el-form-item>
228
+
229
+ <el-form-item label="优先级" prop="priority">
230
+ <el-select v-model="taskForm.priority" placeholder="请选择优先级" style="width: 100%">
231
+ <el-option label="低" value="low"></el-option>
232
+ <el-option label="中" value="medium"></el-option>
233
+ <el-option label="高" value="high"></el-option>
234
+ </el-select>
235
+ </el-form-item>
236
+
237
+ <el-form-item label="状态" prop="status">
238
+ <el-select v-model="taskForm.status" placeholder="请选择状态" style="width: 100%">
239
+ <el-option label="待办" value="pending"></el-option>
240
+ <el-option label="进行中" value="in-progress"></el-option>
241
+ <el-option label="已完成" value="completed"></el-option>
242
+ </el-select>
243
+ </el-form-item>
244
+ </el-form>
245
+
246
+ <template #footer>
247
+ <span class="dialog-footer">
248
+ <el-button @click="taskDialogVisible = false">取消</el-button>
249
+ <el-button
250
+ type="primary"
251
+ @click="saveTask"
252
+ >
253
+ 保存
254
+ </el-button>
255
+ </span>
256
+ </template>
257
+ </el-dialog>
258
+
259
+ <!-- 任务详情对话框 -->
260
+ <el-dialog
261
+ v-model="detailDialogVisible"
262
+ title="任务详情"
263
+ width="600px"
264
+ >
265
+ <el-descriptions :column="1" border>
266
+ <el-descriptions-item label="任务标题">{{ detailTask.title }}</el-descriptions-item>
267
+ <el-descriptions-item label="任务描述">{{ detailTask.description }}</el-descriptions-item>
268
+ <el-descriptions-item label="负责人">{{ detailTask.assignee }}</el-descriptions-item>
269
+ <el-descriptions-item label="状态">
270
+ <el-tag :type="getStatusType(detailTask.status)">
271
+ {{ getStatusText(detailTask.status) }}
272
+ </el-tag>
273
+ </el-descriptions-item>
274
+ <el-descriptions-item label="优先级">
275
+ <el-tag :type="getPriorityType(detailTask.priority)">
276
+ {{ getPriorityText(detailTask.priority) }}
277
+ </el-tag>
278
+ </el-descriptions-item>
279
+ <el-descriptions-item label="创建日期">{{ detailTask.createDate }}</el-descriptions-item>
280
+ <el-descriptions-item label="截止日期">{{ detailTask.dueDate }}</el-descriptions-item>
281
+ <el-descriptions-item v-if="detailTask.startDate" label="开始日期">{{ detailTask.startDate }}</el-descriptions-item>
282
+ <el-descriptions-item v-if="detailTask.completedDate" label="完成日期">{{ detailTask.completedDate }}</el-descriptions-item>
283
+ </el-descriptions>
284
+
285
+ <template #footer>
286
+ <span class="dialog-footer">
287
+ <el-button @click="detailDialogVisible = false">关闭</el-button>
288
+ </span>
289
+ </template>
290
+ </el-dialog>
291
+ </div>
292
+ </template>
293
+
294
+ <script>
295
+ import { Search } from "@element-plus/icons-vue";
296
+
297
+ export default {
298
+ name: "Task",
299
+ components: {
300
+ Search
301
+ },
302
+ data() {
303
+ return {
304
+ activeTab: "all",
305
+ searchText: "",
306
+ filterStatus: "",
307
+ currentPage: 1,
308
+ pageSize: 10,
309
+ totalTasks: 0,
310
+ loading: false,
311
+ taskDialogVisible: false,
312
+ detailDialogVisible: false,
313
+ editingTask: null,
314
+ tasks: [
315
+ {
316
+ id: 1,
317
+ title: "设计新功能界面",
318
+ description: "为新功能模块设计用户界面,包括主要页面布局和交互流程",
319
+ assignee: "张三",
320
+ status: "pending",
321
+ priority: "high",
322
+ createDate: "2023-05-01",
323
+ dueDate: "2023-05-20"
324
+ },
325
+ {
326
+ id: 2,
327
+ title: "开发用户认证模块",
328
+ description: "实现用户注册、登录、权限验证等功能",
329
+ assignee: "李四",
330
+ status: "in-progress",
331
+ priority: "high",
332
+ createDate: "2023-05-02",
333
+ dueDate: "2023-05-25",
334
+ startDate: "2023-05-10"
335
+ },
336
+ {
337
+ id: 3,
338
+ title: "编写API文档",
339
+ description: "为已开发的API接口编写详细文档",
340
+ assignee: "王五",
341
+ status: "completed",
342
+ priority: "medium",
343
+ createDate: "2023-04-28",
344
+ dueDate: "2023-05-10",
345
+ completedDate: "2023-05-09"
346
+ },
347
+ {
348
+ id: 4,
349
+ title: "测试系统性能",
350
+ description: "对系统进行压力测试,找出性能瓶颈",
351
+ assignee: "赵六",
352
+ status: "pending",
353
+ priority: "medium",
354
+ createDate: "2023-05-05",
355
+ dueDate: "2023-05-30"
356
+ },
357
+ {
358
+ id: 5,
359
+ title: "修复已知bug",
360
+ description: "修复用户反馈的几个重要bug",
361
+ assignee: "钱七",
362
+ status: "in-progress",
363
+ priority: "high",
364
+ createDate: "2023-05-03",
365
+ dueDate: "2023-05-18",
366
+ startDate: "2023-05-12"
367
+ }
368
+ ],
369
+ users: [
370
+ { id: 1, name: "张三" },
371
+ { id: 2, name: "李四" },
372
+ { id: 3, name: "王五" },
373
+ { id: 4, name: "赵六" },
374
+ { id: 5, name: "钱七" }
375
+ ],
376
+ taskForm: {
377
+ title: "",
378
+ description: "",
379
+ assignee: "",
380
+ dueDate: "",
381
+ priority: "medium",
382
+ status: "pending"
383
+ },
384
+ detailTask: {},
385
+ taskRules: {
386
+ title: [
387
+ { required: true, message: "请输入任务标题", trigger: "blur" }
388
+ ],
389
+ assignee: [
390
+ { required: true, message: "请选择负责人", trigger: "change" }
391
+ ],
392
+ dueDate: [
393
+ { required: true, message: "请选择截止日期", trigger: "change" }
394
+ ]
395
+ }
396
+ };
397
+ },
398
+ computed: {
399
+ filteredTasks() {
400
+ let result = this.tasks;
401
+
402
+ // 搜索过滤
403
+ if (this.searchText) {
404
+ result = result.filter(task =>
405
+ task.title.toLowerCase().includes(this.searchText.toLowerCase()) ||
406
+ task.description.toLowerCase().includes(this.searchText.toLowerCase())
407
+ );
408
+ }
409
+
410
+ // 状态过滤
411
+ if (this.filterStatus) {
412
+ result = result.filter(task => task.status === this.filterStatus);
413
+ }
414
+
415
+ // 分页处理
416
+ const start = (this.currentPage - 1) * this.pageSize;
417
+ const end = start + this.pageSize;
418
+ return result.slice(start, end);
419
+ },
420
+ pendingTasks() {
421
+ return this.tasks.filter(task => task.status === "pending");
422
+ },
423
+ inProgressTasks() {
424
+ return this.tasks.filter(task => task.status === "in-progress");
425
+ },
426
+ completedTasks() {
427
+ return this.tasks.filter(task => task.status === "completed");
428
+ }
429
+ },
430
+ methods: {
431
+ handleTabChange(tab) {
432
+ this.activeTab = tab;
433
+ this.currentPage = 1;
434
+ },
435
+ handleSizeChange(val) {
436
+ this.pageSize = val;
437
+ this.currentPage = 1;
438
+ },
439
+ handleCurrentChange(val) {
440
+ this.currentPage = val;
441
+ },
442
+ getStatusText(status) {
443
+ const statusMap = {
444
+ "pending": "待办",
445
+ "in-progress": "进行中",
446
+ "completed": "已完成"
447
+ };
448
+ return statusMap[status] || status;
449
+ },
450
+ getStatusType(status) {
451
+ const typeMap = {
452
+ "pending": "info",
453
+ "in-progress": "warning",
454
+ "completed": "success"
455
+ };
456
+ return typeMap[status] || "info";
457
+ },
458
+ getPriorityText(priority) {
459
+ const priorityMap = {
460
+ "low": "低",
461
+ "medium": "中",
462
+ "high": "高"
463
+ };
464
+ return priorityMap[priority] || priority;
465
+ },
466
+ getPriorityType(priority) {
467
+ const typeMap = {
468
+ "low": "info",
469
+ "medium": "",
470
+ "high": "danger"
471
+ };
472
+ return typeMap[priority] || "info";
473
+ },
474
+ showAddTaskDialog() {
475
+ this.editingTask = null;
476
+ this.taskForm = {
477
+ title: "",
478
+ description: "",
479
+ assignee: "",
480
+ dueDate: "",
481
+ priority: "medium",
482
+ status: "pending"
483
+ };
484
+ this.taskDialogVisible = true;
485
+ this.$nextTick(() => {
486
+ this.$refs.taskFormRef.resetFields();
487
+ });
488
+ },
489
+ editTask(task) {
490
+ this.editingTask = task;
491
+ this.taskForm = { ...task };
492
+ this.taskDialogVisible = true;
493
+ },
494
+ viewTask(task) {
495
+ this.detailTask = { ...task };
496
+ this.detailDialogVisible = true;
497
+ },
498
+ deleteTask(task) {
499
+ this.$confirm(`确定要删除任务"${task.title}"吗?`, "提示", {
500
+ confirmButtonText: "确定",
501
+ cancelButtonText: "取消",
502
+ type: "warning"
503
+ }).then(() => {
504
+ const index = this.tasks.findIndex(t => t.id === task.id);
505
+ if (index !== -1) {
506
+ this.tasks.splice(index, 1);
507
+ this.totalTasks = this.tasks.length;
508
+ this.$message.success("任务删除成功");
509
+ }
510
+ }).catch(() => {
511
+ this.$message.info("已取消删除");
512
+ });
513
+ },
514
+ saveTask() {
515
+ this.$refs.taskFormRef.validate((valid) => {
516
+ if (valid) {
517
+ if (this.editingTask) {
518
+ // 编辑任务
519
+ const index = this.tasks.findIndex(t => t.id === this.editingTask.id);
520
+ if (index !== -1) {
521
+ this.tasks[index] = { ...this.editingTask, ...this.taskForm };
522
+ this.$message.success("任务更新成功");
523
+ }
524
+ } else {
525
+ // 添加任务
526
+ const newTask = {
527
+ id: Date.now(),
528
+ createDate: this.formatDate(new Date()),
529
+ ...this.taskForm
530
+ };
531
+ this.tasks.push(newTask);
532
+ this.totalTasks = this.tasks.length;
533
+ this.$message.success("任务添加成功");
534
+ }
535
+ this.taskDialogVisible = false;
536
+ }
537
+ });
538
+ },
539
+ toggleTaskStatus(task) {
540
+ const index = this.tasks.findIndex(t => t.id === task.id);
541
+ if (index !== -1) {
542
+ if (task.completed) {
543
+ this.tasks[index].status = "completed";
544
+ this.tasks[index].completedDate = this.formatDate(new Date());
545
+ } else {
546
+ this.tasks[index].status = "pending";
547
+ delete this.tasks[index].completedDate;
548
+ }
549
+ this.$message.success("任务状态已更新");
550
+ }
551
+ },
552
+ startTask(task) {
553
+ const index = this.tasks.findIndex(t => t.id === task.id);
554
+ if (index !== -1) {
555
+ this.tasks[index].status = "in-progress";
556
+ this.tasks[index].startDate = this.formatDate(new Date());
557
+ this.$message.success("任务已开始");
558
+ }
559
+ },
560
+ completeTask(task) {
561
+ const index = this.tasks.findIndex(t => t.id === task.id);
562
+ if (index !== -1) {
563
+ this.tasks[index].status = "completed";
564
+ this.tasks[index].completedDate = this.formatDate(new Date());
565
+ this.$message.success("任务已完成");
566
+ }
567
+ },
568
+ formatDate(date) {
569
+ const d = new Date(date);
570
+ const year = d.getFullYear();
571
+ const month = String(d.getMonth() + 1).padStart(2, '0');
572
+ const day = String(d.getDate()).padStart(2, '0');
573
+ return `${year}-${month}-${day}`;
574
+ }
575
+ }
576
+ };
577
+ </script>
578
+
579
+ <style lang="scss" scoped>
580
+ .task-container {
581
+ padding: 20px;
582
+
583
+ .card-header {
584
+ display: flex;
585
+ justify-content: space-between;
586
+ align-items: center;
587
+ font-weight: bold;
588
+ }
589
+
590
+ .task-title {
591
+ display: flex;
592
+ align-items: center;
593
+ }
594
+
595
+ .completed-task {
596
+ text-decoration: line-through;
597
+ color: #909399;
598
+ }
599
+
600
+ .task-description {
601
+ display: -webkit-box;
602
+ -webkit-box-orient: vertical;
603
+ -webkit-line-clamp: 2;
604
+ overflow: hidden;
605
+ text-overflow: ellipsis;
606
+ }
607
+
608
+ .pagination-container {
609
+ margin-top: 20px;
610
+ text-align: right;
611
+ }
612
+ }
613
+ </style>