refactor(task): extract billing and polling logic from controller to service layer

Restructure the task relay system for better separation of concerns:
- Extract task billing into service/task_billing.go with unified settlement flow
- Move task polling loop from controller to service/task_polling.go (supports Suno + video platforms)
- Split RelayTask into fetch/submit paths with dedicated retry logic (taskSubmitWithRetry)
- Add TaskDto, TaskResponse generics, and FetchReq to dto/task.go
- Add taskcommon/helpers.go for shared task adaptor utilities
- Remove controller/task_video.go (logic consolidated into service layer)
- Update all task adaptors (ali, doubao, gemini, hailuo, jimeng, kling, sora, suno, vertex, vidu)
- Simplify frontend task logs to use new TaskDto response format
This commit is contained in:
CaIon
2026-02-10 20:40:33 +08:00
parent e0a6ee1cb8
commit 9e3954428d
34 changed files with 1465 additions and 1191 deletions

View File

@@ -396,7 +396,7 @@ export const getTaskLogsColumns = ({
dataIndex: 'fail_reason',
fixed: 'right',
render: (text, record, index) => {
// 仅当为视频生成任务且成功,且 fail_reason URL 时显示可点击链接
// 视频预览:优先使用 result_url兼容旧数据 fail_reason 中的 URL
const isVideoTask =
record.action === TASK_ACTION_GENERATE ||
record.action === TASK_ACTION_TEXT_GENERATE ||
@@ -404,14 +404,15 @@ export const getTaskLogsColumns = ({
record.action === TASK_ACTION_REFERENCE_GENERATE ||
record.action === TASK_ACTION_REMIX_GENERATE;
const isSuccess = record.status === 'SUCCESS';
const isUrl = typeof text === 'string' && /^https?:\/\//.test(text);
if (isSuccess && isVideoTask && isUrl) {
const resultUrl = record.result_url;
const hasResultUrl = typeof resultUrl === 'string' && /^https?:\/\//.test(resultUrl);
if (isSuccess && isVideoTask && hasResultUrl) {
return (
<a
href='#'
onClick={(e) => {
e.preventDefault();
openVideoModal(text);
openVideoModal(resultUrl);
}}
>
{t('点击预览视频')}

View File

@@ -144,8 +144,6 @@ const ContentModal = ({
maxHeight: '100%',
objectFit: 'contain',
}}
autoPlay
crossOrigin='anonymous'
onError={handleVideoError}
onLoadedData={handleVideoLoaded}
onLoadStart={() => setIsLoading(true)}