菜单修改优化
This commit is contained in:
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user