fix: 统一按钮样式
This commit is contained in:
@@ -2,7 +2,6 @@ import React, { useState } from 'react';
|
||||
import { X, FolderOpen, AlertCircle, CheckCircle, Settings } from 'lucide-react';
|
||||
import { BatchImportRequest } from '../../types/template';
|
||||
import { CustomSelect } from '../CustomSelect';
|
||||
import { useProjectStore } from '../../store/projectStore';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
interface BatchImportModalProps {
|
||||
@@ -26,8 +25,6 @@ export const BatchImportModal: React.FC<BatchImportModalProps> = ({
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||
|
||||
const { projects } = useProjectStore();
|
||||
|
||||
// 处理文件夹选择
|
||||
const handleFolderSelect = async () => {
|
||||
try {
|
||||
@@ -77,13 +74,6 @@ export const BatchImportModal: React.FC<BatchImportModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const projectOptions = [
|
||||
{ value: '', label: '不关联项目' },
|
||||
...projects.map(project => ({
|
||||
value: project.id,
|
||||
label: project.name,
|
||||
})),
|
||||
];
|
||||
|
||||
const concurrentOptions = [
|
||||
{ value: `1`, label: '1 个(慢速)' },
|
||||
@@ -164,20 +154,6 @@ export const BatchImportModal: React.FC<BatchImportModalProps> = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 关联项目 */}
|
||||
<div className="mb-6">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
关联项目
|
||||
</label>
|
||||
<CustomSelect
|
||||
value={formData.project_id || ''}
|
||||
onChange={(value) => setFormData(prev => ({ ...prev, project_id: value }))}
|
||||
options={projectOptions}
|
||||
placeholder="选择项目(可选)"
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 自动上传选项 */}
|
||||
<div className="mb-6">
|
||||
<label className="flex items-center">
|
||||
|
||||
@@ -16,6 +16,7 @@ export const ImportProgressModal: React.FC<ImportProgressModalProps> = ({
|
||||
}) => {
|
||||
const [progress, setProgress] = useState<ImportProgress | null>(null);
|
||||
const [lastValidProgress, setLastValidProgress] = useState<ImportProgress | null>(null);
|
||||
const [hasCompleted, setHasCompleted] = useState(false);
|
||||
const { getImportProgress } = useTemplateStore();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -35,10 +36,17 @@ export const ImportProgressModal: React.FC<ImportProgressModalProps> = ({
|
||||
setLastValidProgress(progressData);
|
||||
}
|
||||
|
||||
// 如果进度数据为空(已被清除),说明导入已完成,停止轮询
|
||||
if (!progressData) {
|
||||
// 使用最后一次有效的进度数据,但更新状态为完成
|
||||
if (lastValidProgress) {
|
||||
// 检查是否导入完成
|
||||
const isCompleted = !progressData ||
|
||||
progressData.status === ImportStatus.Completed ||
|
||||
progressData.status === ImportStatus.Failed;
|
||||
|
||||
if (isCompleted && !hasCompleted) {
|
||||
// 标记为已完成,避免重复处理
|
||||
setHasCompleted(true);
|
||||
|
||||
// 如果进度数据为空但有最后有效进度,使用它
|
||||
if (!progressData && lastValidProgress) {
|
||||
const completedProgress: ImportProgress = {
|
||||
...lastValidProgress,
|
||||
status: ImportStatus.Completed,
|
||||
@@ -54,36 +62,20 @@ export const ImportProgressModal: React.FC<ImportProgressModalProps> = ({
|
||||
interval = null;
|
||||
}
|
||||
|
||||
// 触发完成回调
|
||||
if (onComplete) {
|
||||
// 立即触发完成回调,然后延迟关闭弹窗
|
||||
if (onComplete && (progressData?.status === ImportStatus.Completed || !progressData)) {
|
||||
// 立即刷新列表
|
||||
onComplete();
|
||||
|
||||
// 延迟关闭弹窗,让用户看到完成状态
|
||||
setTimeout(() => {
|
||||
if (isMounted) {
|
||||
onComplete();
|
||||
onClose();
|
||||
}
|
||||
}, 2000); // 2秒后自动关闭
|
||||
}, 2000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果进度状态为完成或失败,也停止轮询
|
||||
if (progressData.status === ImportStatus.Completed ||
|
||||
progressData.status === ImportStatus.Failed) {
|
||||
|
||||
// 清除轮询
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
|
||||
if (progressData.status === ImportStatus.Completed && onComplete) {
|
||||
setTimeout(() => {
|
||||
if (isMounted) {
|
||||
onComplete();
|
||||
}
|
||||
}, 2000); // 2秒后自动关闭
|
||||
}
|
||||
return; // 重要:完成后直接返回,不再继续轮询
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取导入进度失败:', error);
|
||||
// 如果出错,也停止轮询
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { X, Upload, File, AlertCircle, CheckCircle } from 'lucide-react';
|
||||
import { X, Upload, AlertCircle, CheckCircle } from 'lucide-react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { ImportTemplateRequest } from '../../types/template';
|
||||
import { CustomSelect } from '../CustomSelect';
|
||||
import { useProjectStore } from '../../store/projectStore';
|
||||
|
||||
interface ImportTemplateModalProps {
|
||||
onClose: () => void;
|
||||
@@ -26,7 +24,6 @@ export const ImportTemplateModal: React.FC<ImportTemplateModalProps> = ({
|
||||
const [selectedFile, setSelectedFile] = useState<string>('');
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
|
||||
const { projects } = useProjectStore();
|
||||
|
||||
// 处理文件选择
|
||||
const handleFileSelect = async () => {
|
||||
@@ -114,14 +111,6 @@ export const ImportTemplateModal: React.FC<ImportTemplateModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const projectOptions = [
|
||||
{ value: '', label: '不关联项目' },
|
||||
...projects.map(project => ({
|
||||
value: project.id,
|
||||
label: project.name,
|
||||
})),
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg shadow-xl w-full max-w-md mx-4">
|
||||
@@ -155,6 +144,7 @@ export const ImportTemplateModal: React.FC<ImportTemplateModalProps> = ({
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
onClick={handleFileSelect}
|
||||
>
|
||||
{selectedFile ? (
|
||||
<div className="flex items-center justify-center">
|
||||
@@ -179,15 +169,6 @@ export const ImportTemplateModal: React.FC<ImportTemplateModalProps> = ({
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleFileSelect}
|
||||
className="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<File className="w-4 h-4 mr-2" />
|
||||
选择文件
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{errors.file_path && (
|
||||
@@ -220,20 +201,6 @@ export const ImportTemplateModal: React.FC<ImportTemplateModalProps> = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 关联项目 */}
|
||||
<div className="mb-6">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
关联项目
|
||||
</label>
|
||||
<CustomSelect
|
||||
value={formData.project_id || ''}
|
||||
onChange={(value) => setFormData(prev => ({ ...prev, project_id: value }))}
|
||||
options={projectOptions}
|
||||
placeholder="选择项目(可选)"
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 自动上传选项 */}
|
||||
<div className="mb-6">
|
||||
<label className="flex items-center">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Activity, Database, Clock, TrendingUp, RefreshCw, Trash2 } from 'lucide-react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { DeleteConfirmDialog } from '../DeleteConfirmDialog';
|
||||
|
||||
interface PerformanceStats {
|
||||
template_import?: {
|
||||
@@ -42,6 +43,8 @@ export const PerformanceMonitor: React.FC<PerformanceMonitorProps> = ({ onClose
|
||||
const [performanceStats, setPerformanceStats] = useState<PerformanceStats>({});
|
||||
const [cacheStats, setCacheStats] = useState<CacheStats | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
// 加载性能数据
|
||||
@@ -66,17 +69,29 @@ export const PerformanceMonitor: React.FC<PerformanceMonitorProps> = ({ onClose
|
||||
};
|
||||
|
||||
// 清理性能数据
|
||||
const handleCleanupData = async () => {
|
||||
if (window.confirm('确定要清理7天前的性能数据吗?')) {
|
||||
try {
|
||||
await invoke('cleanup_template_performance_data', { olderThanHours: 24 * 7 });
|
||||
await loadPerformanceData();
|
||||
} catch (error) {
|
||||
console.error('清理性能数据失败:', error);
|
||||
}
|
||||
const handleCleanupData = () => {
|
||||
setShowDeleteConfirm(true);
|
||||
};
|
||||
|
||||
// 确认清理性能数据
|
||||
const confirmCleanupData = async () => {
|
||||
try {
|
||||
setDeleting(true);
|
||||
await invoke('cleanup_template_performance_data', { olderThanHours: 24 * 7 });
|
||||
await loadPerformanceData();
|
||||
setShowDeleteConfirm(false);
|
||||
} catch (error) {
|
||||
console.error('清理性能数据失败:', error);
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 取消清理
|
||||
const cancelCleanupData = () => {
|
||||
setShowDeleteConfirm(false);
|
||||
};
|
||||
|
||||
// 预热缓存
|
||||
const handleWarmCache = async () => {
|
||||
try {
|
||||
@@ -346,6 +361,15 @@ export const PerformanceMonitor: React.FC<PerformanceMonitorProps> = ({ onClose
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DeleteConfirmDialog
|
||||
isOpen={showDeleteConfirm}
|
||||
title="清理性能数据"
|
||||
message="确定要清理7天前的性能数据吗?此操作不可撤销。"
|
||||
deleting={deleting}
|
||||
onConfirm={confirmCleanupData}
|
||||
onCancel={cancelCleanupData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user