feat: 功能优化

This commit is contained in:
2026-01-18 21:41:44 +08:00
parent 41ebb5017d
commit b76367afed
7 changed files with 240 additions and 172 deletions

View File

@@ -1,106 +1,125 @@
import { message, Modal } from 'ant-design-vue'
// 配置常量
const API_SUCCESS_CODE = 0
const DOWNLOAD_INTERVAL = 500
/**
* 任务操作通用逻辑 Composable
* @param {Object} apis - API 对象,包含 deleteApi, cancelApi, retryApi, getSignedUrlsApi
* @param {Function} onSuccess - 操作成功后的回调函数
* @returns {Object} 操作方法
*
* @param {Object} apiHandlers - API 处理器对象
* @param {Function} apiHandlers.deleteApi - 删除任务的 API 函数 (id) => Promise<void>
* @param {Function} [apiHandlers.cancelApi] - 取消任务的 API 函数 (id) => Promise<void>
* @param {Function} [apiHandlers.retryApi] - 重试任务的 API 函数 (id) => Promise<void>
* @param {Function} [apiHandlers.getSignedUrlsApi] - 获取签名URL的 API 函数 (taskId) => Promise<{code: number, data: string[]}>
* @param {Function} [onSuccess] - 操作成功后的回调函数 () => void
* @returns {Object} 操作方法集合
*
* @example
* ```javascript
* const { handleDelete, handleCancel, handleRetry, handleBatchDownload, handlePreview } = useTaskOperations({
* deleteApi: (id) => taskApi.delete(id),
* cancelApi: (id) => taskApi.cancel(id),
* retryApi: (id) => taskApi.retry(id),
* getSignedUrlsApi: (taskId) => taskApi.getSignedUrls(taskId)
* }, () => {
* // 刷新列表
* fetchTasks()
* })
* ```
*/
export function useTaskOperations(apis, onSuccess) {
const { deleteApi, cancelApi, retryApi, getSignedUrlsApi } = apis
export function useTaskOperations(apiHandlers, onSuccess) {
if (!apiHandlers || typeof apiHandlers !== 'object') {
throw new Error('apiHandlers must be an object')
}
// 删除任务
const handleDelete = (id) => {
if (!apiHandlers.deleteApi || typeof apiHandlers.deleteApi !== 'function') {
throw new Error('deleteApi is required and must be a function')
}
const {
deleteApi,
cancelApi,
retryApi,
getSignedUrlsApi
} = apiHandlers
// 通用模态框确认
function confirmModal({ title, content, okType = 'primary', onOk }) {
Modal.confirm({
title: '确认删除',
content: '确定删除这个任务吗?删除后无法恢复。',
title,
content,
okText: '确认',
cancelText: '取消',
okType: 'danger',
okType,
onOk: async () => {
try {
await deleteApi(id)
message.success('删除成功')
await onOk()
onSuccess && onSuccess()
} catch (error) {
console.error('删除任务失败:', error)
message.error('删除失败')
message.error('操作失败')
}
}
})
}
// 执行 API 操作并显示成功消息
async function executeApiOperation(apiFn, successMessage) {
await apiFn()
message.success(successMessage)
}
// 删除任务
function deleteTask(id) {
confirmModal({
title: '确认删除',
content: '确定删除这个任务吗?删除后无法恢复。',
okType: 'danger',
onOk: () => executeApiOperation(() => deleteApi(id), '删除成功')
})
}
// 取消任务
const handleCancel = (id) => {
Modal.confirm({
function cancelTask(id) {
confirmModal({
title: '确认取消',
content: '确定要取消这个任务吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
try {
await cancelApi(id)
message.success('已取消任务')
onSuccess && onSuccess()
} catch (error) {
console.error('取消任务失败:', error)
message.error('操作失败')
}
}
onOk: () => executeApiOperation(() => cancelApi(id), '已取消任务')
})
}
// 重试任务
const handleRetry = (id) => {
Modal.confirm({
function retryTask(id) {
confirmModal({
title: '确认重试',
content: '确定要重新生成这个任务吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
try {
await retryApi(id)
message.success('已重新提交任务')
onSuccess && onSuccess()
} catch (error) {
console.error('重试任务失败:', error)
message.error('操作失败')
}
}
onOk: () => executeApiOperation(() => retryApi(id), '已重新提交任务')
})
}
// 批量删除
const handleBatchDelete = async (ids, deleteApiFn) => {
async function batchDeleteTasks(ids, deleteApiFn) {
if (!ids || ids.length === 0) {
message.warning('请选择要删除的任务')
return
}
Modal.confirm({
confirmModal({
title: '确认批量删除',
content: `确定要删除选中的 ${ids.length} 个任务吗?删除后无法恢复。`,
okText: '确认',
cancelText: '取消',
okType: 'danger',
onOk: async () => {
try {
const deleteFn = deleteApiFn || deleteApi
for (const id of ids) {
await deleteFn(id)
}
message.success(`成功删除 ${ids.length} 个任务`)
onSuccess && onSuccess()
} catch (error) {
console.error('批量删除失败:', error)
message.error('批量删除失败')
const deleteFn = deleteApiFn || deleteApi
for (const id of ids) {
await deleteFn(id)
}
message.success(`成功删除 ${ids.length} 个任务`)
}
})
}
// 下载单个文件
const handleDownload = (url, filename = 'download') => {
function downloadFile(url, filename = 'download') {
const link = document.createElement('a')
link.href = url
link.download = filename
@@ -110,66 +129,67 @@ export function useTaskOperations(apis, onSuccess) {
document.body.removeChild(link)
}
// 批量下载
const handleBatchDownload = async (urls, getSignedUrlsApi, taskId) => {
if (!urls || urls.length === 0) {
message.warning('没有可下载的文件')
return
// 获取签名URL
async function fetchSignedUrl(getSignedUrlsApi, taskId) {
const res = await getSignedUrlsApi(taskId)
if (res.code === API_SUCCESS_CODE && res.data) {
return res.data
}
throw new Error('获取签名URL失败')
}
// 批量下载
async function batchDownload(urls, getSignedUrlsApi, taskId) {
try {
message.loading('正在获取下载链接...', 0)
message.loading('正在准备下载...', 0)
let downloadUrls = urls
// 如果需要获取签名URL
if (getSignedUrlsApi && taskId) {
const res = await getSignedUrlsApi(taskId)
if (res.code === 0 && res.data) {
downloadUrls = res.data
} else {
message.warning('获取下载链接失败')
return
}
downloadUrls = await fetchSignedUrl(getSignedUrlsApi, taskId)
}
// 检查下载链接
if (!downloadUrls || downloadUrls.length === 0) {
message.warning('没有可下载的文件')
return
}
message.destroy()
message.loading('正在准备下载...', 0)
message.loading('正在下载文件...', 0)
// 逐个触发下载,避免浏览器阻止多个弹窗
downloadUrls.forEach((url, index) => {
setTimeout(() => {
handleDownload(url)
}, index * 500) // 每个下载间隔500ms
downloadFile(url)
}, index * DOWNLOAD_INTERVAL)
})
message.destroy()
message.success(`已触发 ${downloadUrls.length} 个文件的下载`)
} catch (error) {
console.error('批量下载失败:', error)
message.destroy()
message.error('获取下载链接失败')
message.error('下载失败,请稍后重试')
}
}
// 获取签名URL
const getSignedUrl = async (getSignedUrlsApi, taskId, index) => {
// 获取单个签名URL
async function getSignedUrl(getSignedUrlsApi, taskId, index) {
try {
const res = await getSignedUrlsApi(taskId)
if (res.code === 0 && res.data && res.data[index]) {
if (res.code === API_SUCCESS_CODE && res.data && res.data[index]) {
return res.data[index]
} else {
message.warning('获取预览链接失败')
return null
}
message.warning('获取预览链接失败')
return null
} catch (error) {
console.error('获取签名URL失败:', error)
message.error('获取预览链接失败')
return null
}
}
// 预览
const handlePreview = async (getSignedUrlsApi, taskId, index) => {
// 预览文件
async function previewFile(getSignedUrlsApi, taskId, index) {
try {
message.loading('正在获取预览链接...', 0)
const url = await getSignedUrl(getSignedUrlsApi, taskId, index)
@@ -179,7 +199,6 @@ export function useTaskOperations(apis, onSuccess) {
window.open(url, '_blank')
}
} catch (error) {
console.error('预览失败:', error)
message.destroy()
message.error('预览失败')
}
@@ -187,17 +206,17 @@ export function useTaskOperations(apis, onSuccess) {
return {
// 基本操作
handleDelete,
handleCancel,
handleRetry,
handleDelete: deleteTask,
handleCancel: cancelTask,
handleRetry: retryTask,
// 批量操作
handleBatchDelete,
handleBatchDownload,
handleBatchDelete: batchDeleteTasks,
handleBatchDownload: batchDownload,
// 下载和预览
handleDownload,
handlePreview,
handleDownload: downloadFile,
handlePreview: previewFile,
getSignedUrl
}
}