# handlers/module_handler.py - 模块级变更处理 # B1 重命名 / B2 重新描述 / B3 逐条修改 / B4 批量重新生成 from rich.console import Console from rich.panel import Panel from rich.prompt import Confirm, Prompt from rich.rule import Rule from rich.table import Table import config from constants import CHG_EDIT, CHG_REGEN, CHG_RENAME, CHG_REDESCRIBE from core_utils import ( active_reqs, generate_code, generate_signatures, log_change, merge_signatures_to_main, patch_and_save_signatures, write_readme, ) from core.code_generator import CodeGenerator from core.llm_client import LLMClient from core.requirement_analyzer import RequirementAnalyzer from database.db_manager import DBManager from database.models import FunctionalRequirement, Project from ui.display import ( print_functional_requirements, print_module_list, print_req_diff, print_signatures_preview, ) from utils.output_writer import write_function_signatures_json console = Console() db = DBManager() # ══════════════════════════════════════════════════════ # 模块变更入口(子菜单) # ══════════════════════════════════════════════════════ def change_module_requirements( project: Project, func_reqs: list, output_dir: str, knowledge_text: str = "", ) -> None: """ 选择目标模块,进入模块级变更子菜单: B1 · 重命名模块 B2 · 重新描述模块需求 B3 · 逐条修改模块内需求 B4 · 批量重新生成模块代码 """ console.print(Rule("[bold magenta]变更指定模块需求[/bold magenta]")) modules = print_module_list(func_reqs) if not modules: console.print("[yellow]当前项目暂无模块信息。[/yellow]") return mod_idx_str = Prompt.ask("请输入模块序号(输入 0 返回)", default="0") if mod_idx_str == "0": return try: mod_idx = int(mod_idx_str) - 1 if mod_idx < 0 or mod_idx >= len(modules): raise ValueError target_module = modules[mod_idx] except ValueError: console.print("[red]序号无效[/red]") return module_reqs = [ r for r in func_reqs if (r.module or config.DEFAULT_MODULE) == target_module and r.status != "deleted" ] console.print( f"\n[bold magenta]模块:{target_module}[/bold magenta]" f" 共 {len(module_reqs)} 条需求" ) print_functional_requirements(module_reqs) sub_menu = [ ("B1", "✏️ 重命名模块", "修改模块名,批量更新该模块所有需求"), ("B2", "📝 重新描述模块需求", "重新输入模块需求描述,LLM 重新分解并生成代码"), ("B3", "🔧 逐条修改模块内需求", "对模块内每条需求单独修改并重新生成"), ("B4", "⚡ 批量重新生成模块代码", "保持需求内容不变,整体重新生成签名+代码"), ] while True: console.print(Rule()) table = Table(show_header=False, box=None, padding=(0, 2)) table.add_column("选项", style="bold yellow", width=5) table.add_column("功能", style="bold", width=26) table.add_column("说明", style="dim", width=42) for key, name, desc in sub_menu: table.add_row(f"[{key}]", name, desc) table.add_row("[back]", "↩ 返回", "") console.print(table) sub_action = Prompt.ask( "请选择操作", choices=["B1", "B2", "B3", "B4", "back"], default="back", ) if sub_action == "B1": module_rename( project=project, module_reqs=module_reqs, old_module=target_module, ) break elif sub_action == "B2": module_redescribe( project=project, module_reqs=module_reqs, target_module=target_module, output_dir=output_dir, knowledge_text=knowledge_text, ) break elif sub_action == "B3": module_edit_each( project=project, module_reqs=module_reqs, output_dir=output_dir, knowledge_text=knowledge_text, ) module_reqs = [ db.get_functional_requirement(r.id) for r in module_reqs if db.get_functional_requirement(r.id) ] elif sub_action == "B4": module_regen_code( project=project, module_reqs=module_reqs, output_dir=output_dir, knowledge_text=knowledge_text, ) else: break # ══════════════════════════════════════════════════════ # B1:重命名模块 # ══════════════════════════════════════════════════════ def module_rename( project: Project, module_reqs: list, old_module: str, ) -> None: """将指定模块重命名,批量更新该模块下所有需求的 module 字段,记录变更历史。""" new_module = Prompt.ask(f"请输入新模块名(当前:{old_module})") if not new_module.strip(): console.print("[red]模块名不能为空[/red]") return if new_module == old_module: console.print("[dim]模块名未变更,跳过。[/dim]") return change_summary = ( f"模块重命名:'{old_module}' → '{new_module}'\n" f" 影响需求数:{len(module_reqs)} 条\n" + "\n".join(f" · [{r.id}] {r.title}" for r in module_reqs) ) console.print(Panel(change_summary, title="📝 模块重命名预览", border_style="yellow")) if not Confirm.ask("确认执行模块重命名?", default=True): console.print("[yellow]已取消。[/yellow]") return for req in module_reqs: req.module = new_module db.update_functional_requirement(req) log_change( project_id = project.id, change_type = CHG_RENAME, summary = change_summary, module = old_module, ) console.print( f"[green]✓ 模块已重命名:'{old_module}' → '{new_module}'," f"共更新 {len(module_reqs)} 条需求[/green]" ) # ══════════════════════════════════════════════════════ # B2:重新描述模块需求 # ══════════════════════════════════════════════════════ def module_redescribe( project: Project, module_reqs: list, target_module: str, output_dir: str, knowledge_text: str = "", ) -> None: """ 用户重新输入该模块的需求描述文本, LLM 重新分解为功能需求,展示新旧对比后确认, 软删除旧需求,持久化新需求,重新生成签名+代码,记录变更历史。 """ console.print(Rule( f"[bold magenta]重新描述模块 '{target_module}' 需求[/bold magenta]" )) console.print("[bold]当前模块需求:[/bold]") print_functional_requirements(module_reqs) console.print( f"\n[bold]请重新输入模块 '[magenta]{target_module}[/magenta]'" " 的需求描述[/bold](输入空行结束):" ) lines = [] while True: line = input() if line == "": break lines.append(line) new_desc_text = "\n".join(lines).strip() if not new_desc_text: console.print("[yellow]输入为空,已取消。[/yellow]") return llm = LLMClient() analyzer = RequirementAnalyzer(llm) raw_req_id = module_reqs[0].raw_req_id if module_reqs else None with console.status( f"[cyan]LLM 正在重新分解模块 '{target_module}' 需求...[/cyan]" ): # ✅ 修复:移除不存在的 module_hint 参数 # 分解后统一通过 req.module = target_module 强制设置模块归属 new_reqs = analyzer.decompose( raw_requirement = new_desc_text, project_id = project.id, raw_req_id = raw_req_id, knowledge = knowledge_text, ) # 强制将所有新需求归属到当前模块 for req in new_reqs: req.module = target_module console.print(f"[green]✓ 重新分解完成,共 {len(new_reqs)} 条新功能需求[/green]") print_req_diff(old_reqs=module_reqs, new_reqs=new_reqs) if not Confirm.ask( f"确认用以上 {len(new_reqs)} 条新需求替换模块 '{target_module}' 的旧需求?", default=True, ): console.print("[yellow]已取消重新描述。[/yellow]") return # ── 软删除旧需求 ────────────────────────────────── deleted_ids = [] for req in module_reqs: req.status = "deleted" db.update_functional_requirement(req) deleted_ids.append(req.id) console.print( f"[dim]✓ 已软删除旧需求 {len(deleted_ids)} 条(ID: {deleted_ids})[/dim]" ) # ── 持久化新需求 ────────────────────────────────── all_reqs = db.list_functional_requirements(project.id) max_idx = max((r.index_no for r in all_reqs), default=0) for i, req in enumerate(new_reqs): req.index_no = max_idx + i + 1 req.id = db.create_functional_requirement(req) console.print(f"[green]✓ 新功能需求已持久化,共 {len(new_reqs)} 条[/green]") # ── 记录变更历史 ────────────────────────────────── change_summary = ( f"模块 '{target_module}' 需求重新描述:\n" f" 旧需求 {len(module_reqs)} 条(已软删除):\n" + "\n".join(f" - [{r.id}] {r.title}" for r in module_reqs) + f"\n 新需求 {len(new_reqs)} 条:\n" + "\n".join(f" + [{r.id}] {r.title}" for r in new_reqs) ) log_change( project_id = project.id, change_type = CHG_REDESCRIBE, summary = change_summary, module = target_module, ) # ── 重新生成签名与代码 ──────────────────────────── console.print( f"\n[cyan]正在为模块 '{target_module}' 重新生成签名与代码...[/cyan]" ) generator = CodeGenerator(llm) signatures = generate_signatures(analyzer, new_reqs, knowledge_text) mod_sig_file = f"module_{target_module}_redescribe_signatures.json" write_function_signatures_json( output_dir=output_dir, signatures=signatures, project_name=project.name, project_description=project.description or "", file_name=mod_sig_file, ) print_signatures_preview(signatures) code_files = generate_code( generator=generator, project=project, func_reqs=new_reqs, output_dir=output_dir, knowledge_text=knowledge_text, signatures=signatures, ) for cf in code_files: db.upsert_code_file(cf) for req in new_reqs: req.status = "generated" db.update_functional_requirement(req) patch_and_save_signatures( project=project, signatures=signatures, code_files=code_files, output_dir=output_dir, file_name=mod_sig_file, ) merge_signatures_to_main(project, signatures, output_dir) all_active = active_reqs(db.list_functional_requirements(project.id)) write_readme(project, all_active, output_dir) console.print(Panel.fit( f"[bold green]✅ 模块 '{target_module}' 需求重新描述完成![/bold green]\n" f"新需求 {len(new_reqs)} 条,生成代码 {len(code_files)} 个文件", border_style="green", )) # ══════════════════════════════════════════════════════ # B3:逐条修改模块内需求 # ══════════════════════════════════════════════════════ def module_edit_each( project: Project, module_reqs: list, output_dir: str, knowledge_text: str = "", ) -> None: """对模块内需求逐条展示并允许修改,每条确认后立即重新生成签名与代码,记录变更历史。""" llm = LLMClient() analyzer = RequirementAnalyzer(llm) generator = CodeGenerator(llm) for req in module_reqs: console.print(Rule(f"[cyan]需求 ID={req.id} · {req.title}[/cyan]")) console.print( f" 描述: {req.description}\n" f" 优先级: {req.priority}\n" f" 模块: {req.module}" ) if not Confirm.ask("是否修改此需求?", default=False): continue new_description = Prompt.ask(" 新描述", default=req.description) new_priority = Prompt.ask( " 新优先级", default=req.priority, choices=["high", "medium", "low"], ) new_module = Prompt.ask(" 新模块名", default=req.module) changed = ( new_description != req.description or new_priority != req.priority or new_module != req.module ) if not changed: console.print("[dim] 未检测到变更,跳过。[/dim]") continue change_summary = ( f"需求 '{req.title}'(ID={req.id})变更:\n" f" 描述: '{req.description}' → '{new_description}'\n" f" 优先级: '{req.priority}' → '{new_priority}'\n" f" 模块: '{req.module}' → '{new_module}'" ) console.print(Panel(change_summary, title="📝 变更预览", border_style="yellow")) if not Confirm.ask("确认此条变更?", default=True): console.print("[yellow] 已跳过。[/yellow]") continue req.description = new_description req.priority = new_priority req.module = new_module req.status = "pending" db.update_functional_requirement(req) log_change( project_id = project.id, change_type = CHG_EDIT, summary = change_summary, module = new_module, req_id = req.id, ) console.print(f" [cyan]正在重新生成 {req.function_name} 的签名与代码...[/cyan]") change_sig_file = f"change_{req.id}_signatures.json" signatures = generate_signatures(analyzer, [req], knowledge_text) write_function_signatures_json( output_dir=output_dir, signatures=signatures, project_name=project.name, project_description=project.description or "", file_name=change_sig_file, ) code_files = generate_code( generator=generator, project=project, func_reqs=[req], output_dir=output_dir, knowledge_text=knowledge_text, signatures=signatures, ) for cf in code_files: db.upsert_code_file(cf) req.status = "generated" db.update_functional_requirement(req) patch_and_save_signatures( project=project, signatures=signatures, code_files=code_files, output_dir=output_dir, file_name=change_sig_file, ) merge_signatures_to_main(project, signatures, output_dir) console.print(f" [green]✓ 需求 ID={req.id} 变更完成[/green]") console.print("[green]✓ 模块内需求逐条修改完成[/green]") # ══════════════════════════════════════════════════════ # B4:批量重新生成模块代码 # ══════════════════════════════════════════════════════ def module_regen_code( project: Project, module_reqs: list, output_dir: str, knowledge_text: str = "", ) -> None: """保持需求内容不变,对整个模块批量重新生成签名与代码,记录变更历史。""" module_name = module_reqs[0].module if module_reqs else "未知模块" console.print(Panel( f"模块:[bold magenta]{module_name}[/bold magenta]\n" f"需求数量:{len(module_reqs)} 条\n" + "\n".join( f" · [{r.id}] {r.title} ({r.function_name})" for r in module_reqs ), title="⚡ 批量重新生成预览", border_style="cyan", )) if not Confirm.ask( f"确认对模块 '{module_name}' 的 {len(module_reqs)} 条需求批量重新生成代码?", default=True, ): console.print("[yellow]已取消。[/yellow]") return llm = LLMClient() analyzer = RequirementAnalyzer(llm) generator = CodeGenerator(llm) for req in module_reqs: req.status = "pending" db.update_functional_requirement(req) console.print(f"\n[cyan]正在为模块 '{module_name}' 生成函数签名...[/cyan]") signatures = generate_signatures(analyzer, module_reqs, knowledge_text) mod_sig_file = f"module_{module_name}_signatures.json" write_function_signatures_json( output_dir=output_dir, signatures=signatures, project_name=project.name, project_description=project.description or "", file_name=mod_sig_file, ) print_signatures_preview(signatures) console.print(f"\n[cyan]正在为模块 '{module_name}' 生成代码文件...[/cyan]") code_files = generate_code( generator=generator, project=project, func_reqs=module_reqs, output_dir=output_dir, knowledge_text=knowledge_text, signatures=signatures, ) for cf in code_files: db.upsert_code_file(cf) for req in module_reqs: req.status = "generated" db.update_functional_requirement(req) patch_and_save_signatures( project=project, signatures=signatures, code_files=code_files, output_dir=output_dir, file_name=mod_sig_file, ) merge_signatures_to_main(project, signatures, output_dir) change_summary = ( f"模块 '{module_name}' 批量重新生成代码,共 {len(module_reqs)} 条需求:\n" + "\n".join(f" · [{r.id}] {r.title}" for r in module_reqs) ) log_change( project_id = project.id, change_type = CHG_REGEN, summary = change_summary, module = module_name, ) console.print( f"[bold green]✅ 模块 '{module_name}' 批量重新生成完成!" f"共 {len(code_files)} 个文件[/bold green]" )# handlers/module_handler.py - 模块级变更处理 # B1 重命名 / B2 重新描述 / B3 逐条修改 / B4 批量重新生成 from rich.console import Console from rich.panel import Panel from rich.prompt import Confirm, Prompt from rich.rule import Rule from rich.table import Table import config from constants import CHG_EDIT, CHG_REGEN, CHG_RENAME, CHG_REDESCRIBE from core_utils import ( active_reqs, generate_code, generate_signatures, log_change, merge_signatures_to_main, patch_and_save_signatures, write_readme, ) from core.code_generator import CodeGenerator from core.llm_client import LLMClient from core.requirement_analyzer import RequirementAnalyzer from database.db_manager import DBManager from database.models import FunctionalRequirement, Project from ui.display import ( print_functional_requirements, print_module_list, print_req_diff, print_signatures_preview, ) from utils.output_writer import write_function_signatures_json console = Console() db = DBManager() # ══════════════════════════════════════════════════════ # 模块变更入口(子菜单) # ══════════════════════════════════════════════════════ def change_module_requirements( project: Project, func_reqs: list, output_dir: str, knowledge_text: str = "", ) -> None: """ 选择目标模块,进入模块级变更子菜单: B1 · 重命名模块 B2 · 重新描述模块需求 B3 · 逐条修改模块内需求 B4 · 批量重新生成模块代码 """ console.print(Rule("[bold magenta]变更指定模块需求[/bold magenta]")) modules = print_module_list(func_reqs) if not modules: console.print("[yellow]当前项目暂无模块信息。[/yellow]") return mod_idx_str = Prompt.ask("请输入模块序号(输入 0 返回)", default="0") if mod_idx_str == "0": return try: mod_idx = int(mod_idx_str) - 1 if mod_idx < 0 or mod_idx >= len(modules): raise ValueError target_module = modules[mod_idx] except ValueError: console.print("[red]序号无效[/red]") return module_reqs = [ r for r in func_reqs if (r.module or config.DEFAULT_MODULE) == target_module and r.status != "deleted" ] console.print( f"\n[bold magenta]模块:{target_module}[/bold magenta]" f" 共 {len(module_reqs)} 条需求" ) print_functional_requirements(module_reqs) sub_menu = [ ("B1", "✏️ 重命名模块", "修改模块名,批量更新该模块所有需求"), ("B2", "📝 重新描述模块需求", "重新输入模块需求描述,LLM 重新分解并生成代码"), ("B3", "🔧 逐条修改模块内需求", "对模块内每条需求单独修改并重新生成"), ("B4", "⚡ 批量重新生成模块代码", "保持需求内容不变,整体重新生成签名+代码"), ] while True: console.print(Rule()) table = Table(show_header=False, box=None, padding=(0, 2)) table.add_column("选项", style="bold yellow", width=5) table.add_column("功能", style="bold", width=26) table.add_column("说明", style="dim", width=42) for key, name, desc in sub_menu: table.add_row(f"[{key}]", name, desc) table.add_row("[back]", "↩ 返回", "") console.print(table) sub_action = Prompt.ask( "请选择操作", choices=["B1", "B2", "B3", "B4", "back"], default="back", ) if sub_action == "B1": module_rename( project=project, module_reqs=module_reqs, old_module=target_module, ) break elif sub_action == "B2": module_redescribe( project=project, module_reqs=module_reqs, target_module=target_module, output_dir=output_dir, knowledge_text=knowledge_text, ) break elif sub_action == "B3": module_edit_each( project=project, module_reqs=module_reqs, output_dir=output_dir, knowledge_text=knowledge_text, ) module_reqs = [ db.get_functional_requirement(r.id) for r in module_reqs if db.get_functional_requirement(r.id) ] elif sub_action == "B4": module_regen_code( project=project, module_reqs=module_reqs, output_dir=output_dir, knowledge_text=knowledge_text, ) else: break # ══════════════════════════════════════════════════════ # B1:重命名模块 # ══════════════════════════════════════════════════════ def module_rename( project: Project, module_reqs: list, old_module: str, ) -> None: """将指定模块重命名,批量更新该模块下所有需求的 module 字段,记录变更历史。""" new_module = Prompt.ask(f"请输入新模块名(当前:{old_module})") if not new_module.strip(): console.print("[red]模块名不能为空[/red]") return if new_module == old_module: console.print("[dim]模块名未变更,跳过。[/dim]") return change_summary = ( f"模块重命名:'{old_module}' → '{new_module}'\n" f" 影响需求数:{len(module_reqs)} 条\n" + "\n".join(f" · [{r.id}] {r.title}" for r in module_reqs) ) console.print(Panel(change_summary, title="📝 模块重命名预览", border_style="yellow")) if not Confirm.ask("确认执行模块重命名?", default=True): console.print("[yellow]已取消。[/yellow]") return for req in module_reqs: req.module = new_module db.update_functional_requirement(req) log_change( project_id = project.id, change_type = CHG_RENAME, summary = change_summary, module = old_module, ) console.print( f"[green]✓ 模块已重命名:'{old_module}' → '{new_module}'," f"共更新 {len(module_reqs)} 条需求[/green]" ) # ══════════════════════════════════════════════════════ # B2:重新描述模块需求 # ══════════════════════════════════════════════════════ def module_redescribe( project: Project, module_reqs: list, target_module: str, output_dir: str, knowledge_text: str = "", ) -> None: """ 用户重新输入该模块的需求描述文本, LLM 重新分解为功能需求,展示新旧对比后确认, 软删除旧需求,持久化新需求,重新生成签名+代码,记录变更历史。 """ console.print(Rule( f"[bold magenta]重新描述模块 '{target_module}' 需求[/bold magenta]" )) console.print("[bold]当前模块需求:[/bold]") print_functional_requirements(module_reqs) console.print( f"\n[bold]请重新输入模块 '[magenta]{target_module}[/magenta]'" " 的需求描述[/bold](输入空行结束):" ) lines = [] while True: line = input() if line == "": break lines.append(line) new_desc_text = "\n".join(lines).strip() if not new_desc_text: console.print("[yellow]输入为空,已取消。[/yellow]") return llm = LLMClient() analyzer = RequirementAnalyzer(llm) raw_req_id = module_reqs[0].raw_req_id if module_reqs else None with console.status( f"[cyan]LLM 正在重新分解模块 '{target_module}' 需求...[/cyan]" ): # ✅ 修复:移除不存在的 module_hint 参数 # 分解后统一通过 req.module = target_module 强制设置模块归属 new_reqs = analyzer.decompose( raw_requirement = new_desc_text, project_id = project.id, raw_req_id = raw_req_id, knowledge = knowledge_text, ) # 强制将所有新需求归属到当前模块 for req in new_reqs: req.module = target_module console.print(f"[green]✓ 重新分解完成,共 {len(new_reqs)} 条新功能需求[/green]") print_req_diff(old_reqs=module_reqs, new_reqs=new_reqs) if not Confirm.ask( f"确认用以上 {len(new_reqs)} 条新需求替换模块 '{target_module}' 的旧需求?", default=True, ): console.print("[yellow]已取消重新描述。[/yellow]") return # ── 软删除旧需求 ────────────────────────────────── deleted_ids = [] for req in module_reqs: req.status = "deleted" db.update_functional_requirement(req) deleted_ids.append(req.id) console.print( f"[dim]✓ 已软删除旧需求 {len(deleted_ids)} 条(ID: {deleted_ids})[/dim]" ) # ── 持久化新需求 ────────────────────────────────── all_reqs = db.list_functional_requirements(project.id) max_idx = max((r.index_no for r in all_reqs), default=0) for i, req in enumerate(new_reqs): req.index_no = max_idx + i + 1 req.id = db.create_functional_requirement(req) console.print(f"[green]✓ 新功能需求已持久化,共 {len(new_reqs)} 条[/green]") # ── 记录变更历史 ────────────────────────────────── change_summary = ( f"模块 '{target_module}' 需求重新描述:\n" f" 旧需求 {len(module_reqs)} 条(已软删除):\n" + "\n".join(f" - [{r.id}] {r.title}" for r in module_reqs) + f"\n 新需求 {len(new_reqs)} 条:\n" + "\n".join(f" + [{r.id}] {r.title}" for r in new_reqs) ) log_change( project_id = project.id, change_type = CHG_REDESCRIBE, summary = change_summary, module = target_module, ) # ── 重新生成签名与代码 ──────────────────────────── console.print( f"\n[cyan]正在为模块 '{target_module}' 重新生成签名与代码...[/cyan]" ) generator = CodeGenerator(llm) signatures = generate_signatures(analyzer, new_reqs, knowledge_text) mod_sig_file = f"module_{target_module}_redescribe_signatures.json" write_function_signatures_json( output_dir=output_dir, signatures=signatures, project_name=project.name, project_description=project.description or "", file_name=mod_sig_file, ) print_signatures_preview(signatures) code_files = generate_code( generator=generator, project=project, func_reqs=new_reqs, output_dir=output_dir, knowledge_text=knowledge_text, signatures=signatures, ) for cf in code_files: db.upsert_code_file(cf) for req in new_reqs: req.status = "generated" db.update_functional_requirement(req) patch_and_save_signatures( project=project, signatures=signatures, code_files=code_files, output_dir=output_dir, file_name=mod_sig_file, ) merge_signatures_to_main(project, signatures, output_dir) all_active = active_reqs(db.list_functional_requirements(project.id)) write_readme(project, all_active, output_dir) console.print(Panel.fit( f"[bold green]✅ 模块 '{target_module}' 需求重新描述完成![/bold green]\n" f"新需求 {len(new_reqs)} 条,生成代码 {len(code_files)} 个文件", border_style="green", )) # ══════════════════════════════════════════════════════ # B3:逐条修改模块内需求 # ══════════════════════════════════════════════════════ def module_edit_each( project: Project, module_reqs: list, output_dir: str, knowledge_text: str = "", ) -> None: """对模块内需求逐条展示并允许修改,每条确认后立即重新生成签名与代码,记录变更历史。""" llm = LLMClient() analyzer = RequirementAnalyzer(llm) generator = CodeGenerator(llm) for req in module_reqs: console.print(Rule(f"[cyan]需求 ID={req.id} · {req.title}[/cyan]")) console.print( f" 描述: {req.description}\n" f" 优先级: {req.priority}\n" f" 模块: {req.module}" ) if not Confirm.ask("是否修改此需求?", default=False): continue new_description = Prompt.ask(" 新描述", default=req.description) new_priority = Prompt.ask( " 新优先级", default=req.priority, choices=["high", "medium", "low"], ) new_module = Prompt.ask(" 新模块名", default=req.module) changed = ( new_description != req.description or new_priority != req.priority or new_module != req.module ) if not changed: console.print("[dim] 未检测到变更,跳过。[/dim]") continue change_summary = ( f"需求 '{req.title}'(ID={req.id})变更:\n" f" 描述: '{req.description}' → '{new_description}'\n" f" 优先级: '{req.priority}' → '{new_priority}'\n" f" 模块: '{req.module}' → '{new_module}'" ) console.print(Panel(change_summary, title="📝 变更预览", border_style="yellow")) if not Confirm.ask("确认此条变更?", default=True): console.print("[yellow] 已跳过。[/yellow]") continue req.description = new_description req.priority = new_priority req.module = new_module req.status = "pending" db.update_functional_requirement(req) log_change( project_id = project.id, change_type = CHG_EDIT, summary = change_summary, module = new_module, req_id = req.id, ) console.print(f" [cyan]正在重新生成 {req.function_name} 的签名与代码...[/cyan]") change_sig_file = f"change_{req.id}_signatures.json" signatures = generate_signatures(analyzer, [req], knowledge_text) write_function_signatures_json( output_dir=output_dir, signatures=signatures, project_name=project.name, project_description=project.description or "", file_name=change_sig_file, ) code_files = generate_code( generator=generator, project=project, func_reqs=[req], output_dir=output_dir, knowledge_text=knowledge_text, signatures=signatures, ) for cf in code_files: db.upsert_code_file(cf) req.status = "generated" db.update_functional_requirement(req) patch_and_save_signatures( project=project, signatures=signatures, code_files=code_files, output_dir=output_dir, file_name=change_sig_file, ) merge_signatures_to_main(project, signatures, output_dir) console.print(f" [green]✓ 需求 ID={req.id} 变更完成[/green]") console.print("[green]✓ 模块内需求逐条修改完成[/green]") # ══════════════════════════════════════════════════════ # B4:批量重新生成模块代码 # ══════════════════════════════════════════════════════ def module_regen_code( project: Project, module_reqs: list, output_dir: str, knowledge_text: str = "", ) -> None: """保持需求内容不变,对整个模块批量重新生成签名与代码,记录变更历史。""" module_name = module_reqs[0].module if module_reqs else "未知模块" console.print(Panel( f"模块:[bold magenta]{module_name}[/bold magenta]\n" f"需求数量:{len(module_reqs)} 条\n" + "\n".join( f" · [{r.id}] {r.title} ({r.function_name})" for r in module_reqs ), title="⚡ 批量重新生成预览", border_style="cyan", )) if not Confirm.ask( f"确认对模块 '{module_name}' 的 {len(module_reqs)} 条需求批量重新生成代码?", default=True, ): console.print("[yellow]已取消。[/yellow]") return llm = LLMClient() analyzer = RequirementAnalyzer(llm) generator = CodeGenerator(llm) for req in module_reqs: req.status = "pending" db.update_functional_requirement(req) console.print(f"\n[cyan]正在为模块 '{module_name}' 生成函数签名...[/cyan]") signatures = generate_signatures(analyzer, module_reqs, knowledge_text) mod_sig_file = f"module_{module_name}_signatures.json" write_function_signatures_json( output_dir=output_dir, signatures=signatures, project_name=project.name, project_description=project.description or "", file_name=mod_sig_file, ) print_signatures_preview(signatures) console.print(f"\n[cyan]正在为模块 '{module_name}' 生成代码文件...[/cyan]") code_files = generate_code( generator=generator, project=project, func_reqs=module_reqs, output_dir=output_dir, knowledge_text=knowledge_text, signatures=signatures, ) for cf in code_files: db.upsert_code_file(cf) for req in module_reqs: req.status = "generated" db.update_functional_requirement(req) patch_and_save_signatures( project=project, signatures=signatures, code_files=code_files, output_dir=output_dir, file_name=mod_sig_file, ) merge_signatures_to_main(project, signatures, output_dir) change_summary = ( f"模块 '{module_name}' 批量重新生成代码,共 {len(module_reqs)} 条需求:\n" + "\n".join(f" · [{r.id}] {r.title}" for r in module_reqs) ) log_change( project_id = project.id, change_type = CHG_REGEN, summary = change_summary, module = module_name, ) console.print( f"[bold green]✅ 模块 '{module_name}' 批量重新生成完成!" f"共 {len(code_files)} 个文件[/bold green]" )