# ui/prompts.py - 交互式输入 / 选择工具函数 from typing import List, Optional from rich.console import Console from rich.prompt import Confirm, Prompt import config from database.db_manager import DBManager from database.models import FunctionalRequirement, Project from ui.display import print_projects_table from utils.file_handler import merge_knowledge_files console = Console() db = DBManager() def select_project(prompt_text: str = "请选择项目 ID") -> Optional[Project]: """展示项目列表,交互选择并返回 Project 对象;输入 0 返回 None。""" projects = db.list_projects() if not projects: console.print("[yellow]当前暂无项目,请先新建项目。[/yellow]") return None print_projects_table(projects) pid_str = Prompt.ask(f"{prompt_text}(输入 0 返回)", default="0") if pid_str == "0": return None try: pid = int(pid_str) except ValueError: console.print("[red]ID 必须为整数[/red]") return None project = db.get_project(pid) if not project: console.print(f"[red]项目 ID={pid} 不存在[/red]") return None return project def load_knowledge_optional() -> str: """询问是否加载知识库文件,加载后返回合并文本;否则返回空字符串。""" if Confirm.ask("是否加载知识库文件?", default=False): kb_path = Prompt.ask("知识库文件路径(多个用逗号分隔)") paths = [p.strip() for p in kb_path.split(",") if p.strip()] text = merge_knowledge_files(paths) console.print(f"[dim]已加载 {len(paths)} 个知识库文件[/dim]") return text return "" def input_multiline(prompt_hint: str = "请输入内容") -> str: """多行文本输入,输入空行结束,返回合并字符串。""" console.print(f"[dim]{prompt_hint}(输入空行结束):[/dim]") lines: List[str] = [] while True: line = input() if line == "": break lines.append(line) return "\n".join(lines).strip() def pause() -> None: """暂停,等待用户按 Enter 键返回主菜单。""" console.print() input(" 按 Enter 键返回主菜单...") def interactive_edit_req( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式编辑指定序号的需求字段。""" idx_str = Prompt.ask("输入要编辑的序号") try: idx = int(idx_str) except ValueError: console.print("[red]序号必须为整数[/red]") return reqs for req in reqs: if req.index_no == idx: req.title = Prompt.ask("新标题", default=req.title) req.description = Prompt.ask("新描述", default=req.description) req.function_name = Prompt.ask("新函数名", default=req.function_name) req.priority = Prompt.ask( "新优先级", default=req.priority, choices=["high", "medium", "low"], ) req.module = Prompt.ask("新模块", default=req.module) console.print(f"[green]✓ 序号 {idx} 已更新[/green]") return reqs console.print(f"[red]序号 {idx} 不存在[/red]") return reqs def interactive_delete_req( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式删除指定序号的需求(内存操作,未持久化)。""" idx_str = Prompt.ask("输入要删除的序号") try: idx = int(idx_str) except ValueError: console.print("[red]序号必须为整数[/red]") return reqs new_reqs = [r for r in reqs if r.index_no != idx] if len(new_reqs) < len(reqs): console.print(f"[green]✓ 序号 {idx} 已删除[/green]") else: console.print(f"[red]序号 {idx} 不存在[/red]") return new_reqs def interactive_add_req( reqs: List[FunctionalRequirement], project: Project, raw_req_id: int, ) -> List[FunctionalRequirement]: """交互式新增一条需求到列表(内存操作,未持久化)。""" next_idx = max((r.index_no for r in reqs), default=0) + 1 title = Prompt.ask("新需求标题") description = Prompt.ask("新需求描述") function_name = Prompt.ask("函数名(snake_case)") priority = Prompt.ask( "优先级", choices=["high", "medium", "low"], default="medium", ) module = Prompt.ask("所属模块", default=config.DEFAULT_MODULE) new_req = FunctionalRequirement( project_id = project.id, raw_req_id = raw_req_id, index_no = next_idx, title = title, description = description, function_name = function_name, priority = priority, module = module, status = "pending", is_custom = True, ) reqs.append(new_req) console.print(f"[green]✓ 已添加新需求: {title}(序号 {next_idx})[/green]") return reqs def interactive_adjust_modules( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式逐条调整需求的模块归属,并立即持久化。""" while True: idx_str = Prompt.ask("输入要调整的需求序号(输入 0 结束)", default="0") if idx_str == "0": break for req in reqs: if str(req.index_no) == idx_str: new_module = Prompt.ask( f"'{req.function_name}' 新模块名", default=req.module, ) req.module = new_module db.update_functional_requirement(req) console.print( f"[green]✓ 已更新模块: {req.function_name} → {new_module}[/green]" ) break else: console.print(f"[red]序号 {idx_str} 不存在[/red]") return reqs# ui/prompts.py - 交互式输入 / 选择工具函数 from typing import List, Optional from rich.console import Console from rich.prompt import Confirm, Prompt import config from database.db_manager import DBManager from database.models import FunctionalRequirement, Project from ui.display import print_projects_table from utils.file_handler import merge_knowledge_files console = Console() db = DBManager() def select_project(prompt_text: str = "请选择项目 ID") -> Optional[Project]: """展示项目列表,交互选择并返回 Project 对象;输入 0 返回 None。""" projects = db.list_projects() if not projects: console.print("[yellow]当前暂无项目,请先新建项目。[/yellow]") return None print_projects_table(projects) pid_str = Prompt.ask(f"{prompt_text}(输入 0 返回)", default="0") if pid_str == "0": return None try: pid = int(pid_str) except ValueError: console.print("[red]ID 必须为整数[/red]") return None project = db.get_project(pid) if not project: console.print(f"[red]项目 ID={pid} 不存在[/red]") return None return project def load_knowledge_optional() -> str: """询问是否加载知识库文件,加载后返回合并文本;否则返回空字符串。""" if Confirm.ask("是否加载知识库文件?", default=False): kb_path = Prompt.ask("知识库文件路径(多个用逗号分隔)") paths = [p.strip() for p in kb_path.split(",") if p.strip()] text = merge_knowledge_files(paths) console.print(f"[dim]已加载 {len(paths)} 个知识库文件[/dim]") return text return "" def input_multiline(prompt_hint: str = "请输入内容") -> str: """多行文本输入,输入空行结束,返回合并字符串。""" console.print(f"[dim]{prompt_hint}(输入空行结束):[/dim]") lines: List[str] = [] while True: line = input() if line == "": break lines.append(line) return "\n".join(lines).strip() def pause() -> None: """暂停,等待用户按 Enter 键返回主菜单。""" console.print() input(" 按 Enter 键返回主菜单...") def interactive_edit_req( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式编辑指定序号的需求字段。""" idx_str = Prompt.ask("输入要编辑的序号") try: idx = int(idx_str) except ValueError: console.print("[red]序号必须为整数[/red]") return reqs for req in reqs: if req.index_no == idx: req.title = Prompt.ask("新标题", default=req.title) req.description = Prompt.ask("新描述", default=req.description) req.function_name = Prompt.ask("新函数名", default=req.function_name) req.priority = Prompt.ask( "新优先级", default=req.priority, choices=["high", "medium", "low"], ) req.module = Prompt.ask("新模块", default=req.module) console.print(f"[green]✓ 序号 {idx} 已更新[/green]") return reqs console.print(f"[red]序号 {idx} 不存在[/red]") return reqs def interactive_delete_req( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式删除指定序号的需求(内存操作,未持久化)。""" idx_str = Prompt.ask("输入要删除的序号") try: idx = int(idx_str) except ValueError: console.print("[red]序号必须为整数[/red]") return reqs new_reqs = [r for r in reqs if r.index_no != idx] if len(new_reqs) < len(reqs): console.print(f"[green]✓ 序号 {idx} 已删除[/green]") else: console.print(f"[red]序号 {idx} 不存在[/red]") return new_reqs def interactive_add_req( reqs: List[FunctionalRequirement], project: Project, raw_req_id: int, ) -> List[FunctionalRequirement]: """交互式新增一条需求到列表(内存操作,未持久化)。""" next_idx = max((r.index_no for r in reqs), default=0) + 1 title = Prompt.ask("新需求标题") description = Prompt.ask("新需求描述") function_name = Prompt.ask("函数名(snake_case)") priority = Prompt.ask( "优先级", choices=["high", "medium", "low"], default="medium", ) module = Prompt.ask("所属模块", default=config.DEFAULT_MODULE) new_req = FunctionalRequirement( project_id = project.id, raw_req_id = raw_req_id, index_no = next_idx, title = title, description = description, function_name = function_name, priority = priority, module = module, status = "pending", is_custom = True, ) reqs.append(new_req) console.print(f"[green]✓ 已添加新需求: {title}(序号 {next_idx})[/green]") return reqs def interactive_adjust_modules( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式逐条调整需求的模块归属,并立即持久化。""" while True: idx_str = Prompt.ask("输入要调整的需求序号(输入 0 结束)", default="0") if idx_str == "0": break for req in reqs: if str(req.index_no) == idx_str: new_module = Prompt.ask( f"'{req.function_name}' 新模块名", default=req.module, ) req.module = new_module db.update_functional_requirement(req) console.print( f"[green]✓ 已更新模块: {req.function_name} → {new_module}[/green]" ) break else: console.print(f"[red]序号 {idx_str} 不存在[/red]") return reqs# ui/prompts.py - 交互式输入 / 选择工具函数 from typing import List, Optional from rich.console import Console from rich.prompt import Confirm, Prompt import config from database.db_manager import DBManager from database.models import FunctionalRequirement, Project from ui.display import print_projects_table from utils.file_handler import merge_knowledge_files console = Console() db = DBManager() def select_project(prompt_text: str = "请选择项目 ID") -> Optional[Project]: """展示项目列表,交互选择并返回 Project 对象;输入 0 返回 None。""" projects = db.list_projects() if not projects: console.print("[yellow]当前暂无项目,请先新建项目。[/yellow]") return None print_projects_table(projects) pid_str = Prompt.ask(f"{prompt_text}(输入 0 返回)", default="0") if pid_str == "0": return None try: pid = int(pid_str) except ValueError: console.print("[red]ID 必须为整数[/red]") return None project = db.get_project(pid) if not project: console.print(f"[red]项目 ID={pid} 不存在[/red]") return None return project def load_knowledge_optional() -> str: """询问是否加载知识库文件,加载后返回合并文本;否则返回空字符串。""" if Confirm.ask("是否加载知识库文件?", default=False): kb_path = Prompt.ask("知识库文件路径(多个用逗号分隔)") paths = [p.strip() for p in kb_path.split(",") if p.strip()] text = merge_knowledge_files(paths) console.print(f"[dim]已加载 {len(paths)} 个知识库文件[/dim]") return text return "" def input_multiline(prompt_hint: str = "请输入内容") -> str: """多行文本输入,输入空行结束,返回合并字符串。""" console.print(f"[dim]{prompt_hint}(输入空行结束):[/dim]") lines: List[str] = [] while True: line = input() if line == "": break lines.append(line) return "\n".join(lines).strip() def pause() -> None: """暂停,等待用户按 Enter 键返回主菜单。""" console.print() input(" 按 Enter 键返回主菜单...") def interactive_edit_req( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式编辑指定序号的需求字段。""" idx_str = Prompt.ask("输入要编辑的序号") try: idx = int(idx_str) except ValueError: console.print("[red]序号必须为整数[/red]") return reqs for req in reqs: if req.index_no == idx: req.title = Prompt.ask("新标题", default=req.title) req.description = Prompt.ask("新描述", default=req.description) req.function_name = Prompt.ask("新函数名", default=req.function_name) req.priority = Prompt.ask( "新优先级", default=req.priority, choices=["high", "medium", "low"], ) req.module = Prompt.ask("新模块", default=req.module) console.print(f"[green]✓ 序号 {idx} 已更新[/green]") return reqs console.print(f"[red]序号 {idx} 不存在[/red]") return reqs def interactive_delete_req( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式删除指定序号的需求(内存操作,未持久化)。""" idx_str = Prompt.ask("输入要删除的序号") try: idx = int(idx_str) except ValueError: console.print("[red]序号必须为整数[/red]") return reqs new_reqs = [r for r in reqs if r.index_no != idx] if len(new_reqs) < len(reqs): console.print(f"[green]✓ 序号 {idx} 已删除[/green]") else: console.print(f"[red]序号 {idx} 不存在[/red]") return new_reqs def interactive_add_req( reqs: List[FunctionalRequirement], project: Project, raw_req_id: int, ) -> List[FunctionalRequirement]: """交互式新增一条需求到列表(内存操作,未持久化)。""" next_idx = max((r.index_no for r in reqs), default=0) + 1 title = Prompt.ask("新需求标题") description = Prompt.ask("新需求描述") function_name = Prompt.ask("函数名(snake_case)") priority = Prompt.ask( "优先级", choices=["high", "medium", "low"], default="medium", ) module = Prompt.ask("所属模块", default=config.DEFAULT_MODULE) new_req = FunctionalRequirement( project_id = project.id, raw_req_id = raw_req_id, index_no = next_idx, title = title, description = description, function_name = function_name, priority = priority, module = module, status = "pending", is_custom = True, ) reqs.append(new_req) console.print(f"[green]✓ 已添加新需求: {title}(序号 {next_idx})[/green]") return reqs def interactive_adjust_modules( reqs: List[FunctionalRequirement], ) -> List[FunctionalRequirement]: """交互式逐条调整需求的模块归属,并立即持久化。""" while True: idx_str = Prompt.ask("输入要调整的需求序号(输入 0 结束)", default="0") if idx_str == "0": break for req in reqs: if str(req.index_no) == idx_str: new_module = Prompt.ask( f"'{req.function_name}' 新模块名", default=req.module, ) req.module = new_module db.update_functional_requirement(req) console.print( f"[green]✓ 已更新模块: {req.function_name} → {new_module}[/green]" ) break else: console.print(f"[red]序号 {idx_str} 不存在[/red]") return reqs