From 2c0460ddc14d1d0a9c31b2d545455a88c612b6ba Mon Sep 17 00:00:00 2001 From: weicw <594098497@qq.com> Date: Sun, 25 Oct 2026 15:55:49 +0800 Subject: [PATCH] =?UTF-8?q?fix(ai):=20=E4=BA=A7=E7=89=A9=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=85=83=E7=B4=A0?= =?UTF-8?q?=EF=BC=8C=E5=88=9B=E6=84=8F=E5=8A=A9=E6=89=8B=E4=B8=8E=E5=8A=A9?= =?UTF-8?q?=E6=89=8B=E9=A1=B5=E9=93=BE=E6=8E=A5=E5=8F=AF=E5=A4=8D=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit video_result/photo_files 的元素可能直接是地址字符串,原实现按对象取 url, 字符串元素一律取空——视频有文件却不播放、复制链接永远为空。 --- src/api/ai/creativeAssistant/model/index.ts | 16 +++++++++++-- src/views/gxmu/creativeAssistant/index.vue | 25 ++++++++++++++++++--- src/views/oa/chatgpt/index.vue | 20 +++++++++++++---- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/api/ai/creativeAssistant/model/index.ts b/src/api/ai/creativeAssistant/model/index.ts index 4a7a67b..f2a403f 100644 --- a/src/api/ai/creativeAssistant/model/index.ts +++ b/src/api/ai/creativeAssistant/model/index.ts @@ -28,11 +28,23 @@ export interface CreativeAssistantRequest { user_files?: CreativeAssistantUploadFile[]; } +/** + * 工作流产出的一项文件。 + * + * 正常是 { url, name, type } 这样的对象(后端已归一),但上游有时直接把 + * 地址字符串塞进数组;端上按字符串兜一层,否则整条视频链路取不到链接 + * (见禅道 bug #1:有视频不播放、复制链接为空)。 + */ +export type CreativeFileItem = Partial | string; + +/** 文件列表:正常情况下是数组,退化时可能是单个对象或裸地址。 */ +export type CreativeFileList = CreativeFileItem[] | CreativeFileItem; + export interface CreativeAssistantOutputs { - video_result?: Partial[]; + video_result?: CreativeFileList; video_message?: string; Script_result?: string; - photo_files?: Partial[]; + photo_files?: CreativeFileList; photo_message?: string; } diff --git a/src/views/gxmu/creativeAssistant/index.vue b/src/views/gxmu/creativeAssistant/index.vue index e45f1bb..bd0a78b 100644 --- a/src/views/gxmu/creativeAssistant/index.vue +++ b/src/views/gxmu/creativeAssistant/index.vue @@ -197,7 +197,8 @@ import type { FileRecord } from '@/api/system/file/model'; import type { CreativeAssistantOutputs, - CreativeAssistantResponse + CreativeAssistantResponse, + CreativeFileList } from '@/api/ai/creativeAssistant/model'; import { copyText } from '@/utils/common'; import { resolveDisplayText, isFailedPayload, FAILED_TEXT } from '@/utils/ai-result'; @@ -227,9 +228,27 @@ return !!content.value.trim(); }); - const videoFiles = computed(() => workflowOutputs.value?.video_result || []); + /** + * 文件列表兜底:上游可能给成单个对象或裸地址字符串,不是数组时当一项处理, + * 否则视频区直接空掉(见禅道 bug #1)。 + */ + const asFileList = ( + value?: CreativeFileList | null + ): Partial[] => { + const items = !value ? [] : Array.isArray(value) ? value : [value]; + // 裸地址统一包成 { url },下游的 resolveFileUrl / getFileName 不必各自判类型。 + return items.map((item) => + typeof item === 'string' ? { url: item } : item + ); + }; + + const videoFiles = computed(() => + asFileList(workflowOutputs.value?.video_result) + ); const scriptMarkdown = computed(() => workflowOutputs.value?.Script_result || ''); - const photoFiles = computed(() => workflowOutputs.value?.photo_files || []); + const photoFiles = computed(() => + asFileList(workflowOutputs.value?.photo_files) + ); const statusMessage = computed(() => { // 失败态优先:后端失败时 outputs 为空,若不先判失败,用户既看不到正文 // 也看不到原因,只有一个 toast 一闪而过(见 issue 10)。 diff --git a/src/views/oa/chatgpt/index.vue b/src/views/oa/chatgpt/index.vue index 50072c3..5a555ea 100644 --- a/src/views/oa/chatgpt/index.vue +++ b/src/views/oa/chatgpt/index.vue @@ -1493,8 +1493,13 @@ const getCreativeOutputs = (payload: any) => { return payload || {}; }; -const getCreativeFileUrl = (item: any) => - String( +// 元素退化成裸地址字符串时也要取得到链接:上游的 video_result 有时直接给地址数组, +// 取不到 url 就只剩「当前文件缺少链接」(见禅道 bug #1)。 +const getCreativeFileUrl = (item: any) => { + if (typeof item === "string") { + return item.trim(); + } + return String( item?.url || item?.remote_url || item?.downloadUrl || @@ -1502,6 +1507,7 @@ const getCreativeFileUrl = (item: any) => item?.path || "" ).trim(); +}; const getCreativeFileName = (item: any, fallback: string) => String(item?.name || item?.filename || fallback).trim(); @@ -1523,7 +1529,10 @@ const isCreativeImageFile = (item: any) => { ); }; -const formatFileList = (title: string, list: any[] = []) => { +const formatFileList = (title: string, list: any = []) => { + if (!Array.isArray(list)) { + list = list ? [list] : []; + } if (!list.length) { return ""; } @@ -1540,7 +1549,10 @@ const formatFileList = (title: string, list: any[] = []) => { .join("\n")}`; }; -const formatImageList = (title: string, list: any[] = []) => { +const formatImageList = (title: string, list: any = []) => { + if (!Array.isArray(list)) { + list = list ? [list] : []; + } if (!list.length) { return ""; }