feat: 任务分类页面增加草稿箱功能(需求部门可见)

This commit is contained in:
Your Name 2026-01-17 10:36:30 +08:00
parent 166bf76ede
commit 1a74426e56

View File

@ -2114,6 +2114,122 @@
/>
</div>
</a-tab-pane>
<!-- 草稿箱标签页(仅需求部门用户可见) -->
<a-tab-pane key="drafts" v-if="showDraftTab">
<template #tab>
<span>草稿箱 <span class="tab-count">({{ draftsTotal }})</span></span>
</template>
<div class="search-filter-bar chart-card">
<div class="search-row">
<a-input-search
v-model:value="draftsFilters.keyword"
placeholder="搜索草稿任务..."
style="width: 300px;"
@search="loadDraftTasks"
allow-clear
/>
<div class="filter-group">
<span class="filter-label">排序:</span>
<a-select v-model:value="draftsFilters.sortBy" style="width: 120px;" @change="loadDraftTasks">
<a-select-option value="latest">最新创建</a-select-option>
<a-select-option value="oldest">最早创建</a-select-option>
</a-select>
</div>
<div class="stats-info">
<span class="stat-item">共 <span class="stat-value">{{ draftsTotal }}</span> 个草稿</span>
</div>
</div>
</div>
<!-- 草稿列表 -->
<div v-if="draftsLoading" class="loading-container">
<a-spin size="large" />
</div>
<div v-else-if="draftTaskList.length === 0" class="empty-state chart-card">
<Icon name="file" size="3xl" color="#666" />
<p>暂无草稿任务</p>
<p class="empty-hint">发布任务时可以保存为草稿,稍后继续编辑</p>
</div>
<div v-else class="task-grid">
<div
v-for="task in draftTaskList"
:key="task.id"
class="task-card chart-card"
@click="handleEditDraftTask(task)"
>
<!-- 草稿标签 -->
<div class="task-badge-container">
<span class="task-badge draft-badge">草稿</span>
</div>
<!-- 任务标题 -->
<div class="task-header">
<h3 class="task-title">{{ task.title || '未命名任务' }}</h3>
</div>
<!-- 任务信息 -->
<div class="task-details">
<div class="detail-item" v-if="task.taskNo">
<span class="icon"><Icon name="hash" size="sm" color="#31f08b" /></span>
<span>{{ task.taskNo }}</span>
</div>
<div class="detail-item" v-if="task.brandName">
<span class="icon"><Icon name="tag" size="sm" color="#31f08b" /></span>
<span>品牌: {{ task.brandName }}</span>
</div>
<div class="detail-item" v-if="task.categoryName">
<span class="icon"><Icon name="folder" size="sm" color="#31f08b" /></span>
<span>类目: {{ task.categoryName }}</span>
</div>
<div class="detail-item">
<span class="icon"><Icon name="clock" size="sm" color="#31f08b" /></span>
<span>创建: {{ formatDate(task.createTime) }}</span>
</div>
<div class="detail-item" v-if="task.updateTime">
<span class="icon"><Icon name="edit" size="sm" color="#31f08b" /></span>
<span>最后编辑: {{ formatDate(task.updateTime) }}</span>
</div>
</div>
<!-- 操作按钮 -->
<div class="task-actions" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid rgba(49, 240, 139, 0.2);">
<div style="display: flex; gap: 8px;">
<a-button
type="primary"
size="small"
@click.stop="handleEditDraftTask(task)"
style="flex: 1;">
<Icon name="edit" size="sm" style="margin-right: 4px;" />
继续编辑
</a-button>
<a-button
type="default"
danger
size="small"
@click.stop="handleDeleteDraft(task)"
style="width: 80px;">
<Icon name="trash" size="sm" style="margin-right: 4px;" />
删除
</a-button>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div v-if="draftsTotal > 0" class="pagination">
<a-pagination
v-model:current="draftsPagination.page"
v-model:page-size="draftsPagination.pageSize"
:total="draftsTotal"
:show-size-changer="false"
@change="handleDraftsPageChange"
/>
</div>
</a-tab-pane>
</a-tabs>
</div>
@ -2803,6 +2919,9 @@ const handleDeptViewChange = (deptId: number | null) => {
case 'review':
loadReviewTasks()
break
case 'drafts':
loadDraftTasks()
break
}
}, 0) // 使用 setTimeout 确保 effectiveDeptType 已更新
}
@ -2838,6 +2957,18 @@ const publishedLoading = ref(false)
const publishedTaskList = ref<Task[]>([])
const publishedTotal = ref(0)
// 草稿箱状态
const draftsLoading = ref(false)
const draftTaskList = ref<Task[]>([])
const draftsTotal = ref(0)
// 是否显示草稿箱tab(仅需求部门用户可见)
const showDraftTab = computed(() => {
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}')
// 需求部门用户或管理员可以看到草稿箱
return userDeptType.value === 'demand' || userInfo.isAdmin === 1 || userInfo.isAdmin === true
})
// 进行中任务状态
const inProgressLoading = ref(false)
const inProgressTaskList = ref<Task[]>([])
@ -3033,6 +3164,12 @@ const publishedFilters = reactive({
maxScore: undefined as number | undefined
})
// 草稿箱筛选条件
const draftsFilters = reactive({
keyword: undefined as string | undefined,
sortBy: 'latest' as 'latest' | 'oldest'
})
// 进行中任务筛选条件
const inProgressFilters = reactive({
keyword: undefined as string | undefined,
@ -4395,6 +4532,12 @@ const publishedPagination = reactive({
pageSize: 10
})
// 草稿箱分页
const draftsPagination = reactive({
page: 1,
pageSize: 12
})
// 进行中任务分页
const inProgressPagination = reactive({
page: 1,
@ -4437,6 +4580,76 @@ const handlePublishedPageChange = (page: number) => {
loadPublishedTasks()
}
// 加载草稿箱任务
const loadDraftTasks = async () => {
draftsLoading.value = true
try {
const response = await taskApi.getMyTasks({
role: 'publisher',
status: 'draft', // 只查询草稿状态的任务
keyword: draftsFilters.keyword || undefined,
page: draftsPagination.page,
pageSize: draftsPagination.pageSize,
sortBy: draftsFilters.sortBy
})
if (response.code === 200) {
draftTaskList.value = response.data.records || []
draftsTotal.value = response.data.total || 0
}
} catch (error) {
console.error('加载草稿任务失败:', error)
message.error('加载草稿失败')
} finally {
draftsLoading.value = false
}
}
// 草稿箱分页变化
const handleDraftsPageChange = (page: number) => {
draftsPagination.page = page
loadDraftTasks()
}
// 编辑草稿任务
const handleEditDraftTask = (task: any) => {
router.push({
path: '/tasks/create',
query: { taskId: task.id, mode: 'edit' }
})
}
// 删除草稿任务
const handleDeleteDraft = async (task: any) => {
try {
await new Promise<void>((resolve, reject) => {
Modal.confirm({
title: '确认删除',
content: `确定要删除草稿"${task.title || '未命名任务'}"吗?删除后无法恢复。`,
okText: '确认删除',
cancelText: '取消',
okType: 'danger',
onOk: () => resolve(),
onCancel: () => reject()
})
})
const response = await taskApi.deleteTask(task.id)
if (response.code === 200) {
message.success('草稿已删除')
loadDraftTasks()
loadAllTabCounts()
} else {
message.error(response.msg || '删除失败')
}
} catch (error: any) {
if (error) {
console.error('删除草稿失败:', error)
message.error(error.msg || '删除失败')
}
}
}
// 重置已完成任务筛选条件
const handleCompletedFiltersReset = () => {
completedFilters.keyword = undefined
@ -5913,6 +6126,17 @@ const loadAllTabCounts = async () => {
}).catch(() => {})
)
// 6. 草稿箱数量(仅需求部门用户)
if (showDraftTab.value) {
promises.push(
taskApi.getMyTasks({ role: 'publisher', status: 'draft', page: 1, pageSize: 1 }).then(res => {
if (res.code === 200 && res.data && res.data.total !== undefined) {
draftsTotal.value = res.data.total
}
}).catch(() => {})
)
}
await Promise.all(promises)
} catch (error) {
console.error('加载Tab数量统计失败:', error)
@ -6472,6 +6696,26 @@ onUnmounted(() => {
color: $color-success;
}
// 草稿标签样式
.task-badge-container {
margin-bottom: 12px;
}
.task-badge {
display: inline-flex;
align-items: center;
padding: 4px 12px;
border-radius: $radius-small;
font-size: $font-size-xs;
font-weight: $font-weight-medium;
}
.draft-badge {
background: rgba(255, 193, 7, 0.15);
border: 1px solid rgba(255, 193, 7, 0.4);
color: #ffc107;
}
.badge-high-score {
background: rgba(49, 240, 139, 0.1);
border: 1px solid rgba(49, 240, 139, 0.2);