|
|
@@ -27,6 +27,14 @@
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="file_count" label="文件数量" width="100" align="center" />
|
|
|
+ <el-table-column label="标注进度" min-width="150" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-progress
|
|
|
+ :percentage="Math.min(100, Math.round((row.completed_count || 0) / (row.file_count || 1) * 100))"
|
|
|
+ :status="(row.completed_count || 0) >= (row.file_count || 1) ? 'success' : ''"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="task_id" label="标注平台任务ID" min-width="200">
|
|
|
<template #default="{ row }">
|
|
|
<el-tag v-if="row.task_id" type="info">{{ row.task_id }}</el-tag>
|
|
|
@@ -84,6 +92,14 @@
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="file_count" label="文件数量" width="100" align="center" />
|
|
|
+ <el-table-column label="标注进度" min-width="150" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-progress
|
|
|
+ :percentage="Math.min(100, Math.round((row.completed_count || 0) / (row.file_count || 1) * 100))"
|
|
|
+ :status="(row.completed_count || 0) >= (row.file_count || 1) ? 'success' : ''"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="task_id" label="标注平台任务ID" min-width="200">
|
|
|
<template #default="{ row }">
|
|
|
<el-tag v-if="row.task_id" type="info">{{ row.task_id }}</el-tag>
|
|
|
@@ -188,6 +204,7 @@ interface TaskItem {
|
|
|
type: string
|
|
|
name: string
|
|
|
file_count: number
|
|
|
+ completed_count: number
|
|
|
status: string
|
|
|
tag?: string
|
|
|
image_url?: string
|
|
|
@@ -302,8 +319,13 @@ const handleCheckProgress = async (row: TaskItem) => {
|
|
|
|
|
|
// 导出结果
|
|
|
const handleExportData = async (row: TaskItem) => {
|
|
|
+ let loadingMsg: any = null
|
|
|
try {
|
|
|
- ElMessage.info('正在请求导出,请稍候...')
|
|
|
+ loadingMsg = ElMessage.info({
|
|
|
+ message: '正在请求导出,请稍候...',
|
|
|
+ duration: 0 // 不自动关闭
|
|
|
+ })
|
|
|
+
|
|
|
const response = await request.post<any, ApiResponse<any>>('/api/v1/sample/external/projects/export', {
|
|
|
project_id: row.project_id,
|
|
|
format: 'json'
|
|
|
@@ -311,20 +333,57 @@ const handleExportData = async (row: TaskItem) => {
|
|
|
|
|
|
if (response.code === 0) {
|
|
|
const fileUrl = response.data.file_url
|
|
|
+ const fileName = response.data.file_name || `export_${row.project_name || row.project_id}.json`
|
|
|
+
|
|
|
if (fileUrl) {
|
|
|
- ElMessage.success('导出成功,即将开始下载')
|
|
|
- // 如果是相对路径,可能需要拼接基础 URL
|
|
|
- const downloadUrl = fileUrl.startsWith('http') ? fileUrl : `http://192.168.92.61:9003${fileUrl}`
|
|
|
- window.open(downloadUrl, '_blank')
|
|
|
+ // 先关闭之前的“正在请求”消息
|
|
|
+ if (loadingMsg) loadingMsg.close()
|
|
|
+
|
|
|
+ loadingMsg = ElMessage.success({
|
|
|
+ message: '导出成功,正在准备下载...',
|
|
|
+ duration: 3000
|
|
|
+ })
|
|
|
+
|
|
|
+ // 使用我们自己的后端中转接口进行下载,彻底解决跨域和 Token 携带问题
|
|
|
+ // 构建中转下载链接
|
|
|
+ const proxyDownloadUrl = `/api/v1/sample/external/download-proxy?url=${encodeURIComponent(fileUrl)}&filename=${encodeURIComponent(fileName)}`
|
|
|
+
|
|
|
+ // 发起下载请求
|
|
|
+ const fileData = await request.get(proxyDownloadUrl, {
|
|
|
+ responseType: 'blob'
|
|
|
+ }) as unknown as Blob
|
|
|
+
|
|
|
+ // 创建本地下载链接并触发下载
|
|
|
+ const blob = new Blob([fileData])
|
|
|
+ const url = window.URL.createObjectURL(blob)
|
|
|
+ const link = document.createElement('a')
|
|
|
+ link.href = url
|
|
|
+ link.setAttribute('download', fileName)
|
|
|
+ document.body.appendChild(link)
|
|
|
+ link.click()
|
|
|
+
|
|
|
+ // 清理
|
|
|
+ document.body.removeChild(link)
|
|
|
+ window.URL.revokeObjectURL(url)
|
|
|
} else {
|
|
|
+ if (loadingMsg) loadingMsg.close()
|
|
|
ElMessage.warning('导出成功但未获取到下载链接')
|
|
|
}
|
|
|
} else {
|
|
|
+ if (loadingMsg) loadingMsg.close()
|
|
|
ElMessage.error(response.message || '导出失败')
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
+ } catch (error: any) {
|
|
|
+ if (loadingMsg) loadingMsg.close()
|
|
|
console.error('导出数据出错:', error)
|
|
|
- ElMessage.error('导出失败')
|
|
|
+
|
|
|
+ // 如果是业务错误且已经弹过窗了,就不要再弹了
|
|
|
+ if (error.isBusinessError) return
|
|
|
+
|
|
|
+ ElMessage.error({
|
|
|
+ message: '导出失败:网络连接异常或权限不足',
|
|
|
+ duration: 5000
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|