From e6da45ee63e61c5e82ceb4ab8f23df9f6f1b1d6f Mon Sep 17 00:00:00 2001 From: 666ghj <670939375@qq.com> Date: Wed, 31 Dec 2025 17:54:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(history):=20=E6=B7=BB=E5=8A=A0=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E5=8E=86=E5=8F=B2=E9=A1=B9=E7=9B=AE=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 HistoryDatabase.vue 组件,实现扇形堆叠到网格展开的动画效果 - 后端 simulation.py 添加历史模拟数据 API 支持 - 修复 SimulationManager 过滤隐藏文件问题 - 前端 simulation.js 添加获取历史模拟数据的 API 方法 - Home.vue 集成历史项目展示组件 - 实现正方形网格背景装饰效果 --- backend/app/api/simulation.py | 103 +++ backend/app/services/simulation_manager.py | 5 + frontend/src/api/simulation.js | 9 + frontend/src/components/HistoryDatabase.vue | 670 ++++++++++++++++++++ frontend/src/views/Home.vue | 4 + 5 files changed, 791 insertions(+) create mode 100644 frontend/src/components/HistoryDatabase.vue diff --git a/backend/app/api/simulation.py b/backend/app/api/simulation.py index 3e0174b..3a2ff29 100644 --- a/backend/app/api/simulation.py +++ b/backend/app/api/simulation.py @@ -809,6 +809,109 @@ def list_simulations(): }), 500 +@simulation_bp.route('/history', methods=['GET']) +def get_simulation_history(): + """ + 获取历史模拟列表(带项目详情) + + 用于首页历史项目展示,返回包含项目名称、描述等丰富信息的模拟列表 + + Query参数: + limit: 返回数量限制(默认20) + + 返回: + { + "success": true, + "data": [ + { + "simulation_id": "sim_xxxx", + "project_id": "proj_xxxx", + "project_name": "武大舆情分析", + "simulation_requirement": "如果武汉大学发布...", + "status": "completed", + "entities_count": 68, + "profiles_count": 68, + "entity_types": ["Student", "Professor", ...], + "created_at": "2024-12-10", + "updated_at": "2024-12-10", + "total_rounds": 120, + "current_round": 120, + "version": "v1.0.2" + }, + ... + ], + "count": 7 + } + """ + try: + limit = request.args.get('limit', 20, type=int) + + manager = SimulationManager() + simulations = manager.list_simulations()[:limit] + + # 增强模拟数据,添加项目详情 + 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"] = "" + + # 获取模拟配置信息 + config = manager.get_simulation_config(sim.simulation_id) + if config: + time_config = config.get("time_config", {}) + sim_dict["total_simulation_hours"] = time_config.get("total_simulation_hours", 0) + sim_dict["total_rounds"] = int( + time_config.get("total_simulation_hours", 0) * 60 / + max(time_config.get("minutes_per_round", 60), 1) + ) + else: + sim_dict["total_simulation_hours"] = 0 + sim_dict["total_rounds"] = 0 + + # 获取运行状态 + 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 + else: + sim_dict["current_round"] = 0 + sim_dict["runner_status"] = "idle" + + # 添加版本号 + sim_dict["version"] = "v1.0.2" + + # 格式化日期 + try: + created_date = sim_dict.get("created_at", "")[:10] + sim_dict["created_date"] = created_date + except: + sim_dict["created_date"] = "" + + enriched_simulations.append(sim_dict) + + return jsonify({ + "success": True, + "data": enriched_simulations, + "count": len(enriched_simulations) + }) + + except Exception as e: + logger.error(f"获取历史模拟失败: {str(e)}") + return jsonify({ + "success": False, + "error": str(e), + "traceback": traceback.format_exc() + }), 500 + + @simulation_bp.route('//profiles', methods=['GET']) def get_simulation_profiles(simulation_id: str): """ diff --git a/backend/app/services/simulation_manager.py b/backend/app/services/simulation_manager.py index 830762b..96c496f 100644 --- a/backend/app/services/simulation_manager.py +++ b/backend/app/services/simulation_manager.py @@ -465,6 +465,11 @@ class SimulationManager: if os.path.exists(self.SIMULATION_DATA_DIR): for sim_id in os.listdir(self.SIMULATION_DATA_DIR): + # 跳过隐藏文件(如 .DS_Store)和非目录文件 + sim_path = os.path.join(self.SIMULATION_DATA_DIR, sim_id) + if sim_id.startswith('.') or not os.path.isdir(sim_path): + continue + state = self._load_simulation_state(sim_id) if state: if project_id is None or state.project_id == project_id: diff --git a/frontend/src/api/simulation.js b/frontend/src/api/simulation.js index 96404c6..f878586 100644 --- a/frontend/src/api/simulation.js +++ b/frontend/src/api/simulation.js @@ -176,3 +176,12 @@ export const interviewAgents = (data) => { return requestWithRetry(() => service.post('/api/simulation/interview/batch', data), 3, 1000) } +/** + * 获取历史模拟列表(带项目详情) + * 用于首页历史项目展示 + * @param {number} limit - 返回数量限制 + */ +export const getSimulationHistory = (limit = 20) => { + return service.get('/api/simulation/history', { params: { limit } }) +} + diff --git a/frontend/src/components/HistoryDatabase.vue b/frontend/src/components/HistoryDatabase.vue new file mode 100644 index 0000000..d462839 --- /dev/null +++ b/frontend/src/components/HistoryDatabase.vue @@ -0,0 +1,670 @@ + + + + + diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue index 91cb942..1c0dc00 100644 --- a/frontend/src/views/Home.vue +++ b/frontend/src/views/Home.vue @@ -199,6 +199,9 @@ + + + @@ -206,6 +209,7 @@