From 961e4bcc77e7b95066cad68137cb6ac14f11c55e Mon Sep 17 00:00:00 2001 From: sion123 <450702724@qq.com> Date: Sun, 18 Jan 2026 02:15:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/app/web-gold/index.html | 2 +- frontend/app/web-gold/src/App.vue | 5 +- .../src/components/PromptSelector.vue | 577 +++++++++++++++++ .../components/material/MaterialMixModal.vue | 2 +- .../material/MaterialUploadModal.vue | 56 +- frontend/app/web-gold/src/router/index.js | 4 +- frontend/app/web-gold/src/stores/prompt.js | 97 ++- .../src/views/content-style/Copywriting.vue | 247 +------ .../app/web-gold/src/views/dh/VoiceCopy.vue | 2 + .../src/views/material/MaterialListNew.vue | 110 +--- .../src/views/system/StyleSettings.vue | 515 --------------- .../src/views/system/style-settings/index.vue | 600 ++++++++++++++++++ .../digital-human-task/index.vue | 105 ++- .../system/task-management/mix-task/index.vue | 315 ++++++--- .../web-gold/src/views/trends/Forecast.vue | 118 +--- 15 files changed, 1652 insertions(+), 1103 deletions(-) create mode 100644 frontend/app/web-gold/src/components/PromptSelector.vue delete mode 100644 frontend/app/web-gold/src/views/system/StyleSettings.vue create mode 100644 frontend/app/web-gold/src/views/system/style-settings/index.vue diff --git a/frontend/app/web-gold/index.html b/frontend/app/web-gold/index.html index b19040a0e6..e035566b55 100644 --- a/frontend/app/web-gold/index.html +++ b/frontend/app/web-gold/index.html @@ -4,7 +4,7 @@ - Vite App + AI营销
diff --git a/frontend/app/web-gold/src/App.vue b/frontend/app/web-gold/src/App.vue index 6243dcd0b4..509b15ff5f 100644 --- a/frontend/app/web-gold/src/App.vue +++ b/frontend/app/web-gold/src/App.vue @@ -72,7 +72,9 @@ onMounted(async () => {}) @@ -112,5 +114,6 @@ onMounted(async () => {}) } .ant-modal .ant-modal-footer { display: flex; + justify-content: end; } diff --git a/frontend/app/web-gold/src/components/PromptSelector.vue b/frontend/app/web-gold/src/components/PromptSelector.vue new file mode 100644 index 0000000000..6e6d3b86c3 --- /dev/null +++ b/frontend/app/web-gold/src/components/PromptSelector.vue @@ -0,0 +1,577 @@ + + + + + \ No newline at end of file diff --git a/frontend/app/web-gold/src/components/material/MaterialMixModal.vue b/frontend/app/web-gold/src/components/material/MaterialMixModal.vue index cd249b27de..deb6db5196 100644 --- a/frontend/app/web-gold/src/components/material/MaterialMixModal.vue +++ b/frontend/app/web-gold/src/components/material/MaterialMixModal.vue @@ -4,7 +4,7 @@ title="素材混剪" centered :confirm-loading="loading" - ok-text="提交混剪" + ok-text="确定" cancel-text="取消" @ok="handleConfirm" @cancel="handleCancel" diff --git a/frontend/app/web-gold/src/components/material/MaterialUploadModal.vue b/frontend/app/web-gold/src/components/material/MaterialUploadModal.vue index 2bf5892244..5a6cb86315 100644 --- a/frontend/app/web-gold/src/components/material/MaterialUploadModal.vue +++ b/frontend/app/web-gold/src/components/material/MaterialUploadModal.vue @@ -25,7 +25,7 @@

点击或拖拽文件到此处上传

- 支持多文件上传,单个文件不超过 100MB + 支持多文件上传,总大小不超过 300MB
支持格式:视频(MP4、MOV、AVI等)、图片(JPG、PNG、GIF等)、音频(MP3、WAV等)

