# ui/display.py - 所有 Rich 表格 / 面板展示函数 import os from typing import Dict, List from rich.console import Console from rich.panel import Panel from rich.rule import Rule from rich.table import Table import config from constants import CHG_TYPE_LABEL, CHG_TYPE_COLOR from database.models import ( ChangeHistory, FunctionalRequirement, Project, ) console = Console() def print_banner() -> None: console.print() console.print(Panel.fit( "[bold cyan]🚀 需求分析 & 代码生成工具[/bold cyan]\n" "[dim]Powered by LLM · SQLite · Python[/dim]", border_style="cyan", )) console.print() def print_main_menu() -> None: console.print(Rule("[bold cyan]主菜单[/bold cyan]")) menu_items = [ ("1", "📁 新建项目", "输入需求 → 分解 → 生成代码"), ("2", "🔄 变更项目需求", "变更已有需求 / 变更模块需求 / 新增需求"), ("3", "📋 查看所有项目", "列表展示全部项目"), ("4", "🔍 查看项目详情", "需求列表 / 模块分组 / 变更历史"), ("5", "🗑 删除指定项目", "删除项目及其所有数据"), ("0", "🚪 退出", ""), ] table = Table(show_header=False, box=None, padding=(0, 2)) table.add_column("选项", style="bold yellow", width=4) table.add_column("功能", style="bold", width=22) table.add_column("说明", style="dim", width=38) for key, name, desc in menu_items: table.add_row(f"[{key}]", name, desc) console.print(table) console.print() def print_projects_table(projects: List[Project]) -> None: if not projects: console.print("[yellow] 暂无项目记录。[/yellow]") return table = Table(title="📋 项目列表", show_lines=True) table.add_column("ID", style="cyan", width=6) table.add_column("项目名", style="bold", width=22) table.add_column("语言", style="magenta", width=12) table.add_column("描述", width=35) table.add_column("输出目录", style="dim", width=30) for p in projects: desc = p.description or "" table.add_row( str(p.id), p.name, p.language or "-", desc[:40] + ("..." if len(desc) > 40 else ""), p.output_dir or "-", ) console.print(table) def print_functional_requirements(reqs: List[FunctionalRequirement]) -> None: if not reqs: console.print("[yellow] 暂无功能需求。[/yellow]") return priority_color = {"high": "red", "medium": "yellow", "low": "green"} status_color = { "pending": "yellow", "generated": "green", "failed": "red", "deleted": "dim", } table = Table(title="📋 功能需求列表", show_lines=True) table.add_column("序号", style="cyan", width=6) table.add_column("ID", style="dim", width=6) table.add_column("模块", style="magenta", width=15) table.add_column("标题", style="bold", width=18) table.add_column("函数名", width=25) table.add_column("优先级", width=8) table.add_column("状态", width=10) table.add_column("描述", width=35) for req in reqs: pc = priority_color.get(req.priority, "white") sc = status_color.get(req.status, "white") desc = req.description table.add_row( str(req.index_no), str(req.id) if req.id else "-", req.module or config.DEFAULT_MODULE, req.title, f"[code]{req.function_name}[/code]", f"[{pc}]{req.priority}[/{pc}]", f"[{sc}]{req.status}[/{sc}]", desc[:40] + "..." if len(desc) > 40 else desc, ) console.print(table) def print_module_summary(reqs: List[FunctionalRequirement]) -> None: module_map: Dict[str, List[str]] = {} for req in reqs: if req.status == "deleted": continue m = req.module or config.DEFAULT_MODULE module_map.setdefault(m, []).append(req.function_name) table = Table(title="📦 功能模块分组", show_lines=True) table.add_column("模块", style="magenta bold", width=20) table.add_column("函数数量", style="cyan", width=8) table.add_column("函数列表", width=50) for module, funcs in sorted(module_map.items()): table.add_row(module, str(len(funcs)), ", ".join(funcs)) console.print(table) def print_module_list(reqs: List[FunctionalRequirement]) -> List[str]: """打印带序号的模块列表(跳过已删除需求),返回有序模块名列表。""" module_map: Dict[str, List[FunctionalRequirement]] = {} for req in reqs: if req.status == "deleted": continue m = req.module or config.DEFAULT_MODULE module_map.setdefault(m, []).append(req) table = Table(title="📦 模块列表", show_lines=True) table.add_column("序号", style="cyan", width=6) table.add_column("模块名", style="magenta bold", width=22) table.add_column("需求数量", style="yellow", width=8) table.add_column("包含函数", width=45) modules = sorted(module_map.keys()) for i, module in enumerate(modules, 1): funcs = [r.function_name for r in module_map[module]] table.add_row(str(i), module, str(len(funcs)), ", ".join(funcs)) console.print(table) return modules def print_signatures_preview(signatures: List[dict]) -> None: table = Table(title="📄 函数签名预览", show_lines=True) table.add_column("需求编号", style="cyan", width=8) table.add_column("模块", style="magenta", width=15) table.add_column("函数名", style="bold", width=22) table.add_column("参数数", width=6) table.add_column("返回类型", width=10) table.add_column("URL", style="dim", width=28) for sig in signatures: ret = sig.get("return") or {} url = sig.get("url", "") url_display = os.path.basename(url) if url else "[dim]待生成[/dim]" table.add_row( sig.get("requirement_id", "-"), sig.get("module", "-"), sig.get("name", "-"), str(len(sig.get("parameters", {}))), ret.get("type", "void"), url_display, ) console.print(table) def print_change_history(histories: List[ChangeHistory]) -> None: """以表格形式展示变更历史,含变更类型、模块、需求 ID 等字段。""" if not histories: console.print("[dim] 暂无变更历史。[/dim]") return table = Table(title="🕒 变更历史", show_lines=True) table.add_column("ID", style="cyan", width=6) table.add_column("时间", style="dim", width=20) table.add_column("变更类型", width=14) table.add_column("模块", width=16) table.add_column("需求ID", width=8) table.add_column("变更摘要", width=50) for h in histories: ct = getattr(h, "change_type", "") or "" label = CHG_TYPE_LABEL.get(ct, ct) color = CHG_TYPE_COLOR.get(ct, "white") mod = getattr(h, "module", "") or "-" rid = str(getattr(h, "req_id", "") or "-") ts = str(getattr(h, "created_at", "-")) summary = h.changes if len(summary) > 60: summary = summary[:60] + "..." table.add_row( str(h.id), ts, f"[{color}]{label}[/{color}]", mod, rid, summary, ) console.print(table) def print_req_diff( old_reqs: List[FunctionalRequirement], new_reqs: List[FunctionalRequirement], ) -> None: """并排展示新旧需求对比表格。""" console.print() console.print(Rule("[bold]新旧需求对比[/bold]")) old_table = Table( title="❌ 旧需求(将被替换)", show_lines=True, border_style="red", ) old_table.add_column("ID", style="dim", width=6) old_table.add_column("标题", style="bold", width=18) old_table.add_column("函数名", width=22) old_table.add_column("描述", width=30) for r in old_reqs: old_table.add_row( str(r.id), r.title, r.function_name, r.description[:30] + "..." if len(r.description) > 30 else r.description, ) console.print(old_table) new_table = Table( title="✅ 新需求(将被创建)", show_lines=True, border_style="green", ) new_table.add_column("序号", style="cyan", width=6) new_table.add_column("标题", style="bold", width=18) new_table.add_column("函数名", width=22) new_table.add_column("描述", width=30) for r in new_reqs: new_table.add_row( str(r.index_no), r.title, r.function_name, r.description[:30] + "..." if len(r.description) > 30 else r.description, ) console.print(new_table) console.print()# ui/display.py - 所有 Rich 表格 / 面板展示函数 import os from typing import Dict, List from rich.console import Console from rich.panel import Panel from rich.rule import Rule from rich.table import Table import config from constants import CHG_TYPE_LABEL, CHG_TYPE_COLOR from database.models import ( ChangeHistory, FunctionalRequirement, Project, ) console = Console() def print_banner() -> None: console.print() console.print(Panel.fit( "[bold cyan]🚀 需求分析 & 代码生成工具[/bold cyan]\n" "[dim]Powered by LLM · SQLite · Python[/dim]", border_style="cyan", )) console.print() def print_main_menu() -> None: console.print(Rule("[bold cyan]主菜单[/bold cyan]")) menu_items = [ ("1", "📁 新建项目", "输入需求 → 分解 → 生成代码"), ("2", "🔄 变更项目需求", "变更已有需求 / 变更模块需求 / 新增需求"), ("3", "📋 查看所有项目", "列表展示全部项目"), ("4", "🔍 查看项目详情", "需求列表 / 模块分组 / 变更历史"), ("5", "🗑 删除指定项目", "删除项目及其所有数据"), ("0", "🚪 退出", ""), ] table = Table(show_header=False, box=None, padding=(0, 2)) table.add_column("选项", style="bold yellow", width=4) table.add_column("功能", style="bold", width=22) table.add_column("说明", style="dim", width=38) for key, name, desc in menu_items: table.add_row(f"[{key}]", name, desc) console.print(table) console.print() def print_projects_table(projects: List[Project]) -> None: if not projects: console.print("[yellow] 暂无项目记录。[/yellow]") return table = Table(title="📋 项目列表", show_lines=True) table.add_column("ID", style="cyan", width=6) table.add_column("项目名", style="bold", width=22) table.add_column("语言", style="magenta", width=12) table.add_column("描述", width=35) table.add_column("输出目录", style="dim", width=30) for p in projects: desc = p.description or "" table.add_row( str(p.id), p.name, p.language or "-", desc[:40] + ("..." if len(desc) > 40 else ""), p.output_dir or "-", ) console.print(table) def print_functional_requirements(reqs: List[FunctionalRequirement]) -> None: if not reqs: console.print("[yellow] 暂无功能需求。[/yellow]") return priority_color = {"high": "red", "medium": "yellow", "low": "green"} status_color = { "pending": "yellow", "generated": "green", "failed": "red", "deleted": "dim", } table = Table(title="📋 功能需求列表", show_lines=True) table.add_column("序号", style="cyan", width=6) table.add_column("ID", style="dim", width=6) table.add_column("模块", style="magenta", width=15) table.add_column("标题", style="bold", width=18) table.add_column("函数名", width=25) table.add_column("优先级", width=8) table.add_column("状态", width=10) table.add_column("描述", width=35) for req in reqs: pc = priority_color.get(req.priority, "white") sc = status_color.get(req.status, "white") desc = req.description table.add_row( str(req.index_no), str(req.id) if req.id else "-", req.module or config.DEFAULT_MODULE, req.title, f"[code]{req.function_name}[/code]", f"[{pc}]{req.priority}[/{pc}]", f"[{sc}]{req.status}[/{sc}]", desc[:40] + "..." if len(desc) > 40 else desc, ) console.print(table) def print_module_summary(reqs: List[FunctionalRequirement]) -> None: module_map: Dict[str, List[str]] = {} for req in reqs: if req.status == "deleted": continue m = req.module or config.DEFAULT_MODULE module_map.setdefault(m, []).append(req.function_name) table = Table(title="📦 功能模块分组", show_lines=True) table.add_column("模块", style="magenta bold", width=20) table.add_column("函数数量", style="cyan", width=8) table.add_column("函数列表", width=50) for module, funcs in sorted(module_map.items()): table.add_row(module, str(len(funcs)), ", ".join(funcs)) console.print(table) def print_module_list(reqs: List[FunctionalRequirement]) -> List[str]: """打印带序号的模块列表(跳过已删除需求),返回有序模块名列表。""" module_map: Dict[str, List[FunctionalRequirement]] = {} for req in reqs: if req.status == "deleted": continue m = req.module or config.DEFAULT_MODULE module_map.setdefault(m, []).append(req) table = Table(title="📦 模块列表", show_lines=True) table.add_column("序号", style="cyan", width=6) table.add_column("模块名", style="magenta bold", width=22) table.add_column("需求数量", style="yellow", width=8) table.add_column("包含函数", width=45) modules = sorted(module_map.keys()) for i, module in enumerate(modules, 1): funcs = [r.function_name for r in module_map[module]] table.add_row(str(i), module, str(len(funcs)), ", ".join(funcs)) console.print(table) return modules def print_signatures_preview(signatures: List[dict]) -> None: table = Table(title="📄 函数签名预览", show_lines=True) table.add_column("需求编号", style="cyan", width=8) table.add_column("模块", style="magenta", width=15) table.add_column("函数名", style="bold", width=22) table.add_column("参数数", width=6) table.add_column("返回类型", width=10) table.add_column("URL", style="dim", width=28) for sig in signatures: ret = sig.get("return") or {} url = sig.get("url", "") url_display = os.path.basename(url) if url else "[dim]待生成[/dim]" table.add_row( sig.get("requirement_id", "-"), sig.get("module", "-"), sig.get("name", "-"), str(len(sig.get("parameters", {}))), ret.get("type", "void"), url_display, ) console.print(table) def print_change_history(histories: List[ChangeHistory]) -> None: """以表格形式展示变更历史,含变更类型、模块、需求 ID 等字段。""" if not histories: console.print("[dim] 暂无变更历史。[/dim]") return table = Table(title="🕒 变更历史", show_lines=True) table.add_column("ID", style="cyan", width=6) table.add_column("时间", style="dim", width=20) table.add_column("变更类型", width=14) table.add_column("模块", width=16) table.add_column("需求ID", width=8) table.add_column("变更摘要", width=50) for h in histories: ct = getattr(h, "change_type", "") or "" label = CHG_TYPE_LABEL.get(ct, ct) color = CHG_TYPE_COLOR.get(ct, "white") mod = getattr(h, "module", "") or "-" rid = str(getattr(h, "req_id", "") or "-") ts = str(getattr(h, "created_at", "-")) summary = h.changes if len(summary) > 60: summary = summary[:60] + "..." table.add_row( str(h.id), ts, f"[{color}]{label}[/{color}]", mod, rid, summary, ) console.print(table) def print_req_diff( old_reqs: List[FunctionalRequirement], new_reqs: List[FunctionalRequirement], ) -> None: """并排展示新旧需求对比表格。""" console.print() console.print(Rule("[bold]新旧需求对比[/bold]")) old_table = Table( title="❌ 旧需求(将被替换)", show_lines=True, border_style="red", ) old_table.add_column("ID", style="dim", width=6) old_table.add_column("标题", style="bold", width=18) old_table.add_column("函数名", width=22) old_table.add_column("描述", width=30) for r in old_reqs: old_table.add_row( str(r.id), r.title, r.function_name, r.description[:30] + "..." if len(r.description) > 30 else r.description, ) console.print(old_table) new_table = Table( title="✅ 新需求(将被创建)", show_lines=True, border_style="green", ) new_table.add_column("序号", style="cyan", width=6) new_table.add_column("标题", style="bold", width=18) new_table.add_column("函数名", width=22) new_table.add_column("描述", width=30) for r in new_reqs: new_table.add_row( str(r.index_no), r.title, r.function_name, r.description[:30] + "..." if len(r.description) > 30 else r.description, ) console.print(new_table) console.print() def display_change_history(histories: list[dict]) -> None: """ 展示变更历史表格。 Args: histories: get_change_histories() 返回的 dict 列表, 每条包含 id / change_time / status / change_type / module / req_id / summary """ if not histories: console.print("[yellow]暂无变更历史记录。[/yellow]") return table = Table( title="变更历史", box=box.ROUNDED, show_lines=True, header_style="bold cyan", ) table.add_column("ID", style="dim", width=6) table.add_column("变更时间", style="white", width=20) table.add_column("类型", style="cyan", width=14) table.add_column("模块", style="green", width=16) table.add_column("需求 ID", style="yellow", width=8) table.add_column("摘要", style="white", width=40) table.add_column("状态", style="magenta",width=10) for h in histories: # histories 已是 dict(由 get_change_histories 反序列化) change_time = h.get("change_time") time_str = ( change_time.strftime("%Y-%m-%d %H:%M:%S") if hasattr(change_time, "strftime") else str(change_time or "") ) status = h.get("status", "") status_style = { "pending": "[yellow]pending[/yellow]", "confirmed": "[green]confirmed[/green]", }.get(status, status) table.add_row( str(h.get("id", "")), time_str, str(h.get("change_type", "")), str(h.get("module", "")), str(h.get("req_id") or ""), str(h.get("summary", ""))[:60], status_style, ) console.print(table)