mixvideo-v2/apps/desktop/src/stores/templateStore.ts

283 lines
7.9 KiB
TypeScript

import React from 'react';
import { create } from 'zustand';
import { invoke } from '@tauri-apps/api/core';
import {
Template,
TemplateListResponse,
ImportTemplateRequest,
BatchImportRequest,
ImportProgress,
ImportStatus,
SegmentMatchingRule
} from '../types/template';
interface TemplateQueryParams {
search_keyword?: string;
import_status?: ImportStatus;
project_id?: string;
page?: number;
page_size?: number;
}
interface TemplateStore {
templates: Template[];
currentTemplate: Template | null;
importProgress: Record<string, ImportProgress>;
isLoading: boolean;
error: string | null;
// Actions
fetchTemplates: (params?: TemplateQueryParams) => Promise<TemplateListResponse>;
getTemplateById: (id: string) => Promise<Template | null>;
importTemplate: (request: ImportTemplateRequest) => Promise<string>;
batchImportTemplates: (request: BatchImportRequest) => Promise<void>;
deleteTemplate: (id: string) => Promise<void>;
updateTemplate: (template: Template) => Promise<void>;
getImportProgress: (templateId: string) => Promise<ImportProgress | null>;
updateSegmentMatchingRule: (segmentId: string, matchingRule: SegmentMatchingRule) => Promise<void>;
getSegmentMatchingRule: (segmentId: string) => Promise<SegmentMatchingRule>;
clearError: () => void;
setCurrentTemplate: (template: Template | null) => void;
}
export const useTemplateStore = create<TemplateStore>((set, get) => ({
templates: [],
currentTemplate: null,
importProgress: {},
isLoading: false,
error: null,
fetchTemplates: async (params = {}) => {
set({ isLoading: true, error: null });
try {
const response: TemplateListResponse = await invoke('list_templates', {
options: params
});
set({ templates: response.templates, isLoading: false });
return response;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '获取模板列表失败';
set({ error: errorMessage, isLoading: false });
throw error;
}
},
getTemplateById: async (id: string) => {
set({ isLoading: true, error: null });
try {
const template: Template | null = await invoke('get_template_by_id', { id });
set({ currentTemplate: template, isLoading: false });
return template;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '获取模板详情失败';
set({ error: errorMessage, isLoading: false });
throw error;
}
},
importTemplate: async (request: ImportTemplateRequest) => {
set({ isLoading: true, error: null });
try {
const templateId: string = await invoke('import_template', { request });
// 刷新模板列表
await get().fetchTemplates();
set({ isLoading: false });
return templateId;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '导入模板失败';
set({ error: errorMessage, isLoading: false });
throw error;
}
},
batchImportTemplates: async (request: BatchImportRequest) => {
set({ isLoading: true, error: null });
try {
await invoke('batch_import_templates', { request });
// 刷新模板列表
await get().fetchTemplates();
set({ isLoading: false });
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '批量导入失败';
set({ error: errorMessage, isLoading: false });
throw error;
}
},
deleteTemplate: async (id: string) => {
set({ isLoading: true, error: null });
try {
await invoke('delete_template', { id });
// 从本地状态中移除模板
set(state => ({
templates: state.templates.filter(t => t.id !== id),
currentTemplate: state.currentTemplate?.id === id ? null : state.currentTemplate,
isLoading: false
}));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '删除模板失败';
set({ error: errorMessage, isLoading: false });
throw error;
}
},
updateTemplate: async (template: Template) => {
set({ isLoading: true, error: null });
try {
await invoke('update_template', { template });
// 更新本地状态
set(state => ({
templates: state.templates.map(t => t.id === template.id ? template : t),
currentTemplate: state.currentTemplate?.id === template.id ? template : state.currentTemplate,
isLoading: false
}));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '更新模板失败';
set({ error: errorMessage, isLoading: false });
throw error;
}
},
getImportProgress: async (templateId: string) => {
try {
const progress: ImportProgress | null = await invoke('get_import_progress', { templateId });
if (progress) {
set(state => ({
importProgress: {
...state.importProgress,
[templateId]: progress
}
}));
}
return progress;
} catch (error) {
console.error('获取导入进度失败:', error);
return null;
}
},
clearError: () => {
set({ error: null });
},
updateSegmentMatchingRule: async (segmentId: string, matchingRule: SegmentMatchingRule) => {
set({ error: null });
try {
await invoke('update_segment_matching_rule', {
segmentId,
matchingRule
});
// 如果当前有模板详情,刷新模板数据
const currentTemplate = get().currentTemplate;
if (currentTemplate) {
await get().getTemplateById(currentTemplate.id);
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '更新片段匹配规则失败';
set({ error: errorMessage });
throw error;
}
},
getSegmentMatchingRule: async (segmentId: string) => {
set({ error: null });
try {
const matchingRule: SegmentMatchingRule = await invoke('get_segment_matching_rule', {
segmentId
});
return matchingRule;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '获取片段匹配规则失败';
set({ error: errorMessage });
throw error;
}
},
setCurrentTemplate: (template: Template | null) => {
set({ currentTemplate: template });
},
}));
// 导入进度监听 Hook
export const useImportProgress = (templateId?: string) => {
const { importProgress, getImportProgress } = useTemplateStore();
React.useEffect(() => {
if (!templateId) return;
let interval: NodeJS.Timeout | null = null;
let isMounted = true;
const fetchProgress = async () => {
if (!isMounted) return;
const progress = await getImportProgress(templateId);
// 如果导入完成或失败,停止轮询
if (progress && (
progress.status === ImportStatus.Completed ||
progress.status === ImportStatus.Failed
)) {
if (interval) {
clearInterval(interval);
interval = null;
}
return;
}
};
// 立即获取一次
fetchProgress();
// 开始轮询
interval = setInterval(fetchProgress, 1000);
return () => {
isMounted = false;
if (interval) {
clearInterval(interval);
}
};
}, [templateId, getImportProgress]);
return templateId ? importProgress[templateId] : null;
};
// 批量导入进度监听 Hook
export const useBatchImportProgress = () => {
const [batchProgress, setBatchProgress] = React.useState<any>(null);
React.useEffect(() => {
const interval = setInterval(async () => {
try {
const progress = await invoke('get_batch_import_progress');
setBatchProgress(progress);
} catch (error) {
// 忽略错误,可能是没有正在进行的批量导入
}
}, 1000);
return () => clearInterval(interval);
}, []);
return batchProgress;
};