@@ -34,7 +34,12 @@
-
已选择 {{ fileList.length }} 个文件
+
+ 已选择 {{ fileList.length }} 个文件,总大小:{{ getTotalSize() }} + + (已超出 300MB 限制) + +
{ + return fileList.value.reduce((total, item) => { + return total + getFileSize(item) + }, 0) +} + +// 计算总大小(格式化) +const getTotalSize = () => { + return formatFileSize(getTotalSizeBytes()) +} // 监听 visible 变化,重置文件列表 watch(() => props.visible, (newVal) => { @@ -121,12 +139,22 @@ watch(() => props.visible, (newVal) => { // 上传前处理 const handleBeforeUpload = (file) => { - // 检查文件大小 - if (file.size > MAX_FILE_SIZE) { - message.warning(`文件 ${file.name} 超过 100MB,已跳过`) + // 检查单个文件大小 + if (file.size > MAX_SINGLE_FILE_SIZE) { + message.warning(`文件 ${file.name} 超过 300MB,已跳过`) return false } - + + // 计算当前文件列表的总大小(包括新文件) + const currentTotalSize = getTotalSizeBytes() + const newTotalSize = currentTotalSize + file.size + + // 检查总大小 + if (newTotalSize > MAX_TOTAL_SIZE) { + message.warning(`文件总大小超过 300MB(当前:${formatFileSize(currentTotalSize)},新增:${formatFileSize(file.size)}),已跳过`) + return false + } + // 检查是否已存在相同文件 const exists = fileList.value.some(item => { const itemName = getFileName(item) @@ -137,7 +165,7 @@ const handleBeforeUpload = (file) => { message.warning(`文件 ${file.name} 已存在,已跳过`) return false } - + return false // 阻止自动上传 } @@ -197,12 +225,18 @@ const handleConfirm = () => { return } + // 检查总大小 + if (getTotalSizeBytes() > MAX_TOTAL_SIZE) { + message.warning(`文件总大小超过 300MB 限制,请移除部分文件`) + return + } + // 提取文件对象和对应的封面 const filesWithCover = fileList.value .map(item => { const fileObj = item.file || item.originFileObj || item if (!(fileObj instanceof File)) return null - + const fileKey = item.uid || fileObj.name return { file: fileObj, @@ -254,6 +288,9 @@ const handleCancel = () => { font-weight: 500; margin-bottom: 12px; color: var(--color-text); + display: flex; + align-items: center; + flex-wrap: wrap; } .upload-file-items { @@ -267,7 +304,6 @@ const handleCancel = () => { gap: 12px; padding: 8px; border-radius: 4px; - transition: background 0.2s; } .upload-file-item:hover { diff --git a/frontend/app/web-gold/src/router/index.js b/frontend/app/web-gold/src/router/index.js index 6598b79dbf..e74cc7d922 100644 --- a/frontend/app/web-gold/src/router/index.js +++ b/frontend/app/web-gold/src/router/index.js @@ -61,8 +61,8 @@ const routes = [ path: 'system', name: '系统', children: [ - // { path: '', redirect: '/system/style-settings' }, - // { path: 'style-settings', name: '风格设置', component: () => import('../views/system/StyleSettings.vue') }, + { path: '', redirect: '/system/style-settings' }, + { path: 'style-settings', name: '风格设置', component: () => import('../views/system/style-settings/index.vue') }, { path: 'task-management/:type', name: '任务中心', diff --git a/frontend/app/web-gold/src/stores/prompt.js b/frontend/app/web-gold/src/stores/prompt.js index 049e793e7f..d2700af85d 100644 --- a/frontend/app/web-gold/src/stores/prompt.js +++ b/frontend/app/web-gold/src/stores/prompt.js @@ -1,31 +1,116 @@ import { ref } from 'vue' import { defineStore } from 'pinia' import localforage from 'localforage' +import { UserPromptApi } from '@/api/userPrompt' export const usePromptStore = defineStore('prompt', () => { // 存储当前选中的提示词 const currentPrompt = ref('') - + // 存储提示词相关的视频信息 const currentVideoInfo = ref(null) - + + // 存储提示词列表 + const promptList = ref([]) + const promptListLoading = ref(false) + const promptListError = ref(null) + // 设置提示词 function setPrompt(prompt, videoInfo = null) { currentPrompt.value = prompt currentVideoInfo.value = videoInfo } - + // 清空提示词 function clearPrompt() { currentPrompt.value = '' currentVideoInfo.value = null } - + + // 加载提示词列表 + async function loadPromptList(userId) { + if (!userId) { + console.warn('用户未登录,无法加载提示词') + return + } + + // 如果已有数据且不在加载中,直接返回缓存数据 + if (promptList.value.length > 0 && !promptListLoading.value) { + return promptList.value + } + + promptListLoading.value = true + promptListError.value = null + + try { + const response = await UserPromptApi.getUserPromptPage({ + pageNo: 1, + pageSize: 100, + status: undefined + }) + + if (response?.data?.list) { + promptList.value = response.data.list + } else { + promptList.value = [] + } + return promptList.value + } catch (error) { + console.error('加载提示词列表失败:', error) + promptListError.value = error + throw error + } finally { + promptListLoading.value = false + } + } + + // 添加提示词到列表 + function addPromptToList(prompt) { + const existingIndex = promptList.value.findIndex(p => p.id === prompt.id) + if (existingIndex >= 0) { + // 更新已存在的提示词 + promptList.value[existingIndex] = prompt + } else { + // 添加新提示词 + promptList.value.unshift(prompt) + } + } + + // 从列表中删除提示词 + function removePromptFromList(promptId) { + const index = promptList.value.findIndex(p => p.id === promptId) + if (index >= 0) { + promptList.value.splice(index, 1) + } + } + + // 更新提示词 + function updatePromptInList(updatedPrompt) { + const index = promptList.value.findIndex(p => p.id === updatedPrompt.id) + if (index >= 0) { + promptList.value[index] = updatedPrompt + } + } + + // 刷新提示词列表 + async function refreshPromptList(userId) { + promptList.value = [] // 清空缓存,强制重新加载 + return await loadPromptList(userId) + } + return { currentPrompt, currentVideoInfo, + promptList, + promptListLoading, + promptListError, setPrompt, - clearPrompt + clearPrompt, + loadPromptList, + addPromptToList, + removePromptFromList, + updatePromptInList, + refreshPromptList } }, { persist: { @@ -35,6 +120,6 @@ export const usePromptStore = defineStore('prompt', () => { setItem: (key, value) => localforage.setItem(key, value), removeItem: (key) => localforage.removeItem(key) }, - paths: ['currentPrompt', 'currentVideoInfo'] + paths: ['currentPrompt', 'currentVideoInfo', 'promptList'] } }) diff --git a/frontend/app/web-gold/src/views/content-style/Copywriting.vue b/frontend/app/web-gold/src/views/content-style/Copywriting.vue index 32a43a6958..bf8f5bdb5f 100644 --- a/frontend/app/web-gold/src/views/content-style/Copywriting.vue +++ b/frontend/app/web-gold/src/views/content-style/Copywriting.vue @@ -9,6 +9,7 @@ import GmIcon from '@/components/icons/Icon.vue' import { UserPromptApi } from '@/api/userPrompt' import { useUserStore } from '@/stores/user' import GradientButton from '@/components/GradientButton.vue' +import PromptSelector from '@/components/PromptSelector.vue' import { setJSON, getJSON } from '@/utils/storage' import BasicLayout from '@/layouts/components/BasicLayout.vue' @@ -38,28 +39,10 @@ const { getVoiceText } = useVoiceText() // 提示词相关状态 const allPrompts = ref([]) const loadingPrompts = ref(false) -const showAllPromptsModal = ref(false) const selectedPromptId = ref(null) const promptSearchKeyword = ref('') const DISPLAY_COUNT = 6 // 展示的提示词数量 -// 计算属性:展示的部分提示词 -const displayPrompts = computed(() => { - return allPrompts.value.slice(0, DISPLAY_COUNT) -}) - -// 计算属性:过滤后的全部提示词(用于"更多"弹窗) -const filteredPrompts = computed(() => { - if (!promptSearchKeyword.value.trim()) { - return allPrompts.value - } - const keyword = promptSearchKeyword.value.trim().toLowerCase() - return allPrompts.value.filter(p => - p.name.toLowerCase().includes(keyword) || - (p.content && p.content.toLowerCase().includes(keyword)) - ) -}) - /** * 加载用户提示词列表 * 从服务器获取当前用户的提示词,并按创建时间倒序排列 @@ -88,9 +71,6 @@ async function loadUserPrompts() { const timeB = b.createTime ? new Date(b.createTime).getTime() : 0 return timeB - timeA }) - - // 如果用户没有选择提示词,尝试恢复本地存储的选中项或默认选中第一个 - await restoreOrSelectPrompt() } else { throw new Error(response?.msg || response?.message || '加载失败') } @@ -102,97 +82,17 @@ async function loadUserPrompts() { } } -/** - * 保存选中的提示词ID到本地存储 - */ -async function saveSelectedPromptId(promptId) { - if (promptId) { - await setJSON('copywriting_selected_prompt_id', promptId) - } -} -/** - * 从本地存储恢复选中的提示词ID - */ -async function loadSelectedPromptId() { - try { - const savedId = await getJSON('copywriting_selected_prompt_id', null) - return savedId - } catch (error) { - console.error('加载保存的提示词ID失败:', error) - return null - } -} - -/** - * 根据ID选中提示词 - */ -async function selectPromptById(promptId) { - if (!promptId) return false - - const prompt = allPrompts.value.find(p => p.id === promptId) - if (prompt && prompt.content) { - selectedPromptId.value = prompt.id - form.value.prompt = prompt.content - promptStore.setPrompt(prompt.content, prompt) - await saveSelectedPromptId(promptId) - return true - } - return false -} - -/** - * 恢复或选中提示词 - * 优先级:本地存储的选中项 > 第一个提示词 - */ -async function restoreOrSelectPrompt() { - if (allPrompts.value.length === 0) { - return false - } - - // 如果已经有选中项且内容存在,不需要重新选择 - if (selectedPromptId.value && form.value.prompt) { - // 验证选中的提示词是否还在列表中 - const currentPrompt = allPrompts.value.find(p => p.id === selectedPromptId.value) - if (currentPrompt && currentPrompt.content === form.value.prompt) { - return true // 已经正确选中,无需操作 - } - } - - // 尝试恢复本地存储的选中项 - const savedPromptId = await loadSelectedPromptId() - if (savedPromptId) { - const restored = await selectPromptById(savedPromptId) - if (restored) { - return true // 成功恢复保存的选中项 - } - } - - // 如果没有保存的选中项或恢复失败,则选中第一个 - const firstPrompt = allPrompts.value[0] - if (firstPrompt?.content) { - selectedPromptId.value = firstPrompt.id - form.value.prompt = firstPrompt.content - promptStore.setPrompt(firstPrompt.content, firstPrompt) - await saveSelectedPromptId(firstPrompt.id) - return true - } - - return false -} - -// 选择提示词 -async function selectPrompt(prompt) { +// 处理提示词选择 +function handlePromptChange(prompt) { if (!prompt || !prompt.content) { message.warning('提示词内容为空') return } - + selectedPromptId.value = prompt.id form.value.prompt = prompt.content promptStore.setPrompt(prompt.content, prompt) - await saveSelectedPromptId(prompt.id) - showAllPromptsModal.value = false } @@ -217,7 +117,7 @@ async function waitForUserInfo() { async function ensureUserInfoLoaded() { const isLoggedIn = userStore.isLoggedIn const hasNoUserId = !userStore.userId - + if (isLoggedIn && hasNoUserId) { try { await userStore.fetchUserInfo() @@ -239,13 +139,13 @@ async function initializePage() { if (promptStore.currentPrompt) { form.value.prompt = promptStore.currentPrompt } - + // 2. 等待用户信息初始化完成 await waitForUserInfo() - + // 3. 确保用户信息已加载 await ensureUserInfoLoaded() - + // 4. 加载提示词列表 await loadUserPrompts() } @@ -255,34 +155,11 @@ onMounted(() => { initializePage() }) -/** - * keep-alive 激活时的处理 - * 1. 如果有提示词列表,尝试恢复或选中提示词 - * 2. 如果没有提示词列表但用户已登录,加载提示词列表 - */ -onActivated(async () => { - // 如果已经有提示词列表,尝试恢复或选中提示词 - if (allPrompts.value.length > 0) { - await restoreOrSelectPrompt() - } - // 如果提示词列表为空,但用户已登录,则尝试加载 - else if (userStore.userId) { - await loadUserPrompts() - } - // 如果用户未登录,等待用户信息加载 - else if (!userStore.userId && userStore.isLoggedIn) { - await ensureUserInfoLoaded() - if (userStore.userId) { - await loadUserPrompts() - } - } -}) - // 监听 userId 变化:如果之前没有 userId,现在有了,则自动加载提示词 watch(() => userStore.userId, async (newUserId, oldUserId) => { const userIdChanged = newUserId && !oldUserId const hasNoPrompts = allPrompts.value.length === 0 - + if (userIdChanged && hasNoPrompts) { await loadUserPrompts() } @@ -510,47 +387,25 @@ defineOptions({ name: 'ContentStyleCopywriting' }) - -
-
-
- {{ prompt.name }} -
-
-
+ + - -
-
- 您可以在视频分析页面保存风格 -
-
- - -
- + +
+ 您可以在视频分析页面保存风格
@@ -664,58 +519,6 @@ defineOptions({ name: 'ContentStyleCopywriting' })
- - -
- - - - - - -
-
- {{ prompt.name }} -
-
- - -
- 没有找到匹配的提示词 -
-
- - -
diff --git a/frontend/app/web-gold/src/views/dh/VoiceCopy.vue b/frontend/app/web-gold/src/views/dh/VoiceCopy.vue index 2e7fb472d8..d6c0c150f4 100644 --- a/frontend/app/web-gold/src/views/dh/VoiceCopy.vue +++ b/frontend/app/web-gold/src/views/dh/VoiceCopy.vue @@ -57,6 +57,8 @@ v-model:open="modalVisible" :title="isCreateMode ? '新建配音' : '编辑配音'" :width="600" + ok-text="确定" + cancel-text="取消" :confirm-loading="submitting" @ok="handleSubmit" @cancel="handleCancel" diff --git a/frontend/app/web-gold/src/views/material/MaterialListNew.vue b/frontend/app/web-gold/src/views/material/MaterialListNew.vue index 00ced26338..96b34a08dc 100644 --- a/frontend/app/web-gold/src/views/material/MaterialListNew.vue +++ b/frontend/app/web-gold/src/views/material/MaterialListNew.vue @@ -150,6 +150,7 @@ - - - - - diff --git a/frontend/app/web-gold/src/views/system/style-settings/index.vue b/frontend/app/web-gold/src/views/system/style-settings/index.vue new file mode 100644 index 0000000000..1cd3e1b337 --- /dev/null +++ b/frontend/app/web-gold/src/views/system/style-settings/index.vue @@ -0,0 +1,600 @@ + + + + + + diff --git a/frontend/app/web-gold/src/views/system/task-management/digital-human-task/index.vue b/frontend/app/web-gold/src/views/system/task-management/digital-human-task/index.vue index 59e1efb4aa..e873467668 100644 --- a/frontend/app/web-gold/src/views/system/task-management/digital-human-task/index.vue +++ b/frontend/app/web-gold/src/views/system/task-management/digital-human-task/index.vue @@ -59,16 +59,7 @@ >