已完成教学任务归档纠错功能:
已归档任务新增“撤销归档”和“删除”,支持单条及批量操作。 撤销后恢复为“已发布”状态。 已发布任务仍不可直接删除;被排课、选课、成绩或考试引用的归档任务也会拒绝删除并明确提示。 状态与操作文案统一为“归档”
This commit is contained in:
@@ -56,7 +56,7 @@ const manualEligibleTeachers = ref<any[]>([])
|
||||
const statusLabels: Record<string, string> = {
|
||||
Draft: '草稿',
|
||||
Published: '已发布',
|
||||
Closed: '已结课',
|
||||
Closed: '已归档',
|
||||
}
|
||||
const courseNatureLabels: Record<string, string> = {
|
||||
GeneralRequired: '公共必修',
|
||||
@@ -166,6 +166,9 @@ const selectedDraftRows = computed(() =>
|
||||
const selectedPublishedRows = computed(() =>
|
||||
selectedRows.value.filter((item) => item.status === 'Published'),
|
||||
)
|
||||
const selectedClosedRows = computed(() =>
|
||||
selectedRows.value.filter((item) => item.status === 'Closed'),
|
||||
)
|
||||
const responsibilityText = computed(() => {
|
||||
if (isSuperAdmin.value) return '超级管理员可处理全部教学任务,并保留跨层级纠错权限。'
|
||||
if (isAcademicAdmin.value && isCollegeAdmin.value) {
|
||||
@@ -242,7 +245,7 @@ function clearFilteredClasses(target: Record<string, any>, filtered: any[]) {
|
||||
}
|
||||
|
||||
function rowSelectable(row: any) {
|
||||
return canManageRow(row) && ['Draft', 'Published'].includes(row.status)
|
||||
return canManageRow(row) && ['Draft', 'Published', 'Closed'].includes(row.status)
|
||||
}
|
||||
|
||||
function onTaskSelectionChanged(selection: any[]) {
|
||||
@@ -368,11 +371,21 @@ async function save() {
|
||||
}
|
||||
|
||||
async function remove(row: any) {
|
||||
const isArchived = row.status === 'Closed'
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除教学任务“${row.name}”吗?`, '删除草稿', {
|
||||
type: 'warning',
|
||||
})
|
||||
await ElMessageBox.confirm(
|
||||
isArchived
|
||||
? `将永久删除已归档教学任务“${row.name}”。如任务已被排课、选课、成绩或考试引用,系统会拒绝删除。确定继续吗?`
|
||||
: `确定删除教学任务草稿“${row.name}”吗?`,
|
||||
isArchived ? '删除已归档任务' : '删除草稿',
|
||||
{
|
||||
type: 'error',
|
||||
confirmButtonText: '确认删除',
|
||||
cancelButtonText: '取消',
|
||||
},
|
||||
)
|
||||
await http.delete(`/teaching-tasks/${row.id}`)
|
||||
ElMessage.success(isArchived ? '已归档教学任务已删除' : '教学任务草稿已删除')
|
||||
await load()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel' && error !== 'close') ElMessage.error(apiErrorMessage(error))
|
||||
@@ -396,12 +409,32 @@ async function publish(row: any) {
|
||||
|
||||
async function closeTask(row: any) {
|
||||
try {
|
||||
await ElMessageBox.confirm('结课后将停止后续选课和排课调整,确定继续吗?', '教学任务结课', {
|
||||
await ElMessageBox.confirm('归档后将停止后续选课和排课调整,确定继续吗?', '归档教学任务', {
|
||||
type: 'warning',
|
||||
confirmButtonText: '确认结课',
|
||||
confirmButtonText: '确认归档',
|
||||
cancelButtonText: '取消',
|
||||
})
|
||||
await http.post(`/teaching-tasks/${row.id}/close`)
|
||||
ElMessage.success('教学任务已归档')
|
||||
await load()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel' && error !== 'close') ElMessage.error(apiErrorMessage(error))
|
||||
}
|
||||
}
|
||||
|
||||
async function unarchive(row: any) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'撤销归档后,教学任务将恢复为已发布状态,并重新进入相关业务流程。确定继续吗?',
|
||||
'撤销教学任务归档',
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: '撤销归档',
|
||||
cancelButtonText: '取消',
|
||||
},
|
||||
)
|
||||
await http.post(`/teaching-tasks/${row.id}/unarchive`)
|
||||
ElMessage.success('教学任务已撤销归档')
|
||||
await load()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel' && error !== 'close') ElMessage.error(apiErrorMessage(error))
|
||||
@@ -409,10 +442,12 @@ async function closeTask(row: any) {
|
||||
}
|
||||
|
||||
async function batchAction(
|
||||
operation: 'Publish' | 'Delete' | 'Archive',
|
||||
operation: 'Publish' | 'Delete' | 'Archive' | 'Unarchive',
|
||||
targets: any[],
|
||||
) {
|
||||
if (!targets.length) return
|
||||
const deletingArchived = operation === 'Delete' &&
|
||||
targets.every((item) => item.status === 'Closed')
|
||||
const descriptions = {
|
||||
Publish: {
|
||||
title: '批量发布教学任务',
|
||||
@@ -422,10 +457,12 @@ async function batchAction(
|
||||
type: 'warning',
|
||||
},
|
||||
Delete: {
|
||||
title: '批量删除教学任务',
|
||||
message: `将永久删除选中的 ${targets.length} 个草稿,此操作不可撤销。确定继续吗?`,
|
||||
title: deletingArchived ? '批量删除已归档任务' : '批量删除教学任务草稿',
|
||||
message: deletingArchived
|
||||
? `将永久删除选中的 ${targets.length} 个已归档任务。已被后续业务引用的任务会拒绝删除,此操作不可撤销。确定继续吗?`
|
||||
: `将永久删除选中的 ${targets.length} 个草稿,此操作不可撤销。确定继续吗?`,
|
||||
confirmButtonText: '批量删除',
|
||||
success: '教学任务草稿已批量删除',
|
||||
success: deletingArchived ? '已归档教学任务已批量删除' : '教学任务草稿已批量删除',
|
||||
type: 'error',
|
||||
},
|
||||
Archive: {
|
||||
@@ -435,6 +472,13 @@ async function batchAction(
|
||||
success: '教学任务已批量归档',
|
||||
type: 'warning',
|
||||
},
|
||||
Unarchive: {
|
||||
title: '批量撤销教学任务归档',
|
||||
message: `将选中的 ${targets.length} 个已归档任务恢复为已发布状态,并重新进入相关业务流程。确定继续吗?`,
|
||||
confirmButtonText: '批量撤销归档',
|
||||
success: '教学任务已批量撤销归档',
|
||||
type: 'warning',
|
||||
},
|
||||
} as const
|
||||
const description = descriptions[operation]
|
||||
try {
|
||||
@@ -572,7 +616,7 @@ onMounted(async () => {
|
||||
<div v-if="selectedRows.length" class="batch-action-bar">
|
||||
<div>
|
||||
<b>已选择 {{ selectedRows.length }} 个教学任务</b>
|
||||
<span>可操作:{{ selectedDraftRows.length }} 个草稿,{{ selectedPublishedRows.length }} 个已发布</span>
|
||||
<span>可操作:{{ selectedDraftRows.length }} 个草稿,{{ selectedPublishedRows.length }} 个已发布,{{ selectedClosedRows.length }} 个已归档</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-button
|
||||
@@ -599,6 +643,22 @@ onMounted(async () => {
|
||||
>
|
||||
归档已发布({{ selectedPublishedRows.length }})
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
:disabled="!selectedClosedRows.length"
|
||||
@click="batchAction('Unarchive', selectedClosedRows)"
|
||||
>
|
||||
撤销归档({{ selectedClosedRows.length }})
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
:disabled="!selectedClosedRows.length"
|
||||
@click="batchAction('Delete', selectedClosedRows)"
|
||||
>
|
||||
删除已归档({{ selectedClosedRows.length }})
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -625,14 +685,16 @@ onMounted(async () => {
|
||||
<el-table-column label="人数 / 容量" width="105"><template #default="{ row }">{{ row.studentCount }} / {{ row.capacity }}</template></el-table-column>
|
||||
<el-table-column label="周次" width="105"><template #default="{ row }">{{ row.startWeek }}—{{ row.endWeek }} 周</template></el-table-column>
|
||||
<el-table-column label="状态" width="90"><template #default="{ row }"><span class="table-status" :class="{ off: row.status === 'Closed' }">{{ statusLabels[row.status] }}</span></template></el-table-column>
|
||||
<el-table-column label="操作" width="185" fixed="right">
|
||||
<el-table-column label="操作" width="210" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="canManageRow(row) && row.status === 'Draft'" link type="primary" @click="openEdit(row)">编辑</el-button>
|
||||
<el-button v-if="canManageRow(row) && row.status === 'Draft'" link type="success" @click="publish(row)">发布</el-button>
|
||||
<el-button v-if="canManageRow(row) && row.status === 'Draft'" link type="danger" @click="remove(row)">删除</el-button>
|
||||
<el-button v-if="canManageRow(row) && row.status === 'Published'" link type="warning" @click="closeTask(row)">结课</el-button>
|
||||
<el-button v-if="canManageRow(row) && row.status === 'Published'" link type="warning" @click="closeTask(row)">归档</el-button>
|
||||
<el-button v-if="canManageRow(row) && row.status === 'Closed'" link type="primary" @click="unarchive(row)">撤销归档</el-button>
|
||||
<el-button v-if="canManageRow(row) && row.status === 'Closed'" link type="danger" @click="remove(row)">删除</el-button>
|
||||
<span v-if="!canManageRow(row) && row.status !== 'Closed'" class="muted-action">只读</span>
|
||||
<span v-if="row.status === 'Closed'" class="muted-action">已结课归档</span>
|
||||
<span v-if="!canManageRow(row) && row.status === 'Closed'" class="muted-action">已归档</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty><el-empty description="没有符合条件的教学任务" /></template>
|
||||
|
||||
Reference in New Issue
Block a user