diff --git a/python_core/services/template_manager.py b/python_core/services/template_manager.py index a7961d7..0bd672e 100644 --- a/python_core/services/template_manager.py +++ b/python_core/services/template_manager.py @@ -119,19 +119,21 @@ class TemplateManager: if progress_callback: progress_callback(f"Found {total_templates} potential templates") - + for i, template_dir in enumerate(subdirs): template_path = os.path.join(source_folder, template_dir) - + if progress_callback: progress_callback(f"Processing template {i+1}/{total_templates}: {template_dir}") - + try: template_info = self._import_single_template(template_path, template_dir) if template_info: result['imported_count'] += 1 result['imported_templates'].append(template_info) logger.info(f"Successfully imported template: {template_dir}") + if progress_callback: + progress_callback(f"✅ Successfully imported: {template_dir}") else: result['failed_count'] += 1 result['failed_templates'].append({ @@ -139,7 +141,9 @@ class TemplateManager: 'error': 'No draft_content.json found or invalid template' }) logger.warning(f"Failed to import template: {template_dir}") - + if progress_callback: + progress_callback(f"❌ Failed to import: {template_dir} (No draft_content.json found)") + except Exception as e: result['failed_count'] += 1 result['failed_templates'].append({ @@ -147,15 +151,17 @@ class TemplateManager: 'error': str(e) }) logger.error(f"Error importing template {template_dir}: {e}") + if progress_callback: + progress_callback(f"❌ Error importing: {template_dir} ({str(e)})") # Save metadata self._save_metadata() - + result['msg'] = f"Import completed. Success: {result['imported_count']}, Failed: {result['failed_count']}" logger.info(result['msg']) - + if progress_callback: - progress_callback(result['msg']) + progress_callback(f"🎉 Import completed! Success: {result['imported_count']}, Failed: {result['failed_count']}") except Exception as e: result['status'] = False @@ -381,6 +387,37 @@ def main(): return def progress_callback(message): + # Parse progress information from message + if "Processing template" in message: + # Extract template info from message like "Processing template 1/3: Template_Name" + parts = message.split(":") + if len(parts) >= 2: + template_name = parts[1].strip() + # Extract progress numbers + if "/" in parts[0]: + progress_part = parts[0].split("Processing template")[1].strip() + if "/" in progress_part: + current, total = progress_part.split("/") + try: + current_num = int(current.strip()) + total_num = int(total.strip()) + progress_percent = (current_num / total_num) * 100 + + progress.report( + step="import", + progress=progress_percent, + message=message, + details={ + "current_template": template_name, + "total_templates": total_num, + "processed_templates": current_num + } + ) + return + except ValueError: + pass + + # Default progress step progress.step("import", message) result = manager.batch_import_templates(args.source_folder, progress_callback) diff --git a/src/pages/TemplateManagePage.tsx b/src/pages/TemplateManagePage.tsx index 148aec5..0626d14 100644 --- a/src/pages/TemplateManagePage.tsx +++ b/src/pages/TemplateManagePage.tsx @@ -31,6 +31,16 @@ interface ImportResult { }> } +interface ImportProgress { + step: string + progress: number // 0-100 + message: string + currentTemplate?: string + totalTemplates?: number + processedTemplates?: number + timestamp: number +} + const TemplateManagePage: React.FC = () => { const [templates, setTemplates] = useState([]) const [loading, setLoading] = useState(false) @@ -39,6 +49,9 @@ const TemplateManagePage: React.FC = () => { const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid') const [selectedTemplate, setSelectedTemplate] = useState(null) const [importResult, setImportResult] = useState(null) + const [importProgress, setImportProgress] = useState(null) + const [importLogs, setImportLogs] = useState([]) + const [showImportModal, setShowImportModal] = useState(false) // Load templates on component mount useEffect(() => { @@ -67,10 +80,38 @@ const TemplateManagePage: React.FC = () => { const folderResult = await invoke('select_folder') if (!folderResult) return + // Reset states setImporting(true) setImportResult(null) + setImportProgress(null) + setImportLogs([]) + setShowImportModal(true) + // Progress callback + const onProgress = (progress: ImportProgress) => { + setImportProgress(progress) + setImportLogs(prev => [...prev, `[${new Date().toLocaleTimeString()}] ${progress.message}`]) + } + + // Simulate initial progress + onProgress({ + step: "scanning", + progress: 10, + message: "正在扫描模板文件夹...", + timestamp: Date.now() + }) + + // For now, use the regular import and simulate progress + // TODO: Switch to batchImportTemplatesWithProgress when backend is ready const result = await TemplateService.batchImportTemplates(folderResult) + + // Simulate completion progress + onProgress({ + step: "complete", + progress: 100, + message: "模板导入完成", + timestamp: Date.now() + }) setImportResult(result) if (result.status && result.imported_count > 0) { @@ -350,6 +391,122 @@ const TemplateManagePage: React.FC = () => { )} + {/* Import Progress Modal */} + {showImportModal && ( +
+
+
+
+

模板导入进度

+ {!importing && ( + + )} +
+ + {/* Progress Bar */} + {importProgress && ( +
+
+ {importProgress.step} + + {importProgress.progress >= 0 ? `${Math.round(importProgress.progress)}%` : '处理中...'} + +
+
+
= 0 ? `${importProgress.progress}%` : '50%' + }} + >
+
+

{importProgress.message}

+ {importProgress.processedTemplates !== undefined && importProgress.totalTemplates !== undefined && ( +

+ 已处理: {importProgress.processedTemplates} / {importProgress.totalTemplates} +

+ )} +
+ )} + + {/* Real-time Logs */} +
+

实时日志

+
+
+ {importLogs.map((log, index) => ( +
+ {log} +
+ ))} + {importLogs.length === 0 && ( +
等待日志输出...
+ )} +
+
+
+ + {/* Import Result */} + {importResult && ( +
+
+
+

+ 导入完成 +

+

+ {importResult.msg} +

+ {importResult.imported_count > 0 && ( +

+ 成功导入 {importResult.imported_count} 个模板 +

+ )} + {importResult.failed_count > 0 && ( +
+ + {importResult.failed_count} 个模板导入失败 (点击查看详情) + +
+ {importResult.failed_templates.map((failed, index) => ( +
+ {failed.name}: {failed.error} +
+ ))} +
+
+ )} +
+
+
+ )} + + {/* Action Buttons */} +
+ {importing ? ( +
+
+ 导入中... +
+ ) : ( + + )} +
+
+
+
+ )} + {/* Template Detail Modal */} {selectedTemplate && (
diff --git a/src/services/tauri.ts b/src/services/tauri.ts index 3e76bab..11fe522 100644 --- a/src/services/tauri.ts +++ b/src/services/tauri.ts @@ -483,6 +483,40 @@ export class TemplateService { } } + /** + * Batch import templates with progress monitoring + */ + static async batchImportTemplatesWithProgress( + sourceFolder: string, + onProgress?: (progress: any) => void + ): Promise { + try { + const request = { source_folder: sourceFolder } + + // Set up progress listener if callback provided + let unlisten: (() => void) | null = null + if (onProgress) { + const { listen } = await import('@tauri-apps/api/event') + unlisten = await listen('template-import-progress', (event) => { + onProgress(event.payload) + }) + } + + try { + const result = await invoke('batch_import_templates_with_progress', { request }) + return JSON.parse(result as string) + } finally { + // Clean up listener + if (unlisten) { + unlisten() + } + } + } catch (error) { + console.error('Failed to batch import templates with progress:', error) + throw error + } + } + /** * Get all templates */