diff --git a/backend/app/api/simulation.py b/backend/app/api/simulation.py index 3a2ff29..298b8dc 100644 --- a/backend/app/api/simulation.py +++ b/backend/app/api/simulation.py @@ -849,41 +849,48 @@ def get_simulation_history(): manager = SimulationManager() simulations = manager.list_simulations()[:limit] - # 增强模拟数据,添加项目详情 + # 增强模拟数据,只从 Simulation 文件读取 enriched_simulations = [] for sim in simulations: sim_dict = sim.to_dict() - # 获取关联的项目信息 - project = ProjectManager.get_project(sim.project_id) - if project: - sim_dict["project_name"] = project.name - sim_dict["simulation_requirement"] = project.simulation_requirement - else: - sim_dict["project_name"] = "未知项目" - sim_dict["simulation_requirement"] = "" - - # 获取模拟配置信息 + # 获取模拟配置信息(从 simulation_config.json 读取 simulation_requirement) config = manager.get_simulation_config(sim.simulation_id) if config: + sim_dict["simulation_requirement"] = config.get("simulation_requirement", "") time_config = config.get("time_config", {}) sim_dict["total_simulation_hours"] = time_config.get("total_simulation_hours", 0) - sim_dict["total_rounds"] = int( + # 推荐轮数(后备值) + recommended_rounds = int( time_config.get("total_simulation_hours", 0) * 60 / max(time_config.get("minutes_per_round", 60), 1) ) else: + sim_dict["simulation_requirement"] = "" sim_dict["total_simulation_hours"] = 0 - sim_dict["total_rounds"] = 0 + recommended_rounds = 0 - # 获取运行状态 + # 获取运行状态(从 run_state.json 读取用户设置的实际轮数) run_state = SimulationRunner.get_run_state(sim.simulation_id) if run_state: sim_dict["current_round"] = run_state.current_round sim_dict["runner_status"] = run_state.runner_status.value + # 使用用户设置的 total_rounds,若无则使用推荐轮数 + sim_dict["total_rounds"] = run_state.total_rounds if run_state.total_rounds > 0 else recommended_rounds else: sim_dict["current_round"] = 0 sim_dict["runner_status"] = "idle" + sim_dict["total_rounds"] = recommended_rounds + + # 获取关联项目的文件列表(最多3个) + project = ProjectManager.get_project(sim.project_id) + if project and hasattr(project, 'files') and project.files: + sim_dict["files"] = [ + {"filename": f.get("filename", "未知文件")} + for f in project.files[:3] + ] + else: + sim_dict["files"] = [] # 添加版本号 sim_dict["version"] = "v1.0.2" diff --git a/frontend/src/components/HistoryDatabase.vue b/frontend/src/components/HistoryDatabase.vue index e01ed89..155643e 100644 --- a/frontend/src/components/HistoryDatabase.vue +++ b/frontend/src/components/HistoryDatabase.vue @@ -1,8 +1,7 @@ @@ -333,7 +351,6 @@ onMounted(() => { left: 0; right: 0; bottom: 0; - /* 40px x 40px 的正方形网格 */ background-image: linear-gradient(to right, rgba(0, 0, 0, 0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 1px, transparent 1px); @@ -347,59 +364,38 @@ onMounted(() => { left: 0; right: 0; bottom: 0; - /* 四边渐变遮罩,让网格在边缘淡出 */ background: linear-gradient(to right, rgba(255, 255, 255, 0.9) 0%, transparent 15%, transparent 85%, rgba(255, 255, 255, 0.9) 100%), linear-gradient(to bottom, rgba(255, 255, 255, 0.8) 0%, transparent 20%, transparent 80%, rgba(255, 255, 255, 0.8) 100%); pointer-events: none; } -/* CTA 按钮 - 位置固定不变 */ -.cta-button { +/* 标题区域 */ +.section-header { position: relative; z-index: 100; - display: flex; - justify-content: center; - margin-bottom: 48px; - cursor: pointer; -} - -.cta-inner { display: flex; align-items: center; - gap: 12px; - padding: 14px 32px; - background: #FFFFFF; - border: 1px solid #E0E0E0; - border-radius: 30px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); /* 加深阴影 */ + justify-content: center; + gap: 24px; + margin-bottom: 24px; font-family: 'JetBrains Mono', 'SF Mono', monospace; - font-size: 0.78rem; - font-weight: 600; /* 加粗 */ - color: #1a1a1a; - letter-spacing: 1.2px; - transition: all 0.3s ease; + padding: 0 40px; } -.cta-inner:hover { - background: #FAFAFA; - border-color: #CCCCCC; - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12); - transform: translateY(-2px); +.section-line { + flex: 1; + height: 1px; + background: linear-gradient(90deg, transparent, #E5E7EB, transparent); + max-width: 200px; } -.cta-icon { - color: #666; /* 加深颜色 */ - font-size: 1rem; -} - -.cta-arrow { - color: #666; /* 加深颜色 */ - transition: transform 0.3s ease; -} - -.cta-arrow.expanded { - transform: rotate(90deg); +.section-title { + font-size: 0.8rem; + font-weight: 500; + color: #9CA3AF; + letter-spacing: 3px; + text-transform: uppercase; } /* 卡片容器 */ @@ -407,37 +403,32 @@ onMounted(() => { position: relative; display: flex; justify-content: center; - align-items: flex-start; /* 从顶部开始排列 */ - min-height: 420px; /* 折叠时的最小高度 */ + align-items: flex-start; + min-height: 420px; padding: 0 40px; - transition: min-height 700ms cubic-bezier(0.23, 1, 0.32, 1); /* Match card duration */ + transition: min-height 700ms cubic-bezier(0.23, 1, 0.32, 1); } .cards-container.expanded { - min-height: 620px; /* 展开时增加高度,页面自动向下延长 */ + min-height: 620px; } -/* 项目卡片 - 完全参照参考图 */ +/* 项目卡片 */ .project-card { position: absolute; - width: 280px; /* 调整宽度 */ + width: 280px; background: #FFFFFF; - border: 1px solid #E5E7EB; /* border-gray-200 */ - border-radius: 0; /* 直角或极小圆角 */ - padding: 14px; /* 稍微减小内边距,让内容更紧凑 */ + border: 1px solid #E5E7EB; + border-radius: 0; + padding: 14px; cursor: pointer; - /* Transitions are handled inline for transform/opacity, CSS for others */ - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); /* shadow-sm */ - /* Remove transition property from here as it's overridden by inline styles for transform/opacity */ - /* Add specific transitions for border and shadow */ + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); transition: box-shadow 0.3s ease, border-color 0.3s ease, transform 700ms cubic-bezier(0.23, 1, 0.32, 1), opacity 700ms cubic-bezier(0.23, 1, 0.32, 1); } -/* 悬停效果 - 黑色粗边框,阴影加深 */ -/* Micro-interaction: Hover: border-black/40 shadow-lg */ .project-card:hover { - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); /* shadow-lg */ - border-color: rgba(0, 0, 0, 0.4); /* border-black/40 */ + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + border-color: rgba(0, 0, 0, 0.4); z-index: 1000 !important; } @@ -452,13 +443,13 @@ onMounted(() => { align-items: center; margin-bottom: 12px; padding-bottom: 12px; - border-bottom: 1px solid #F3F4F6; /* 增加分割线 */ + border-bottom: 1px solid #F3F4F6; font-family: 'JetBrains Mono', 'SF Mono', monospace; font-size: 0.7rem; } .card-id { - color: #6B7280; /* 加深灰色 */ + color: #6B7280; letter-spacing: 0.5px; font-weight: 500; } @@ -477,61 +468,120 @@ onMounted(() => { font-size: 0.5rem; } -.card-status.completed { - color: #10B981; /* 更鲜艳的绿 */ +.card-status.completed { color: #10B981; } +.card-status.processing { color: #F59E0B; } +.card-status.ready { color: #3B82F6; } +.card-status.failed { color: #EF4444; } +.card-status.pending { color: #9CA3AF; } + +/* 文件列表区域 */ +.card-files-wrapper { + position: relative; + width: 100%; + min-height: 64px; + margin-bottom: 12px; + padding: 8px 10px; + background: linear-gradient(135deg, #f8f9fa 0%, #f1f3f4 100%); + border-radius: 4px; + border: 1px solid #e8eaed; } -.card-status.processing { - color: #F59E0B; +.files-list { + display: flex; + flex-direction: column; + gap: 6px; } -.card-status.ready { - color: #3B82F6; +.file-item { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 6px; + background: rgba(255, 255, 255, 0.7); + border-radius: 3px; + transition: all 0.2s ease; } -.card-status.failed { - color: #EF4444; +.file-item:hover { + background: rgba(255, 255, 255, 1); + transform: translateX(2px); + border-color: #e5e7eb; } -.card-status.pending { +/* 简约文件标签样式 */ +.file-tag { + display: inline-flex; + align-items: center; + justify-content: center; + height: 16px; + padding: 0 4px; + border-radius: 2px; + font-family: 'JetBrains Mono', monospace; + font-size: 0.55rem; + font-weight: 600; + line-height: 1; + text-transform: uppercase; + letter-spacing: 0.2px; + flex-shrink: 0; + min-width: 28px; +} + +/* 低饱和度配色方案 - Morandi色系 */ +.file-tag.pdf { background: #f2e6e6; color: #a65a5a; } +.file-tag.doc { background: #e6eff5; color: #5a7ea6; } +.file-tag.xls { background: #e6f2e8; color: #5aa668; } +.file-tag.ppt { background: #f5efe6; color: #a6815a; } +.file-tag.txt { background: #f0f0f0; color: #757575; } +.file-tag.code { background: #eae6f2; color: #815aa6; } +.file-tag.img { background: #e6f2f2; color: #5aa6a6; } +.file-tag.zip { background: #f2f0e6; color: #a69b5a; } +.file-tag.other { background: #f3f4f6; color: #6b7280; } + +.file-name { + font-family: 'Inter', sans-serif; + font-size: 0.7rem; + color: #4b5563; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + letter-spacing: 0.1px; +} + +/* 无文件时的占位 */ +.files-empty { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + height: 48px; color: #9CA3AF; } -/* 卡片图片区域 */ -.card-image-wrapper { - position: relative; - width: 100%; - height: 64px; /* 极度压扁,复刻参考图的宽银幕感 */ - margin-bottom: 12px; - overflow: hidden; - background: #f0f0f0; +.empty-file-icon { + font-size: 1rem; + opacity: 0.5; } -.card-image { - width: 100%; - height: 100%; - object-fit: cover; - /* Micro-interaction: Default: opacity-80 grayscale */ - filter: grayscale(100%); - opacity: 0.8; - transition: all 500ms ease; /* Duration 500ms */ +.empty-file-text { + font-family: 'JetBrains Mono', monospace; + font-size: 0.7rem; + letter-spacing: 0.5px; } -/* 悬停时图片变彩色 */ -/* Micro-interaction: Hover: opacity-100 grayscale-0 */ -.project-card:hover .card-image { - filter: grayscale(0%); - opacity: 1; +/* 悬停时文件区域效果 */ +.project-card:hover .card-files-wrapper { + border-color: #d1d5db; + background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); } -/* 角落装饰 - 只保留左上角,颜色加深 */ +/* 角落装饰 */ .corner-mark.top-left-only { position: absolute; top: 6px; left: 6px; width: 8px; height: 8px; - border-top: 1.5px solid rgba(0, 0, 0, 0.4); /* 加粗一点,颜色更深 */ + border-top: 1.5px solid rgba(0, 0, 0, 0.4); border-left: 1.5px solid rgba(0, 0, 0, 0.4); pointer-events: none; z-index: 10; @@ -540,10 +590,10 @@ onMounted(() => { /* 卡片标题 */ .card-title { font-family: 'Inter', -apple-system, sans-serif; - font-size: 0.9rem; /* 稍微调小一点点 */ + font-size: 0.9rem; font-weight: 700; color: #111827; - margin: 0 0 6px 0; /* 减小间距 */ + margin: 0 0 6px 0; line-height: 1.4; white-space: nowrap; overflow: hidden; @@ -551,19 +601,18 @@ onMounted(() => { transition: color 0.3s ease; } -/* 悬停时标题变蓝 - 参考图细节 */ .project-card:hover .card-title { - color: #2563EB; /* 蓝色 */ + color: #2563EB; } /* 卡片描述 */ .card-desc { font-family: 'Inter', sans-serif; font-size: 0.75rem; - color: #6B7280; /* 灰色 */ + color: #6B7280; margin: 0 0 16px 0; line-height: 1.5; - height: 34px; /* 两行高度 */ + height: 34px; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; @@ -572,12 +621,12 @@ onMounted(() => { /* 卡片底部 */ .card-footer { - position: relative; /* For absolute positioning of the line */ + position: relative; display: flex; justify-content: space-between; align-items: center; padding-top: 12px; - border-top: 1px solid #F3F4F6; /* 增加分割线 */ + border-top: 1px solid #F3F4F6; font-family: 'JetBrains Mono', monospace; font-size: 0.65rem; color: #9CA3AF; @@ -585,7 +634,6 @@ onMounted(() => { } /* 底部装饰线 */ -/* Micro-interaction: Height 2px, bg-black, Default w-0, Hover w-full */ .card-bottom-line { position: absolute; bottom: 0; @@ -594,7 +642,7 @@ onMounted(() => { width: 0; background-color: #000; transition: width 0.5s cubic-bezier(0.23, 1, 0.32, 1); - z-index: 20; /* 确保在内容之上 */ + z-index: 20; } .project-card:hover .card-bottom-line {