项目/AI生成链路合并

This commit is contained in:
2026-07-20 13:48:17 +08:00
parent 34ca98f9eb
commit fe5a59d725
73 changed files with 5819 additions and 2573 deletions
+6 -4
View File
@@ -348,8 +348,9 @@ export async function deleteIndustryConfig(id: string): Promise<void> {
await api.delete(`/admin/industry-configs/${id}`);
}
export async function getVideoEngines(): Promise<any[]> {
return api.get('/admin/video-engines');
export async function getVideoEngines(options?: { includeDeleted?: boolean }): Promise<any[]> {
const query = options?.includeDeleted ? '?include_deleted=true' : '';
return api.get(`/admin/video-engines${query}`);
}
export async function saveVideoEngine(engine: any): Promise<any> {
@@ -361,8 +362,9 @@ export async function deleteVideoEngine(id: string): Promise<void> {
await api.delete(`/admin/video-engines/${id}`);
}
export async function getImageEngines(): Promise<any[]> {
return api.get('/admin/image-engines');
export async function getImageEngines(options?: { includeDeleted?: boolean }): Promise<any[]> {
const query = options?.includeDeleted ? '?include_deleted=true' : '';
return api.get(`/admin/image-engines${query}`);
}
export async function saveImageEngine(engine: any): Promise<any> {
@@ -29,8 +29,13 @@ import {
VideoCameraOutlined,
} from '@ant-design/icons';
import dayjs from 'dayjs';
import { getAdminGenerationAiTasks } from '../api';
import type { GenerationAIMediaReference, GenerationAITaskOut } from '../types';
import { getAdminGenerationAiTasks, getImageEngines, getVideoEngines } from '../api';
import type {
GenerationAiImageEngine,
GenerationAIMediaReference,
GenerationAITaskOut,
GenerationAiVideoEngine,
} from '../types';
import { formatDate } from '../utils/formatDate';
import GenerationTaskResourceGrid from '../components/generation/GenerationTaskResourceGrid';
@@ -240,6 +245,9 @@ const AdminGenerationAiRecords: React.FC = () => {
const [createdRange, setCreatedRange] = useState<any>([todayStart(), todayEnd()]);
const [queryCreatedRange, setQueryCreatedRange] = useState<any>([todayStart(), todayEnd()]);
const [reloadKey, setReloadKey] = useState(0);
const [engineListLoading, setEngineListLoading] = useState(false);
const [imageEngines, setImageEngines] = useState<GenerationAiImageEngine[]>([]);
const [videoEngines, setVideoEngines] = useState<GenerationAiVideoEngine[]>([]);
const [preview, setPreview] = useState<GenerationAITaskOut | null>(null);
const [resourceState, setResourceState] = useState<PreviewResourceState>(EMPTY_RESOURCE_STATE);
@@ -280,6 +288,64 @@ const AdminGenerationAiRecords: React.FC = () => {
load();
}, [load, reloadKey]);
useEffect(() => {
let cancelled = false;
const loadEngineOptions = async () => {
setEngineListLoading(true);
try {
const [images, videos] = await Promise.all([
getImageEngines({ includeDeleted: true }),
getVideoEngines({ includeDeleted: true }),
]);
if (!cancelled) {
setImageEngines(images || []);
setVideoEngines(videos || []);
}
} catch (error: any) {
if (!cancelled) {
message.error(error?.message || '加载模型引擎列表失败');
}
} finally {
if (!cancelled) setEngineListLoading(false);
}
};
void loadEngineOptions();
return () => {
cancelled = true;
};
}, []);
const engineOptions = useMemo(() => {
const toOption = (
engine: GenerationAiImageEngine | GenerationAiVideoEngine,
type: 'image' | 'video',
) => {
const deleted = Boolean(engine.deletedAt);
const typeText = type === 'image' ? '图片' : '视频';
const deletedText = deleted ? '[已删除]' : '';
const detailText = [engine.name, engine.modelName, engine.provider, engine.id]
.filter(Boolean)
.join(' / ');
const label = `[${typeText}]${deletedText} ${detailText}`;
return {
value: engine.id,
label,
searchText: [engine.id, engine.name, engine.modelName, engine.provider, typeText, deleted ? '已删除' : '']
.filter(Boolean)
.join(' ')
.toLowerCase(),
};
};
const merged = [
...imageEngines.map((engine) => toOption(engine, 'image')),
...videoEngines.map((engine) => toOption(engine, 'video')),
];
return Array.from(new Map(merged.map((option) => [option.value, option])).values());
}, [imageEngines, videoEngines]);
useEffect(() => {
if (!preview) {
setResourceState(EMPTY_RESOURCE_STATE);
@@ -969,21 +1035,17 @@ const AdminGenerationAiRecords: React.FC = () => {
<Select
allowClear
showSearch
loading={engineListLoading}
placeholder="引擎筛选"
value={filterEngineId || undefined}
style={{ width: 180 }}
style={{ width: 260 }}
onChange={(v) => { setFilterEngineId(v || ''); setPage(1); setQueryEngineId(v || ''); }}
optionFilterProp="label"
options={Array.from(
new Map(
records
.filter((r) => r.engineId)
.map((r) => [r.engineId, {
value: r.engineId,
label: getEngineName(r.engineSnapshot as any) || r.engineId,
}]),
).values(),
)}
filterOption={(input, option: any) =>
String(option?.searchText || option?.label || '')
.toLowerCase()
.includes(input.trim().toLowerCase())
}
options={engineOptions}
/>
<RangePicker
value={createdRange}
+4
View File
@@ -285,6 +285,8 @@ export interface GenerationAiImageEngine {
maxGenerationCount: number;
multiImageMaxImages: number;
maxReferenceImageCount: number;
isActive?: boolean;
deletedAt?: string | null;
}
export interface GenerationAiVideoEngine {
@@ -305,6 +307,8 @@ export interface GenerationAiVideoEngine {
priority: number;
multiGenerationEnabled: boolean;
maxGenerationCount: number;
isActive?: boolean;
deletedAt?: string | null;
}
export interface GenerationAiEnginesResponse {