2025-11-24 23:51:22 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="mix-task-list">
|
|
|
|
|
|
<div class="mix-task-list__header">
|
|
|
|
|
|
<h1 class="mix-task-list__title">混剪任务</h1>
|
|
|
|
|
|
<div class="mix-task-list__actions">
|
|
|
|
|
|
<a-button @click="handleRefresh">
|
|
|
|
|
|
<template #icon>
|
|
|
|
|
|
<ReloadOutlined />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
刷新
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 筛选条件 -->
|
|
|
|
|
|
<div class="mix-task-list__filters">
|
|
|
|
|
|
<a-space>
|
|
|
|
|
|
<a-select
|
|
|
|
|
|
v-model:value="filters.status"
|
|
|
|
|
|
style="width: 120px"
|
|
|
|
|
|
placeholder="任务状态"
|
|
|
|
|
|
@change="handleFilterChange"
|
|
|
|
|
|
allow-clear
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-select-option value="">全部状态</a-select-option>
|
|
|
|
|
|
<a-select-option value="pending">待处理</a-select-option>
|
|
|
|
|
|
<a-select-option value="running">处理中</a-select-option>
|
|
|
|
|
|
<a-select-option value="success">已完成</a-select-option>
|
|
|
|
|
|
<a-select-option value="failed">失败</a-select-option>
|
|
|
|
|
|
</a-select>
|
|
|
|
|
|
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model="filters.title"
|
|
|
|
|
|
placeholder="搜索标题"
|
|
|
|
|
|
style="width: 200px"
|
|
|
|
|
|
allow-clear
|
|
|
|
|
|
@press-enter="handleFilterChange"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #prefix>
|
|
|
|
|
|
<SearchOutlined />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-input>
|
|
|
|
|
|
|
|
|
|
|
|
<a-range-picker
|
|
|
|
|
|
v-model:value="filters.createTime"
|
|
|
|
|
|
style="width: 300px"
|
|
|
|
|
|
format="YYYY-MM-DD"
|
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
|
:placeholder="['开始日期', '结束日期']"
|
|
|
|
|
|
@change="handleFilterChange"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<a-button type="primary" @click="handleFilterChange">查询</a-button>
|
|
|
|
|
|
<a-button @click="handleResetFilters">重置</a-button>
|
|
|
|
|
|
</a-space>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 任务列表 -->
|
|
|
|
|
|
<div class="mix-task-list__content">
|
|
|
|
|
|
<a-spin :spinning="loading" tip="加载中...">
|
2025-11-30 18:06:54 +08:00
|
|
|
|
<a-table
|
|
|
|
|
|
:data-source="taskList"
|
|
|
|
|
|
:columns="columns"
|
|
|
|
|
|
:row-key="record => record.id"
|
|
|
|
|
|
:pagination="paginationConfig"
|
|
|
|
|
|
@change="handleTableChange"
|
|
|
|
|
|
:expanded-row-keys="expandedRowKeys"
|
|
|
|
|
|
@expandedRowsChange="handleExpandedRowsChange"
|
|
|
|
|
|
:scroll="{ x: 1000 }"
|
|
|
|
|
|
>
|
|
|
|
|
|
<!-- 标题列 -->
|
|
|
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
|
<template v-if="column.key === 'title'">
|
|
|
|
|
|
<div class="title-cell">
|
|
|
|
|
|
<strong>{{ record.title }}</strong>
|
|
|
|
|
|
<a-tag v-if="record.text" size="small" style="margin-left: 8px">有文案</a-tag>
|
2025-11-24 23:51:22 +08:00
|
|
|
|
</div>
|
2025-11-30 18:06:54 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 状态列 -->
|
|
|
|
|
|
<template v-else-if="column.key === 'status'">
|
|
|
|
|
|
<a-tag :color="getStatusColor(record.status)">
|
|
|
|
|
|
{{ getStatusText(record.status) }}
|
|
|
|
|
|
</a-tag>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 进度列 -->
|
|
|
|
|
|
<template v-else-if="column.key === 'progress'">
|
|
|
|
|
|
<div style="min-width: 100px">
|
|
|
|
|
|
<div style="font-size: 12px; margin-bottom: 4px">{{ record.progress }}%</div>
|
|
|
|
|
|
<a-progress
|
|
|
|
|
|
:percent="record.progress"
|
|
|
|
|
|
:status="getProgressStatus(record.status)"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
:show-info="false"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 创建时间列 -->
|
|
|
|
|
|
<template v-else-if="column.key === 'createTime'">
|
|
|
|
|
|
{{ formatDate(record.createTime) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 完成时间列 -->
|
|
|
|
|
|
<template v-else-if="column.key === 'finishTime'">
|
|
|
|
|
|
{{ record.finishTime ? formatDate(record.finishTime) : '-' }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 生成结果列 -->
|
|
|
|
|
|
<template v-else-if="column.key === 'outputUrls'">
|
|
|
|
|
|
<div v-if="record.outputUrls && record.outputUrls.length > 0">
|
|
|
|
|
|
<a-tag color="success">{{ record.outputUrls.length }} 个视频</a-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 操作列 -->
|
|
|
|
|
|
<template v-else-if="column.key === 'actions'">
|
|
|
|
|
|
<a-space>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
v-if="record.outputUrls && record.outputUrls.length > 0"
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="handleDownloadAll(record.outputUrls)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #icon>
|
|
|
|
|
|
<DownloadOutlined />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<span>下载</span>
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
v-if="record.status === 'failed'"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="handleRetry(record.id)"
|
|
|
|
|
|
>
|
|
|
|
|
|
重新生成
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
v-if="record.status === 'running'"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="handleCancel(record.id)"
|
|
|
|
|
|
>
|
|
|
|
|
|
取消
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
<a-popconfirm
|
|
|
|
|
|
title="确定删除这个任务吗?删除后无法恢复。"
|
|
|
|
|
|
@confirm="() => handleDelete(record.id)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-button size="small" danger>删除</a-button>
|
|
|
|
|
|
</a-popconfirm>
|
|
|
|
|
|
</a-space>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</template>
|
2025-11-24 23:51:22 +08:00
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
<!-- 展开行内容 -->
|
|
|
|
|
|
<template #expandedRowRender="{ record }">
|
|
|
|
|
|
<div class="expanded-content">
|
|
|
|
|
|
<!-- 任务详情 -->
|
|
|
|
|
|
<div v-if="record.text" class="task-text">
|
|
|
|
|
|
<strong>文案内容:</strong>
|
|
|
|
|
|
<p>{{ record.text }}</p>
|
|
|
|
|
|
</div>
|
2025-11-24 23:51:22 +08:00
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
<!-- 生成结果 -->
|
|
|
|
|
|
<div v-if="record.outputUrls && record.outputUrls.length > 0" class="task-results">
|
|
|
|
|
|
<strong>生成结果:</strong>
|
|
|
|
|
|
<div class="result-list">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="(url, index) in record.outputUrls"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
class="result-item"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a :href="url" target="_blank">
|
|
|
|
|
|
<PlayCircleOutlined />
|
|
|
|
|
|
视频 {{ index + 1 }}
|
|
|
|
|
|
</a>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="link"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="handleDownload(url)"
|
2025-11-24 23:51:22 +08:00
|
|
|
|
>
|
2025-11-30 18:06:54 +08:00
|
|
|
|
<DownloadOutlined />
|
|
|
|
|
|
</a-button>
|
2025-11-24 23:51:22 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-11-30 18:06:54 +08:00
|
|
|
|
</div>
|
2025-11-24 23:51:22 +08:00
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
<!-- 错误信息 -->
|
|
|
|
|
|
<div v-if="record.errorMsg" class="task-error">
|
|
|
|
|
|
<a-alert
|
|
|
|
|
|
type="error"
|
|
|
|
|
|
:message="record.errorMsg"
|
|
|
|
|
|
show-icon
|
|
|
|
|
|
/>
|
2025-11-24 23:51:22 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-11-30 18:06:54 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
</a-table>
|
2025-11-24 23:51:22 +08:00
|
|
|
|
</a-spin>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-11-30 18:06:54 +08:00
|
|
|
|
import { ref, reactive, onMounted } from 'vue'
|
2025-11-24 23:51:22 +08:00
|
|
|
|
import { message, Modal } from 'ant-design-vue'
|
|
|
|
|
|
import {
|
|
|
|
|
|
ReloadOutlined,
|
|
|
|
|
|
SearchOutlined,
|
|
|
|
|
|
PlayCircleOutlined,
|
|
|
|
|
|
DownloadOutlined
|
|
|
|
|
|
} from '@ant-design/icons-vue'
|
|
|
|
|
|
import { MixTaskService } from '@/api/mixTask'
|
|
|
|
|
|
import { formatDate } from '@/utils/file'
|
|
|
|
|
|
|
|
|
|
|
|
// 数据
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const taskList = ref([])
|
2025-11-30 18:06:54 +08:00
|
|
|
|
const expandedRowKeys = ref([])
|
|
|
|
|
|
|
|
|
|
|
|
// 表格列定义
|
|
|
|
|
|
const columns = [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'ID',
|
|
|
|
|
|
dataIndex: 'id',
|
|
|
|
|
|
key: 'id',
|
|
|
|
|
|
width: 80,
|
|
|
|
|
|
fixed: 'left'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '标题',
|
|
|
|
|
|
dataIndex: 'title',
|
|
|
|
|
|
key: 'title',
|
|
|
|
|
|
width: 250,
|
|
|
|
|
|
ellipsis: true
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '状态',
|
|
|
|
|
|
dataIndex: 'status',
|
|
|
|
|
|
key: 'status',
|
|
|
|
|
|
width: 100
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '进度',
|
|
|
|
|
|
dataIndex: 'progress',
|
|
|
|
|
|
key: 'progress',
|
|
|
|
|
|
width: 150
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '生成结果',
|
|
|
|
|
|
dataIndex: 'outputUrls',
|
|
|
|
|
|
key: 'outputUrls',
|
|
|
|
|
|
width: 120
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '创建时间',
|
|
|
|
|
|
dataIndex: 'createTime',
|
|
|
|
|
|
key: 'createTime',
|
|
|
|
|
|
width: 180
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '完成时间',
|
|
|
|
|
|
dataIndex: 'finishTime',
|
|
|
|
|
|
key: 'finishTime',
|
|
|
|
|
|
width: 180
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '操作',
|
|
|
|
|
|
key: 'actions',
|
|
|
|
|
|
width: 300,
|
|
|
|
|
|
fixed: 'right'
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2025-11-24 23:51:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 筛选条件
|
|
|
|
|
|
const filters = reactive({
|
|
|
|
|
|
status: '',
|
|
|
|
|
|
title: '',
|
|
|
|
|
|
createTime: undefined
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
// 分页配置
|
|
|
|
|
|
const paginationConfig = reactive({
|
|
|
|
|
|
current: 1,
|
2025-11-24 23:51:22 +08:00
|
|
|
|
pageSize: 10,
|
2025-11-30 18:06:54 +08:00
|
|
|
|
total: 0,
|
|
|
|
|
|
showSizeChanger: true,
|
|
|
|
|
|
showQuickJumper: true,
|
|
|
|
|
|
showTotal: (total) => `共 ${total} 条`,
|
|
|
|
|
|
pageSizeOptions: ['10', '20', '50', '100'],
|
|
|
|
|
|
onChange: (page, pageSize) => {
|
|
|
|
|
|
paginationConfig.current = page
|
|
|
|
|
|
paginationConfig.pageSize = pageSize
|
|
|
|
|
|
handlePageChange(page, pageSize)
|
|
|
|
|
|
},
|
|
|
|
|
|
onShowSizeChange: (current, size) => {
|
|
|
|
|
|
paginationConfig.current = 1
|
|
|
|
|
|
paginationConfig.pageSize = size
|
|
|
|
|
|
handlePageChange(1, size)
|
|
|
|
|
|
}
|
2025-11-24 23:51:22 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 构建查询参数
|
|
|
|
|
|
const buildQueryParams = () => {
|
|
|
|
|
|
const params = {
|
2025-11-30 18:06:54 +08:00
|
|
|
|
pageNo: paginationConfig.current,
|
|
|
|
|
|
pageSize: paginationConfig.pageSize,
|
2025-11-24 23:51:22 +08:00
|
|
|
|
status: filters.status || undefined,
|
|
|
|
|
|
title: filters.title || undefined
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理日期范围
|
|
|
|
|
|
if (filters.createTime && Array.isArray(filters.createTime) && filters.createTime.length === 2) {
|
|
|
|
|
|
params.createTimeStart = `${filters.createTime[0]} 00:00:00`
|
|
|
|
|
|
params.createTimeEnd = `${filters.createTime[1]} 23:59:59`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return params
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加载任务列表
|
|
|
|
|
|
const loadTaskList = async () => {
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await MixTaskService.getTaskPage(buildQueryParams())
|
|
|
|
|
|
if (res.code === 0) {
|
|
|
|
|
|
taskList.value = res.data.list || []
|
2025-11-30 18:06:54 +08:00
|
|
|
|
paginationConfig.total = res.data.total || 0
|
2025-11-24 23:51:22 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
message.error(res.msg || '加载失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载任务列表失败:', error)
|
|
|
|
|
|
message.error('加载失败,请重试')
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 筛选
|
|
|
|
|
|
const handleFilterChange = () => {
|
2025-11-30 18:06:54 +08:00
|
|
|
|
paginationConfig.current = 1
|
2025-11-24 23:51:22 +08:00
|
|
|
|
loadTaskList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleResetFilters = () => {
|
|
|
|
|
|
filters.status = ''
|
|
|
|
|
|
filters.title = ''
|
|
|
|
|
|
filters.createTime = undefined
|
2025-11-30 18:06:54 +08:00
|
|
|
|
paginationConfig.current = 1
|
2025-11-24 23:51:22 +08:00
|
|
|
|
loadTaskList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 分页
|
|
|
|
|
|
const handlePageChange = (page, pageSize) => {
|
|
|
|
|
|
loadTaskList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
// 表格变化
|
|
|
|
|
|
const handleTableChange = (pag, filters, sorter) => {
|
|
|
|
|
|
console.log('表格变化:', pag, filters, sorter)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 展开行变化
|
|
|
|
|
|
const handleExpandedRowsChange = (expandedRows) => {
|
|
|
|
|
|
expandedRowKeys.value = expandedRows
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 23:51:22 +08:00
|
|
|
|
// 刷新
|
|
|
|
|
|
const handleRefresh = () => {
|
|
|
|
|
|
loadTaskList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重新生成
|
|
|
|
|
|
const handleRetry = (id) => {
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: '确认重新生成',
|
|
|
|
|
|
content: '确定要重新生成这个任务吗?',
|
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await MixTaskService.retryTask(id)
|
|
|
|
|
|
message.success('已重新提交任务')
|
|
|
|
|
|
loadTaskList()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
message.error('操作失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 取消任务
|
|
|
|
|
|
const handleCancel = (id) => {
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: '确认取消',
|
|
|
|
|
|
content: '确定要取消这个任务吗?',
|
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await MixTaskService.cancelTask(id)
|
|
|
|
|
|
message.success('已取消任务')
|
|
|
|
|
|
loadTaskList()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
message.error('操作失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除任务
|
|
|
|
|
|
const handleDelete = (id) => {
|
2025-11-30 18:06:54 +08:00
|
|
|
|
MixTaskService.deleteTask(id)
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
message.success('删除成功')
|
|
|
|
|
|
loadTaskList()
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {
|
|
|
|
|
|
message.error('删除失败')
|
|
|
|
|
|
})
|
2025-11-24 23:51:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
// 下载单个视频
|
2025-11-24 23:51:22 +08:00
|
|
|
|
const handleDownload = (url) => {
|
|
|
|
|
|
const link = document.createElement('a')
|
|
|
|
|
|
link.href = url
|
|
|
|
|
|
link.download = 'video'
|
|
|
|
|
|
link.target = '_blank'
|
|
|
|
|
|
document.body.appendChild(link)
|
|
|
|
|
|
link.click()
|
|
|
|
|
|
document.body.removeChild(link)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
// 批量下载所有视频
|
|
|
|
|
|
const handleDownloadAll = (urls) => {
|
|
|
|
|
|
if (!urls || urls.length === 0) {
|
|
|
|
|
|
message.warning('没有可下载的视频')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
message.loading('正在准备下载...', 0)
|
|
|
|
|
|
|
|
|
|
|
|
// 逐个触发下载,避免浏览器阻止多个弹窗
|
|
|
|
|
|
urls.forEach((url, index) => {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
console.log('下载视频:', url)
|
|
|
|
|
|
handleDownload(url)
|
|
|
|
|
|
}, index * 500) // 每个下载间隔500ms
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
message.destroy()
|
|
|
|
|
|
message.success(`已触发 ${urls.length} 个视频的下载`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 23:51:22 +08:00
|
|
|
|
// 获取状态文本
|
|
|
|
|
|
const getStatusText = (status) => {
|
|
|
|
|
|
const statusMap = {
|
|
|
|
|
|
pending: '待处理',
|
|
|
|
|
|
running: '处理中',
|
|
|
|
|
|
success: '已完成',
|
|
|
|
|
|
failed: '失败'
|
|
|
|
|
|
}
|
|
|
|
|
|
return statusMap[status] || status
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取状态颜色
|
|
|
|
|
|
const getStatusColor = (status) => {
|
|
|
|
|
|
const colorMap = {
|
|
|
|
|
|
pending: 'default',
|
|
|
|
|
|
running: 'processing',
|
|
|
|
|
|
success: 'success',
|
|
|
|
|
|
failed: 'error'
|
|
|
|
|
|
}
|
|
|
|
|
|
return colorMap[status] || 'default'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取进度条状态
|
|
|
|
|
|
const getProgressStatus = (status) => {
|
|
|
|
|
|
const statusMap = {
|
|
|
|
|
|
pending: 'normal',
|
|
|
|
|
|
running: 'active',
|
|
|
|
|
|
success: 'success',
|
|
|
|
|
|
failed: 'exception'
|
|
|
|
|
|
}
|
|
|
|
|
|
return statusMap[status] || 'normal'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
loadTaskList()
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.mix-task-list {
|
|
|
|
|
|
padding: 24px;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-task-list__header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-task-list__title {
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-task-list__actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-task-list__filters {
|
|
|
|
|
|
margin-bottom: 24px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
background: var(--color-surface);
|
|
|
|
|
|
border-radius: var(--radius-card);
|
|
|
|
|
|
border: 1px solid var(--color-border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mix-task-list__content {
|
|
|
|
|
|
flex: 1;
|
2025-11-30 18:06:54 +08:00
|
|
|
|
overflow: auto;
|
2025-11-24 23:51:22 +08:00
|
|
|
|
background: var(--color-surface);
|
|
|
|
|
|
border-radius: var(--radius-card);
|
2025-11-30 18:06:54 +08:00
|
|
|
|
border: 1px solid var(--color-border);
|
2025-11-24 23:51:22 +08:00
|
|
|
|
padding: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
.title-cell {
|
2025-11-24 23:51:22 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-11-30 18:06:54 +08:00
|
|
|
|
flex-wrap: wrap;
|
2025-11-24 23:51:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
.expanded-content {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
background: var(--color-bg-2);
|
|
|
|
|
|
border-radius: var(--radius-card);
|
|
|
|
|
|
margin: 8px;
|
2025-11-24 23:51:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
.task-text {
|
|
|
|
|
|
margin-bottom: 16px;
|
2025-11-24 23:51:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
.task-text p {
|
|
|
|
|
|
margin: 8px 0 0 0;
|
|
|
|
|
|
padding: 8px;
|
|
|
|
|
|
background: var(--color-surface);
|
|
|
|
|
|
border-radius: var(--radius-card);
|
2025-11-24 23:51:22 +08:00
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
.task-results {
|
|
|
|
|
|
margin-bottom: 16px;
|
2025-11-24 23:51:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.result-list {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 8px;
|
2025-11-30 18:06:54 +08:00
|
|
|
|
margin-top: 8px;
|
2025-11-24 23:51:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.result-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
padding: 6px 12px;
|
2025-11-30 18:06:54 +08:00
|
|
|
|
background: var(--color-surface);
|
2025-11-24 23:51:22 +08:00
|
|
|
|
border-radius: var(--radius-card);
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 18:06:54 +08:00
|
|
|
|
.task-error {
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 确保按钮内的图标和文字对齐 */
|
|
|
|
|
|
:deep(.ant-btn .anticon) {
|
|
|
|
|
|
vertical-align: middle;
|
2025-11-24 23:51:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|