菜单修改优化

This commit is contained in:
supernijia
2026-07-28 13:40:19 +08:00
parent 4ddb8b47b0
commit 7c3c9e53a0
90 changed files with 9388 additions and 1545 deletions
@@ -128,8 +128,7 @@
>
<div class="task-section-header">
<div class="task-title-wrap">
<strong>{{ detail.task.taskNo || `任务 ${detail.task.id}` }}</strong>
<span class="task-meta">任务 ID{{ detail.task.id }}</span>
<strong>上架任务 #{{ detail.task.id }}</strong>
<span class="task-meta">创建时间{{ formatDateTime(detail.task.createdAt) }}</span>
</div>
<div class="task-actions">
@@ -144,6 +143,14 @@
>
下载结果
</button>
<button
type="button"
class="btn-delete"
:disabled="isDeletingTask(detail.task.id)"
@click="deleteTaskRecord(detail)"
>
{{ isDeletingTask(detail.task.id) ? '删除中...' : '删除' }}
</button>
</div>
</div>
@@ -163,17 +170,19 @@
<span v-if="file.platform">平台{{ file.platform }}</span>
<span>数据{{ fileProgressCurrent(file) }}/{{ fileProgressTotal(file) }}</span>
</div>
<div class="file-progress-header">
<span>{{ file.progressMessage || statusText(file.status) }}</span>
<span>{{ fileProgressPercent(file) }}%</span>
</div>
<div class="file-progress-track">
<div
class="file-progress-fill"
:class="statusClass(file.status)"
:style="{ width: `${fileProgressPercent(file)}%` }"
/>
</div>
<template v-if="shouldShowFileProgress(file)">
<div class="file-progress-header">
<span>{{ file.progressMessage || statusText(file.status) }}</span>
<span>{{ fileProgressPercent(file) }}%</span>
</div>
<div class="file-progress-track">
<div
class="file-progress-fill"
:class="statusClass(file.status)"
:style="{ width: `${fileProgressPercent(file)}%` }"
/>
</div>
</template>
<div v-if="fileErrorText(file)" class="file-error">{{ fileErrorText(file) }}</div>
</div>
<span class="status file-status" :class="statusClass(file.status)">
@@ -191,7 +200,7 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import BrandTopBar from './BrandTopBar.vue'
import ZiniaoVersionSetting from '@/shared/components/ZiniaoVersionSetting.vue'
@@ -199,6 +208,7 @@ import { expandBrandFolderRecursive, type BrandExpandFolderItem } from '@/shared
import {
activatePublishFile,
activatePublishTask,
deletePublishTask,
getPublishDashboard,
getPublishHistory,
getPublishItemsPageUrl,
@@ -261,6 +271,7 @@ const queuedBatches = ref<PublishQueueBatch[]>([])
const taskSnapshots = ref<Record<number, PublishTaskDetailVo>>({})
const historyItems = ref<PublishTaskDetailVo[]>([])
const missingTaskIds = ref<number[]>([])
const deletingTaskIds = ref<number[]>([])
const dashboard = ref<PublishDashboardVo>({
pendingCount: 0,
runningCount: 0,
@@ -990,6 +1001,10 @@ function fileErrorText(file: PublishFileItem) {
return file.errorMessage || file.error || ''
}
function shouldShowFileProgress(file: PublishFileItem) {
return ['RUNNING', 'SUCCESS', 'COMPLETED', 'FAILED', 'CANCELLED'].includes(normalizeStatus(file.status))
}
function fileProgressCurrent(file: PublishFileItem) {
return Math.max(0, Number(file.progressCurrent ?? file.processedRows ?? 0))
}
@@ -1038,6 +1053,58 @@ async function downloadResult(detail: PublishTaskDetailVo) {
else if (saved.error && saved.error !== '用户取消') ElMessage.error(saved.error)
}
function isDeletingTask(taskId: number) {
return deletingTaskIds.value.includes(taskId)
}
function removeTaskLocally(taskId: number) {
progressLoop.remove(taskId)
historyItems.value = historyItems.value.filter((detail) => detail.task?.id !== taskId)
const snapshots = { ...taskSnapshots.value }
delete snapshots[taskId]
taskSnapshots.value = snapshots
missingTaskIds.value = Array.from(new Set([...missingTaskIds.value, taskId]))
queuedBatches.value = queuedBatches.value.filter((batch) => batch.taskId !== taskId)
if (currentTaskId.value === taskId) {
currentTaskId.value = null
currentFiles.value = []
pendingFileIds.value = []
activeFileId.value = null
dispatchOptions.value = null
}
saveQueueState()
}
async function deleteTaskRecord(detail: PublishTaskDetailVo) {
const taskId = detail.task?.id
if (!taskId || isDeletingTask(taskId)) return
try {
await ElMessageBox.confirm(
`确定删除上架任务 #${taskId}?任务明细和结果文件也会一并删除。`,
'删除任务',
{
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning',
},
)
} catch {
return
}
deletingTaskIds.value = [...deletingTaskIds.value, taskId]
try {
await deletePublishTask(taskId)
removeTaskLocally(taskId)
ElMessage.success('任务已删除')
await Promise.all([loadDashboard(), loadHistory()])
} catch (error) {
ElMessage.error(error instanceof Error ? error.message : '删除任务失败')
} finally {
deletingTaskIds.value = deletingTaskIds.value.filter((id) => id !== taskId)
}
}
onMounted(async () => {
loadQueueState()
if (currentTaskId.value) progressLoop.add(currentTaskId.value)
@@ -1069,7 +1136,7 @@ onBeforeUnmount(() => {
.hint, .loading-msg, .task-meta, .file-info, .history-count { color: #888; font-size: 12px; line-height: 1.5; }
.btns, .run-row, .task-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.btns { justify-content: center; }
.opt-btn, .btn-run, .download { border: 0; border-radius: 6px; cursor: pointer; transition: background-color .15s ease, color .15s ease, opacity .15s ease; }
.opt-btn, .btn-run, .download, .btn-delete { border: 0; border-radius: 6px; cursor: pointer; transition: background-color .15s ease, color .15s ease, opacity .15s ease; }
.opt-btn { padding: 8px 16px; border: 1px solid #3a3a3a; background: #2a2a2a; color: #ccc; font-size: 13px; }
.opt-btn:hover:not(:disabled) { border-color: #3498db; color: #67b7ef; }
.opt-btn:disabled, .btn-run:disabled { opacity: .55; cursor: not-allowed; }
@@ -1105,6 +1172,9 @@ onBeforeUnmount(() => {
.task-error { padding: 10px 16px 0; }
.download { padding: 7px 12px; background: #2d6b46; color: #dff7e8; font-size: 12px; white-space: nowrap; }
.download:hover { background: #367d54; }
.btn-delete { padding: 7px 12px; background: #472929; color: #efaaaa; font-size: 12px; white-space: nowrap; }
.btn-delete:hover:not(:disabled) { background: #5a3030; color: #ffd0d0; }
.btn-delete:disabled { cursor: wait; opacity: .55; }
.status { display: inline-flex; align-items: center; justify-content: center; min-width: 58px; min-height: 26px; padding: 0 8px; border-radius: 4px; font-size: 12px; white-space: nowrap; }
.status.pending { background: #3a3424; color: #e4c56a; }
.status.running { background: #24394a; color: #75bff1; }