素材云下载

This commit is contained in:
孙佳艺
2026-06-25 11:11:06 +08:00
parent 5fc1e43d4e
commit 87e412ef74
15 changed files with 767 additions and 911 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 MiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

+1 -1
View File
@@ -28,7 +28,7 @@
} }
})(); })();
</script> </script>
<script type="module" crossorigin src="/assets/index-BwL6llN9.js"></script> <script type="module" crossorigin src="/assets/index-BjRp0K8U.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-eLRg4pQk.css"> <link rel="stylesheet" crossorigin href="/assets/index-eLRg4pQk.css">
</head> </head>
<body> <body>
+94 -1
View File
@@ -12,6 +12,7 @@
"@types/three": "^0.184.1", "@types/three": "^0.184.1",
"antd": "^6.3.7", "antd": "^6.3.7",
"dayjs": "^1.11.20", "dayjs": "^1.11.20",
"jszip": "^3.10.1",
"plyr-react": "^6.0.0", "plyr-react": "^6.0.0",
"qrcode.react": "^4.2.0", "qrcode.react": "^4.2.0",
"react": "^19.2.5", "react": "^19.2.5",
@@ -2501,6 +2502,12 @@
"url": "https://opencollective.com/core-js" "url": "https://opencollective.com/core-js"
} }
}, },
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -3083,6 +3090,12 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/imurmurhash": { "node_modules/imurmurhash": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -3093,6 +3106,12 @@
"node": ">=0.8.19" "node": ">=0.8.19"
} }
}, },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-binary-path": { "node_modules/is-binary-path": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -3161,6 +3180,12 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3241,6 +3266,18 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"license": "(MIT OR GPL-3.0-or-later)",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -3265,6 +3302,15 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lightningcss": { "node_modules/lightningcss": {
"version": "1.32.0", "version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
@@ -3770,6 +3816,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/path-exists": { "node_modules/path-exists": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -4040,6 +4092,12 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -4179,6 +4237,21 @@
"pify": "^2.3.0" "pify": "^2.3.0"
} }
}, },
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -4303,6 +4376,12 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/scheduler": { "node_modules/scheduler": {
"version": "0.27.0", "version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
@@ -4334,6 +4413,12 @@
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -4367,6 +4452,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/string-convert": { "node_modules/string-convert": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
@@ -4659,7 +4753,6 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/uuid": { "node_modules/uuid": {
+1
View File
@@ -14,6 +14,7 @@
"@types/three": "^0.184.1", "@types/three": "^0.184.1",
"antd": "^6.3.7", "antd": "^6.3.7",
"dayjs": "^1.11.20", "dayjs": "^1.11.20",
"jszip": "^3.10.1",
"plyr-react": "^6.0.0", "plyr-react": "^6.0.0",
"qrcode.react": "^4.2.0", "qrcode.react": "^4.2.0",
"react": "^19.2.5", "react": "^19.2.5",
+49 -34
View File
@@ -26,6 +26,8 @@ import {
uploadVideo, getCreditRatios, deleteHistory, calculateCredits uploadVideo, getCreditRatios, deleteHistory, calculateCredits
} from '../api'; } from '../api';
import { useAppStore } from '../store/useAppStore';
import { import {
PlusOutlined, PlusOutlined,
MenuUnfoldOutlined, MenuUnfoldOutlined,
@@ -112,9 +114,31 @@ const AIChatPage: React.FC = () => {
const [inputValue, setInputValue] = useState<string>(''); const [inputValue, setInputValue] = useState<string>('');
const [mediaType, setMediaType] = useState<string>('image'); // 从 store 读取生成配置状态
const {
const [countType, setCountType] = useState<string>('请选择'); mediaType,
countType,
selectedRatio,
selectedResolution,
width,
height,
videoDuration,
videoAspectRatio,
videoResolution,
engineOptions,
enginesele,
setMediaType,
setCountType,
setSelectedRatio,
setSelectedResolution,
setWidth,
setHeight,
setVideoDuration,
setVideoAspectRatio,
setVideoResolution,
setEngineOptions,
setEnginesele,
} = useAppStore();
const [uploading, setUploading] = useState<boolean>(false); const [uploading, setUploading] = useState<boolean>(false);
@@ -183,11 +207,6 @@ const AIChatPage: React.FC = () => {
const [attachmentPopupMessageId, setAttachmentPopupMessageId] = useState<string | null>(null); const [attachmentPopupMessageId, setAttachmentPopupMessageId] = useState<string | null>(null);
const [attachmentPopupPosition, setAttachmentPopupPosition] = useState({ x: 0, y: 0 }); const [attachmentPopupPosition, setAttachmentPopupPosition] = useState({ x: 0, y: 0 });
// 图片设置相关状态
const [selectedRatio, setSelectedRatio] = useState<string>('1:1');
const [selectedResolution, setSelectedResolution] = useState<string>('2K');
const [width, setWidth] = useState<number>(2048);
const [height, setHeight] = useState<number>(2048);
const [showImageSettingsModal, setShowImageSettingsModal] = useState(false); const [showImageSettingsModal, setShowImageSettingsModal] = useState(false);
const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false); const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false);
const [ratioOptions, setRatioOptions] = useState([]); const [ratioOptions, setRatioOptions] = useState([]);
@@ -196,22 +215,8 @@ const AIChatPage: React.FC = () => {
const [blindex, setBlindex] = useState<any>(0); const [blindex, setBlindex] = useState<any>(0);
const [fblindex, setFBlindex] = useState<any>(0); const [fblindex, setFBlindex] = useState<any>(0);
// 视频设置相关状态
const [videoDuration, setVideoDuration] = useState(5);
const [videoAspectRatio, setVideoAspectRatio] = useState<string>('16:9');
const [videoResolution, setVideoResolution] = useState<string>('720p');
const [showEngineModal, setShowEngineModal] = useState(false); const [showEngineModal, setShowEngineModal] = useState(false);
const [engineOptions, setEngineOptions] = useState<{
ratios: string[];
resolutions: string[];
durations: number[];
}>({
ratios: ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
resolutions: ['480p', '720p', '1080p'],
durations: [5, 8, 10, 12, 15],
});
const [enginesele, setEnginesele] = useState<any>([]);
const [creditRatios, setCreditRatios] = useState<any[]>([]); const [creditRatios, setCreditRatios] = useState<any[]>([]);
const [cimage, setCimage] = useState<any[]>([]); const [cimage, setCimage] = useState<any[]>([]);
const [creditCalculationData, setCreditCalculationData] = useState<any[]>([]); const [creditCalculationData, setCreditCalculationData] = useState<any[]>([]);
@@ -359,23 +364,33 @@ const AIChatPage: React.FC = () => {
// 如果是视频模式,初始化视频参数选项 // 如果是视频模式,初始化视频参数选项
if (data.engine.video && data.engine.video.length > 0) { if (data.engine.video && data.engine.video.length > 0) {
const defaultEngine = data.engine.video[0]; const defaultEngine = data.engine.video[0];
// 查找用户之前选择的引擎(如果存在)
const savedEngine = data.engine.video.find((e: any) => e.id === countType);
const targetEngine = savedEngine || defaultEngine;
// 更新引擎选项为当前引擎支持的参数
setEngineOptions({ setEngineOptions({
ratios: defaultEngine.supportedRatios || ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'], ratios: targetEngine.supportedRatios || ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
resolutions: defaultEngine.supportedResolutions || ['480p', '720p', '1080p'], resolutions: targetEngine.supportedResolutions || ['480p', '720p', '1080p'],
durations: defaultEngine.supportedDurations || [5, 8, 10, 12, 15], durations: targetEngine.supportedDurations || [5, 8, 10, 12, 15],
}); });
// 设置默认选中值
if (defaultEngine.supportedRatios?.length > 0) { // 确保视频参数在引擎支持的范围内
setVideoAspectRatio(defaultEngine.supportedRatios[0]); if (!targetEngine.supportedRatios?.includes(videoAspectRatio)) {
setVideoAspectRatio(targetEngine.supportedRatios?.[0] || '16:9');
} }
if (defaultEngine.supportedResolutions?.length > 0) { if (!targetEngine.supportedResolutions?.includes(videoResolution)) {
setVideoResolution(defaultEngine.supportedResolutions[0]); setVideoResolution(targetEngine.supportedResolutions?.[0] || '720p');
} }
if (defaultEngine.supportedDurations?.length > 0) { if (!targetEngine.supportedDurations?.includes(videoDuration)) {
setVideoDuration(defaultEngine.supportedDurations[0]); setVideoDuration(targetEngine.supportedDurations?.[0] || 5);
}
// 如果之前没有选择过引擎(还是默认值),才设置默认引擎
if (countType === '请选择') {
setCountType(targetEngine.id);
} }
// 设置默认引擎
setCountType(defaultEngine.id);
} }
}) })
.catch(() => { .catch(() => {
+92 -4
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useLayoutEffect, useRef, useCallback } from 'react'; import React, { useEffect, useState, useLayoutEffect, useRef, useCallback } from 'react';
import { Button, Empty, Input, Select, Space, Typography, Tag, message, Modal, Table, DatePicker } from 'antd'; import { Button, Empty, Input, Select, Space, Typography, Tag, message, Modal, Table, DatePicker } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import JSZip from 'jszip';
import { import {
FilterOutlined, FilterOutlined,
VideoCameraOutlined, VideoCameraOutlined,
@@ -601,6 +602,81 @@ const GeneratedRecord: React.FC = () => {
} }
}; };
const handleDownloadSelected = async () => {
if (selectedItems.size === 0) {
message.warning('请先选择要下载的媒体');
return;
}
// 检查下载数量限制
if (selectedItems.size > 10) {
message.warning('最多只能单次下载10个文件');
return;
}
const selectedContent: any[] = [];
recordlist.forEach((group: any) => {
group.items.forEach((item: any) => {
if (selectedItems.has(getItemResourceId(item))) {
selectedContent.push(item);
}
});
});
const zip = new JSZip();
const baseUrl = import.meta.env.VITE_API_BASE || "http://localhost:8000";
const folder = zip.folder('downloads');
let hasError = false;
let successCount = 0;
message.loading({ content: '下载中,请稍候...', key: 'downloadProgress' });
for (const item of selectedContent) {
const url = `${baseUrl}${item.videoUrl || item.imageUrl}`;
const filename = ((item.videoUrl || item.imageUrl).split('/').pop() || `file_${Date.now()}`).split('?')[0];
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Network response was not ok');
const blob = await response.blob();
folder?.file(filename, blob);
successCount++;
} catch (error) {
console.warn(`文件下载失败(CORS限制): ${filename},将使用备用方式下载`);
hasError = true;
break;
}
}
if (hasError) {
// Fallback: 逐个打开文件下载(不受 CORS 限制)
message.destroy('downloadProgress');
message.info('由于跨域限制,将逐个下载文件');
selectedContent.forEach((item, index) => {
setTimeout(() => {
const url = `${baseUrl}${item.videoUrl || item.imageUrl}&download=1`;
const link = document.createElement('a');
link.href = url;
link.download = '';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}, index * 500);
});
return;
}
const zipBlob = await zip.generateAsync({ type: 'blob' });
const link = document.createElement('a');
link.href = URL.createObjectURL(zipBlob);
link.download = `downloads_${Date.now()}.zip`;
link.click();
URL.revokeObjectURL(link.href);
message.destroy('downloadProgress');
message.success(`下载完成,共 ${successCount} 个文件`);
};
const handleBatchUploadSelected = () => { const handleBatchUploadSelected = () => {
if (selectedItems.size === 0) { if (selectedItems.size === 0) {
message.warning('请先选择要上传的媒体'); message.warning('请先选择要上传的媒体');
@@ -828,7 +904,7 @@ const GeneratedRecord: React.FC = () => {
}]; }];
if (recordList && recordList[0].items.length > 0) { if (recordList && recordList[0].items.length > 0) {
setRecordList(recordList); setRecordList(recordList);
}else{ } else {
setRecordList([]); setRecordList([]);
} }
}).catch((err) => { }).catch((err) => {
@@ -927,7 +1003,7 @@ const GeneratedRecord: React.FC = () => {
}, [filterType, filterMedia]); }, [filterType, filterMedia]);
return ( return (
<div style={{ minHeight: 'calc(100vh - 90px)', background: '#ffffffff' , overflowY: 'auto'}} > <div style={{ minHeight: 'calc(100vh - 90px)', background: '#ffffffff', overflowY: 'auto' }} >
{/* 操作栏:筛选 + 上传按钮 */} {/* 操作栏:筛选 + 上传按钮 */}
<div style={{ <div style={{
display: 'flex', display: 'flex',
@@ -1008,6 +1084,18 @@ const GeneratedRecord: React.FC = () => {
> >
</Button> </Button>
<Button
onClick={() => handleDownloadSelected()}
style={{
borderRadius: 8,
background: '#f8f9fc',
border: '1px solid #e2e8f0',
color: '#222222ff',
fontWeight: 600,
}}
>
{selectedItems.size}
</Button>
<Button <Button
type="primary" type="primary"
onClick={handleBatchUploadSelected} onClick={handleBatchUploadSelected}
@@ -1036,7 +1124,7 @@ const GeneratedRecord: React.FC = () => {
fontWeight: 600, fontWeight: 600,
}} }}
> >
</Button> </Button>
)} )}
@@ -1534,7 +1622,7 @@ const GeneratedRecord: React.FC = () => {
open={uploadHistoryModalVisible} open={uploadHistoryModalVisible}
onCancel={() => setUploadHistoryModalVisible(false)} onCancel={() => setUploadHistoryModalVisible(false)}
footer={null} footer={null}
width={ 800 } width={800}
style={{ borderRadius: 8 }} style={{ borderRadius: 8 }}
mask={{ closable: false }} mask={{ closable: false }}
> >
+86
View File
@@ -15,6 +15,23 @@ interface AppState {
records: api.GenerationRecordPageListOut; records: api.GenerationRecordPageListOut;
loading: boolean; loading: boolean;
// 生成配置状态 - 页面跳转时保留,刷新时重置
mediaType: string;
countType: string;
selectedRatio: string;
selectedResolution: string;
width: number;
height: number;
videoDuration: number;
videoAspectRatio: string;
videoResolution: string;
engineOptions: {
ratios: string[];
resolutions: string[];
durations: number[];
};
enginesele: any;
fetchProjects: () => Promise<void>; fetchProjects: () => Promise<void>;
createProject: (name: string, industry: Industry) => Promise<Project>; createProject: (name: string, industry: Industry) => Promise<Project>;
deleteProject: (id: string) => Promise<void>; deleteProject: (id: string) => Promise<void>;
@@ -23,6 +40,23 @@ interface AppState {
optimizePrompt: (projectId: string, params: OptimizeParams) => Promise<OptimizeResult>; optimizePrompt: (projectId: string, params: OptimizeParams) => Promise<OptimizeResult>;
generateVideo: (recordId: string, params: GenerateParams) => Promise<GenerationRecord>; generateVideo: (recordId: string, params: GenerateParams) => Promise<GenerationRecord>;
updateRecordReferences: (recordId: string, references: MediaReference[]) => void; updateRecordReferences: (recordId: string, references: MediaReference[]) => void;
// 生成配置状态更新方法
setMediaType: (mediaType: string) => void;
setCountType: (countType: string) => void;
setImageSettings: (ratio: string, resolution: string, width: number, height: number) => void;
setVideoSettings: (duration: number, aspectRatio: string, resolution: string) => void;
setEngineOptions: (options: { ratios: string[]; resolutions: string[]; durations: number[] }) => void;
// 单独的 setter 方法
setSelectedRatio: (ratio: string) => void;
setSelectedResolution: (resolution: string) => void;
setWidth: (width: number) => void;
setHeight: (height: number) => void;
setVideoDuration: (duration: number) => void;
setVideoAspectRatio: (aspectRatio: string) => void;
setVideoResolution: (resolution: string) => void;
setEnginesele: (enginesele: any) => void;
resetGenerationConfig: () => void;
} }
export const useAppStore = create<AppState>((set, get) => ({ export const useAppStore = create<AppState>((set, get) => ({
@@ -30,6 +64,23 @@ export const useAppStore = create<AppState>((set, get) => ({
records: emptyRecordsPage(), records: emptyRecordsPage(),
loading: false, loading: false,
// 生成配置状态初始值
mediaType: 'image',
countType: '请选择',
selectedRatio: '1:1',
selectedResolution: '2K',
width: 2048,
height: 2048,
videoDuration: 5,
videoAspectRatio: '16:9',
videoResolution: '720p',
engineOptions: {
ratios: ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
resolutions: ['480p', '720p', '1080p'],
durations: [5, 8, 10, 12, 15],
},
enginesele: [],
fetchProjects: async () => { fetchProjects: async () => {
set({ loading: true }); set({ loading: true });
try { try {
@@ -99,4 +150,39 @@ export const useAppStore = create<AppState>((set, get) => ({
}, },
}); });
}, },
// 生成配置状态更新方法
setMediaType: (mediaType) => set({ mediaType }),
setCountType: (countType) => set({ countType }),
setImageSettings: (ratio, resolution, width, height) =>
set({ selectedRatio: ratio, selectedResolution: resolution, width, height }),
setVideoSettings: (duration, aspectRatio, resolution) =>
set({ videoDuration: duration, videoAspectRatio: aspectRatio, videoResolution: resolution }),
setEngineOptions: (options) => set({ engineOptions: options }),
// 单独的 setter 方法
setSelectedRatio: (ratio) => set({ selectedRatio: ratio }),
setSelectedResolution: (resolution) => set({ selectedResolution: resolution }),
setWidth: (width) => set({ width }),
setHeight: (height) => set({ height }),
setVideoDuration: (duration) => set({ videoDuration: duration }),
setVideoAspectRatio: (aspectRatio) => set({ videoAspectRatio: aspectRatio }),
setVideoResolution: (resolution) => set({ videoResolution: resolution }),
setEnginesele: (enginesele) => set({ enginesele }),
resetGenerationConfig: () => set({
mediaType: 'image',
countType: '请选择',
selectedRatio: '1:1',
selectedResolution: '2K',
width: 2048,
height: 2048,
videoDuration: 5,
videoAspectRatio: '16:9',
videoResolution: '720p',
engineOptions: {
ratios: ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
resolutions: ['480p', '720p', '1080p'],
durations: [5, 8, 10, 12, 15],
},
enginesele: [],
}),
})); }));