AIDeveloper-PC/requirements_generator/ui/display.py

520 lines
20 KiB
Python
Raw Normal View History

# 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)
2026-03-06 17:20:01 +00:00
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)