ShiErFeng/shierfeng-fastapi-backend/cli/tui/adapters/gen.py
2026-07-24 09:43:10 +08:00

808 lines
32 KiB
Python

from typing import Any
from cli.tui.adapters.base import BaseBrowserAdapter
from cli.tui.adapters.models import (
TUI_ADAPTER_MODEL_RENDERER,
BrowserPageSnapshot,
BrowserRecordSnapshot,
DetailSectionSnapshot,
)
from cli.tui.copy import TUI_COPY
from cli.tui.diagnostics import TUI_DIAGNOSTIC_SERVICE
from cli.utils import NESTED_CLI_SUPPORT, SHELL_TEXT_FORMATTER
class GenRenderingSupport:
"""
代码生成浏览页渲染支持对象。
该对象负责布尔语义渲染与常见文本辅助逻辑,供分区和记录构建复用。
"""
@staticmethod
def render_yes_no(value: object) -> str:
"""
将常见布尔语义值转换为“是/否”。
:param value: 原始值
:return: 中文布尔文本
"""
normalized = str(value).strip().lower()
return '' if normalized in {'1', 'y', 'yes', 'true'} else ''
class GenSectionBuilder:
"""
代码生成浏览页分区构建器。
该构建器负责构建代码生成页共享分区,以及单条业务表详情分区。
:param page_adapter: 代码生成浏览页适配器
:param rendering: 代码生成浏览页渲染支持对象
"""
def __init__(
self,
page_adapter: BaseBrowserAdapter,
rendering: GenRenderingSupport,
) -> None:
"""
初始化代码生成浏览页分区构建器。
:param page_adapter: 代码生成浏览页适配器
:param rendering: 代码生成浏览页渲染支持对象
:return: None
"""
self.page_adapter = page_adapter
self.rendering = rendering
def build_gen_focus_section(self, payload: dict[str, Any] | None) -> DetailSectionSnapshot:
"""
构建业务表概览分区。
:param payload: `gen detail` JSON 负载
:return: 分区快照
"""
detail = payload.get('detail') if isinstance(payload, dict) else None
info = detail.get('info') if isinstance(detail, dict) else None
if not isinstance(info, dict):
return DetailSectionSnapshot(
title='业务表摘要',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(payload, empty_label='详情', empty_value=''),
)
return DetailSectionSnapshot(
title='业务表摘要',
status='ok' if payload.get('ok', False) else 'fail',
lines=[
'## 表身份',
f'表 ID: {payload.get("tableId", "-")}',
f'表名: {SHELL_TEXT_FORMATTER.truncate_text(payload.get("tableName", "-"), 40)}',
],
)
def build_gen_generation_section(self, payload: dict[str, Any] | None) -> DetailSectionSnapshot:
"""
构建代码生成配置分区。
:param payload: `gen detail` JSON 负载
:return: 分区快照
"""
detail = payload.get('detail') if isinstance(payload, dict) else None
info = detail.get('info') if isinstance(detail, dict) else None
if not isinstance(info, dict):
return DetailSectionSnapshot(
title='生成配置',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(
payload, empty_label='生成配置', empty_value='不可用'
),
)
return DetailSectionSnapshot(
title='生成配置',
status='ok' if payload.get('ok', False) else 'fail',
lines=[
'## 生成类信息',
f'生成类名: {SHELL_TEXT_FORMATTER.truncate_text(info.get("className", "-"), 32)}',
f'所属模块: {SHELL_TEXT_FORMATTER.truncate_text(info.get("moduleName", "-"), 24)}',
'',
'## 业务信息',
f'业务标识: {SHELL_TEXT_FORMATTER.truncate_text(info.get("businessName", "-"), 24)}',
f'功能名称: {SHELL_TEXT_FORMATTER.truncate_text(info.get("functionName", "-"), 24)}',
],
)
def build_gen_column_summary_section(self, payload: dict[str, Any] | None) -> DetailSectionSnapshot:
"""
构建字段概览分区。
:param payload: `gen detail` JSON 负载
:return: 分区快照
"""
detail = payload.get('detail') if isinstance(payload, dict) else None
rows = detail.get('rows') if isinstance(detail, dict) else None
if not isinstance(rows, list):
return DetailSectionSnapshot(
title='字段摘要',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(
payload, empty_label='字段摘要', empty_value='不可用'
),
)
row_dicts = [row for row in rows if isinstance(row, dict)]
primary_key_count = sum(1 for row in row_dicts if self.rendering.render_yes_no(row.get('isPk', '-')) == '')
required_count = sum(1 for row in row_dicts if self.rendering.render_yes_no(row.get('isRequired', '-')) == '')
return DetailSectionSnapshot(
title='字段摘要',
status='ok' if payload.get('ok', False) else 'fail',
lines=[
'## 字段规模',
f'字段总数: {payload.get("columnCount", "-")}',
f'主键字段: {primary_key_count}',
f'必填字段: {required_count}',
],
)
def build_gen_columns_section(self, payload: dict[str, Any] | None) -> DetailSectionSnapshot:
"""
构建业务表字段分区。
:param payload: `gen detail` JSON 负载
:return: 分区快照
"""
detail = payload.get('detail') if isinstance(payload, dict) else None
rows = detail.get('rows') if isinstance(detail, dict) else None
if not isinstance(rows, list) or not rows:
return DetailSectionSnapshot(
title='字段列表',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(payload, empty_label='字段', empty_value=''),
)
lines: list[str] = []
for row in rows[:12]:
if not isinstance(row, dict):
continue
lines.extend(
[
f'## {SHELL_TEXT_FORMATTER.truncate_text(row.get("columnName", "-"), 24)} · {SHELL_TEXT_FORMATTER.truncate_text(row.get("columnType", "-"), 20)}',
(
f'> 主键: {self.rendering.render_yes_no(row.get("isPk", "-"))} | '
f'必填: {self.rendering.render_yes_no(row.get("isRequired", "-"))} | '
f'查询: {row.get("queryType", "-")}'
),
f'> 说明: {SHELL_TEXT_FORMATTER.truncate_text(row.get("columnComment", "-"), 40)}',
'',
]
)
return DetailSectionSnapshot(
title='字段列表',
status='ok' if payload.get('ok', False) else 'fail',
lines=(lines[:-1] if lines and lines[-1] == '' else lines)
or TUI_ADAPTER_MODEL_RENDERER.build_empty_lines(
empty_label='字段信息',
empty_value='0 列',
detail='当前业务表没有可展示的字段信息',
),
)
def build_gen_precheck_section(
self,
detail_payload: dict[str, Any] | None,
preview_payload: dict[str, Any] | None,
) -> DetailSectionSnapshot:
"""
构建代码生成前校验分区。
:param detail_payload: `gen detail` JSON 负载
:param preview_payload: `gen preview` JSON 负载
:return: 分区快照
"""
detail = detail_payload.get('detail') if isinstance(detail_payload, dict) else None
info = detail.get('info') if isinstance(detail, dict) else None
rows = detail.get('rows') if isinstance(detail, dict) and isinstance(detail.get('rows'), list) else []
preview = preview_payload.get('preview') if isinstance(preview_payload, dict) else None
preview_templates = preview if isinstance(preview, dict) else {}
row_dicts = [row for row in rows if isinstance(row, dict)]
has_class_name = bool(isinstance(info, dict) and str(info.get('className', '') or '').strip())
has_module_name = bool(isinstance(info, dict) and str(info.get('moduleName', '') or '').strip())
has_business_name = bool(isinstance(info, dict) and str(info.get('businessName', '') or '').strip())
has_primary_key = any(self.rendering.render_yes_no(row.get('isPk', '-')) == '' for row in row_dicts)
column_count = len(row_dicts)
template_count = len(preview_templates)
risk_items: list[str] = []
if not has_class_name:
risk_items.append('生成类名缺失')
if not has_module_name:
risk_items.append('所属模块缺失')
if not has_business_name:
risk_items.append('业务标识缺失')
if column_count <= 0:
risk_items.append('字段列表为空')
if not has_primary_key:
risk_items.append('未识别到主键字段')
if template_count <= 0:
risk_items.append('未生成可预览模板')
status = 'ok' if not risk_items else 'warn'
return DetailSectionSnapshot(
title='生成前校验',
status=status,
lines=[
'## 校验结果',
f'生成类名: {"通过" if has_class_name else "缺失"}',
f'所属模块: {"通过" if has_module_name else "缺失"}',
f'业务标识: {"通过" if has_business_name else "缺失"}',
f'字段数量: {column_count}',
f'主键字段: {"通过" if has_primary_key else "缺失"}',
f'模板预览: {template_count}',
'',
'## 风险提示',
*(risk_items if risk_items else ['当前未发现阻断生成的明显风险']),
],
)
def build_gen_sync_precheck_section(
self,
table_name: str,
payload: dict[str, Any] | None,
) -> DetailSectionSnapshot:
"""
构建数据库表结构同步前检查分区。
:param table_name: 业务表名称
:param payload: `gen db-list --table-name=...` JSON 负载
:return: 分区快照
"""
if not isinstance(payload, dict) or not payload.get('ok', False):
return DetailSectionSnapshot(
title='同步预检查',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(
payload, empty_label='同步预检查', empty_value='不可用'
),
)
rows = self.page_adapter.extract_page_rows(payload)
matched_row = next(
(row for row in rows if str(row.get('tableName', '') or '').strip().lower() == table_name.strip().lower()),
None,
)
if matched_row is None:
return DetailSectionSnapshot(
title='同步预检查',
status='warn',
lines=[
'## 当前状态',
f'目标业务表: {table_name}',
'数据库物理表: 未匹配',
'',
'## 建议操作',
'当前数据库中未找到同名物理表,执行同步前应先确认表结构来源',
],
)
return DetailSectionSnapshot(
title='同步预检查',
status='ok',
lines=[
'## 当前状态',
f'目标业务表: {table_name}',
f'数据库物理表: {matched_row.get("tableName", "-")}',
f'表注释: {SHELL_TEXT_FORMATTER.truncate_text(matched_row.get("tableComment", "-"), 56)}',
'',
'## 建议操作',
'已匹配到同名物理表,可继续使用同步数据库表结构动作',
],
)
def build_gen_preview_section(self, payload: dict[str, Any] | None) -> DetailSectionSnapshot:
"""
构建代码预览分区。
:param payload: `gen preview` JSON 负载
:return: 分区快照
"""
if not isinstance(payload, dict) or not payload.get('ok', False):
return DetailSectionSnapshot(
title='代码预览',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(
payload, empty_label='代码预览', empty_value='不可用'
),
)
preview_payload = payload.get('preview') if isinstance(payload.get('preview'), dict) else {}
lines = [
'## 模板规模',
f'模板数量: {payload.get("templateCount", len(preview_payload))}',
]
if not preview_payload:
lines.extend(
[
'',
*TUI_ADAPTER_MODEL_RENDERER.build_empty_lines(
empty_label='模板样本',
empty_value='0 份',
detail='当前业务表没有可预览的模板输出',
),
]
)
return DetailSectionSnapshot(title='代码预览', status='info', lines=lines)
lines.extend(['', '## 模板样本'])
for template_name, template_content in list(preview_payload.items())[:4]:
preview_lines = str(template_content).splitlines()[:3]
lines.append(f'## {SHELL_TEXT_FORMATTER.truncate_text(template_name, 48)}')
lines.extend(f'> {SHELL_TEXT_FORMATTER.truncate_text(line, 72)}' for line in preview_lines)
lines.append('')
if lines[-1] == '':
lines.pop()
return DetailSectionSnapshot(
title='代码预览',
status='ok',
lines=lines,
)
def build_gen_export_preview_section(self, payload: dict[str, Any] | None) -> DetailSectionSnapshot:
"""
构建代码导出预演分区。
:param payload: `gen export --dry-run` JSON 负载
:return: 分区快照
"""
if not isinstance(payload, dict) or not payload.get('ok', False):
return DetailSectionSnapshot(
title='导出预览',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(
payload, empty_label='导出预览', empty_value='不可用'
),
)
results = payload.get('results') if isinstance(payload.get('results'), list) else []
lines = [
'## 预演结果',
f'执行模式: {payload.get("mode", "-")}',
f'dry-run: {"" if payload.get("dryRun", False) else ""}',
f'表数量: {len(payload.get("tableNames", [])) if isinstance(payload.get("tableNames"), list) else 0}',
f'结果数量: {len(results)}',
'',
'## 摘要',
f'结果摘要: {SHELL_TEXT_FORMATTER.truncate_text(payload.get("message", "-"), 72)}',
]
if payload.get('outputFile'):
lines.append(f'输出文件: {SHELL_TEXT_FORMATTER.truncate_text(payload.get("outputFile", "-"), 72)}')
if payload.get('genPath'):
lines.append(f'输出目录: {SHELL_TEXT_FORMATTER.truncate_text(payload.get("genPath", "-"), 72)}')
if results:
lines.extend(['', '## 结果样本'])
for item in results[:4]:
if not isinstance(item, dict):
continue
lines.append(
f'> {item.get("tableName", "-")} · {"成功" if item.get("ok", False) else "失败"} · '
f'{SHELL_TEXT_FORMATTER.truncate_text(item.get("message", "-"), 48)}'
)
return DetailSectionSnapshot(
title='导出预览',
status='ok',
lines=lines,
)
def build_importable_tables_section(self, payload: dict[str, Any] | None) -> DetailSectionSnapshot:
"""
构建数据库可导入表共享分区。
:param payload: `gen db-list` JSON 负载
:return: 分区快照
"""
if not isinstance(payload, dict) or not payload.get('ok', False):
return DetailSectionSnapshot(
title='可导入数据表',
status='fail',
lines=TUI_ADAPTER_MODEL_RENDERER.build_failure_lines(
payload, empty_label='数据表', empty_value='不可用'
),
)
rows = self.page_adapter.extract_page_rows(payload)
lines = TUI_ADAPTER_MODEL_RENDERER.build_empty_lines(
empty_label='可导入数据表',
empty_value='0 张',
detail='当前环境没有可导入的数据库表',
)
if rows:
lines = [
f'{SHELL_TEXT_FORMATTER.truncate_text(row.get("tableName", "-"), 40)} · {SHELL_TEXT_FORMATTER.truncate_text(row.get("tableComment", "-"), 48)}'
for row in rows[:8]
]
return DetailSectionSnapshot(
title='可导入数据表',
status='ok',
lines=lines,
)
@staticmethod
def build_gen_export_entry_section(table_name: str) -> DetailSectionSnapshot:
"""
构建代码导出向导入口分区。
:param table_name: 当前业务表名称
:return: 分区快照
"""
return DetailSectionSnapshot(
title='导出入口',
status='info',
lines=TUI_COPY.build_command_hint_lines(
scenario=f'准备导出当前业务表 {table_name} 的生成结果时,应先通过向导确认目标表、输出目录和覆盖范围。',
command=TUI_COPY.build_cli_command_hint('wizard', 'gen-export', '--output=text'),
guide='进入向导后优先选择当前业务表,并在最终确认前检查导出目录和文件覆盖预览。',
),
)
@staticmethod
def build_gen_import_entry_section(importable_rows: list[dict[str, Any]]) -> DetailSectionSnapshot:
"""
构建物理表导入入口分区。
:param importable_rows: 可导入物理表列表
:return: 分区快照
"""
suggested_table_names = [
str(row.get('tableName', '') or '').strip()
for row in importable_rows[:3]
if str(row.get('tableName', '') or '').strip()
]
suggested_tables = ' '.join(suggested_table_names) if suggested_table_names else '<table_name>'
return DetailSectionSnapshot(
title='导入入口',
status='info',
lines=TUI_COPY.build_command_hint_lines(
scenario='准备把数据库物理表纳入代码生成管理时,应先核对物理表名、注释和目标环境,再通过导入命令执行 dry-run 预演。',
command=TUI_COPY.build_cli_command_hint(
'gen', 'import-table', suggested_tables, '--dry-run', '--output=text'
),
guide='建议先从“可导入数据表”中确认目标表名,必要时一次只导入 1 到 3 张表,确认 dry-run 输出后再执行真实导入。',
),
)
@staticmethod
def build_gen_create_entry_section() -> DetailSectionSnapshot:
"""
构建建表 SQL 导入入口分区。
:return: 分区快照
"""
sql_template = 'CREATE TABLE demo_table (id bigint primary key);'
return DetailSectionSnapshot(
title='建表入口',
status='info',
lines=TUI_COPY.build_command_hint_lines(
scenario='准备根据建表 SQL 直接创建物理表并导入代码生成配置时,应先使用单条 SQL 执行 dry-run 预演,确认语句可解析且只包含目标表。',
command=TUI_COPY.build_cli_command_hint(
'gen', 'create-table', '--dry-run', '--sql', sql_template, '--output=text'
),
guide='建议优先使用单条 CREATE TABLE 语句做预演;若 SQL 较长或来自文件,可改用 --sql-file 方式,但不要同时传入 --sql 与 --sql-file。',
),
)
def load_gen_detail_sections(
self,
table_row: dict[str, Any],
env: str,
) -> list[DetailSectionSnapshot]:
"""
按需加载单条业务表详情分区。
:param table_row: 业务表列表行数据
:param env: 当前运行环境
:return: 详情分区列表
"""
table_id = table_row.get('tableId')
detail_payload = NESTED_CLI_SUPPORT.run(
'gen',
'detail',
str(table_id),
f'--env={env}',
'--output=json',
parse_json=True,
).payload
preview_payload = NESTED_CLI_SUPPORT.run(
'gen',
'preview',
str(table_id),
f'--env={env}',
'--output=json',
parse_json=True,
).payload
table_name = str(table_row.get('tableName', '-') or '-')
export_payload = NESTED_CLI_SUPPORT.run(
'gen',
'export',
table_name,
f'--env={env}',
'--dry-run',
'--mode=zip',
'--output=json',
'--yes',
parse_json=True,
).payload
sync_check_payload = NESTED_CLI_SUPPORT.run(
'gen',
'db-list',
f'--env={env}',
f'--table-name={table_name}',
'--paged',
'--page-size=5',
'--output=json',
parse_json=True,
).payload
return [
self.build_gen_focus_section(detail_payload),
self.build_gen_generation_section(detail_payload),
self.build_gen_column_summary_section(detail_payload),
self.build_gen_precheck_section(detail_payload, preview_payload),
self.build_gen_sync_precheck_section(table_name, sync_check_payload),
self.build_gen_columns_section(detail_payload),
self.build_gen_preview_section(preview_payload),
self.build_gen_export_preview_section(export_payload),
self.build_gen_export_entry_section(table_name),
]
def build_gen_overview_section(
self,
gen_rows: list[dict[str, Any]],
filtered_rows: list[dict[str, Any]],
importable_rows: list[dict[str, Any]],
) -> DetailSectionSnapshot:
"""
构建代码生成页总览判断共享分区。
:param gen_rows: 全量业务表行列表
:param filtered_rows: 当前筛选后的业务表行列表
:param importable_rows: 可导入物理表行列表
:return: 分区快照
"""
incomplete_count = sum(
1
for row in gen_rows
if not str(row.get('className', '') or '').strip()
or not str(row.get('moduleName', '') or '').strip()
or not str(row.get('businessName', '') or '').strip()
)
status = 'ok'
conclusion = '当前生成配置可继续下钻,优先查看预检查、代码预览和导出预演'
if incomplete_count > 0:
status = 'warn'
conclusion = '存在生成配置不完整的业务表,建议先处理生成前校验风险'
elif not gen_rows and importable_rows:
status = 'info'
conclusion = '当前还没有业务表配置,可先从可导入物理表中选择目标'
return DetailSectionSnapshot(
title='总览判断',
status=status,
lines=[
'## 当前结论',
conclusion,
'',
'## 核心指标',
f'已加载业务表: {len(gen_rows)}',
f'当前匹配: {len(filtered_rows)}',
f'可导入物理表: {len(importable_rows)}',
f'配置待补全: {incomplete_count}',
'',
'## 建议入口',
'优先关注:生成前校验 / 同步预检查 / 代码预览 / 导出预览 / 导入入口 / 建表入口',
],
)
class GenRecordBuilder:
"""
代码生成浏览记录构建器。
该对象负责构建代码生成页单条业务表浏览记录与失败兜底记录。
:param page_adapter: 代码生成浏览页适配器
:param section_builder: 代码生成浏览页分区构建器
"""
def __init__(
self,
page_adapter: BaseBrowserAdapter,
section_builder: GenSectionBuilder,
) -> None:
"""
初始化代码生成浏览记录构建器。
:param page_adapter: 代码生成浏览页适配器
:param section_builder: 代码生成浏览页分区构建器
:return: None
"""
self.page_adapter = page_adapter
self.section_builder = section_builder
def build_gen_record(self, table_row: dict[str, Any], env: str) -> BrowserRecordSnapshot:
"""
构建单条业务表浏览记录。
:param table_row: 业务表列表行数据
:param env: 当前运行环境
:return: 浏览记录快照
"""
table_id = table_row.get('tableId', '-')
table_name = str(table_row.get('tableName', '-') or '-')
class_name = str(table_row.get('className', '-') or '-')
module_name = str(table_row.get('moduleName', '-') or '-')
return BrowserRecordSnapshot(
key=f'gen:{table_id}',
title=SHELL_TEXT_FORMATTER.truncate_text(table_name, 40),
status='ok',
summary=f'生成类 {SHELL_TEXT_FORMATTER.truncate_text(class_name, 24)} · 模块 {SHELL_TEXT_FORMATTER.truncate_text(module_name, 20)}',
metadata_lines=[
'## 表身份',
f'表 ID: {table_id}',
'',
'## 生成信息',
f'生成类名: {SHELL_TEXT_FORMATTER.truncate_text(class_name, 32)}',
f'所属模块: {SHELL_TEXT_FORMATTER.truncate_text(module_name, 24)}',
f'业务标识: {SHELL_TEXT_FORMATTER.truncate_text(table_row.get("businessName", "-"), 24)}',
],
detail_sections=[],
detail_loader=lambda table_row=table_row, env=env: self.section_builder.load_gen_detail_sections(
table_row, env
),
)
def build_failure_record(self, payload: dict[str, Any] | None) -> BrowserRecordSnapshot:
"""
构建代码生成页失败兜底记录。
:param payload: 失败结果负载
:return: 浏览记录快照
"""
return self.page_adapter.build_failure_record(
key='gen:unavailable',
subject='代码生成',
section_subject='业务表列表',
payload=payload,
)
class GenBrowserAdapter(BaseBrowserAdapter):
"""
代码生成浏览页适配器。
该适配器负责采集业务表列表、详情、预览与可导入表清单,并委托
协作对象完成共享分区、详情分区和记录构建。
"""
def __init__(
self,
rendering: GenRenderingSupport | None = None,
section_builder: GenSectionBuilder | None = None,
record_builder: GenRecordBuilder | None = None,
) -> None:
"""
初始化代码生成浏览页适配器。
:param rendering: 代码生成浏览页渲染支持对象
:param section_builder: 代码生成浏览页分区构建器
:param record_builder: 代码生成浏览记录构建器
:return: None
"""
super().__init__(
page_title='代码生成',
search_view_key='gen',
filter_options=(),
)
self.rendering = rendering or GenRenderingSupport()
self.section_builder = section_builder or GenSectionBuilder(self, self.rendering)
self.record_builder = record_builder or GenRecordBuilder(self, self.section_builder)
@staticmethod
def apply_gen_query(rows: list[dict[str, Any]], query: str) -> list[dict[str, Any]]:
"""
按业务表名、生成类名或模块名查询词过滤业务表行数据。
:param rows: 原始业务表行列表
:param query: 当前搜索词
:return: 过滤后的业务表行列表
"""
normalized_query = str(query).strip().lower()
if not normalized_query:
return rows
return [
row
for row in rows
if normalized_query in str(row.get('tableName', '') or '').strip().lower()
or normalized_query in str(row.get('className', '') or '').strip().lower()
or normalized_query in str(row.get('moduleName', '') or '').strip().lower()
]
def collect_snapshot(self, env: str, query: str = '') -> BrowserPageSnapshot:
"""
采集代码生成浏览页只读快照。
:param env: 当前运行环境
:param query: 当前搜索词
:return: 浏览页快照
"""
search_context = self.resolve_search_context(query)
gen_tables_payload = NESTED_CLI_SUPPORT.run(
'gen',
'list',
f'--env={env}',
'--paged',
'--page-size=8',
'--output=json',
parse_json=True,
).payload
db_tables_payload = NESTED_CLI_SUPPORT.run(
'gen',
'db-list',
f'--env={env}',
'--paged',
'--page-size=8',
'--output=json',
parse_json=True,
).payload
importable_rows = self.extract_page_rows(db_tables_payload)
if not isinstance(gen_tables_payload, dict) or not gen_tables_payload.get('ok', False):
return BrowserPageSnapshot(
title='代码生成',
subtitle=TUI_COPY.build_unavailable_subtitle(
'业务表',
SHELL_TEXT_FORMATTER.truncate_text(self.extract_payload_message(gen_tables_payload), 72),
),
records=[self.record_builder.build_failure_record(gen_tables_payload)],
shared_sections=[
self.section_builder.build_gen_overview_section([], [], importable_rows),
self.section_builder.build_importable_tables_section(db_tables_payload),
self.section_builder.build_gen_import_entry_section(importable_rows),
self.section_builder.build_gen_create_entry_section(),
],
search=search_context,
)
rows = self.extract_page_rows(gen_tables_payload)
filtered_rows = self.apply_gen_query(rows, query)
records = [self.record_builder.build_gen_record(table_row, env) for table_row in filtered_rows[:8]]
if not records:
records = [
self.build_empty_record(
key='gen:none',
subject='业务表',
empty_label='业务表',
has_source_rows=bool(rows),
filtered_summary='当前搜索条件下没有匹配业务表',
empty_summary='当前环境中还没有纳入代码生成的业务表',
filtered_empty_value='暂无匹配',
empty_empty_value='暂无配置',
filtered_detail='当前搜索条件下没有匹配业务表',
empty_detail='当前环境中尚未配置代码生成业务表',
)
]
return BrowserPageSnapshot(
title='代码生成',
subtitle=TUI_DIAGNOSTIC_SERVICE.build_gen_diagnostic_subtitle(
len(filtered_rows),
len(importable_rows),
),
records=records,
shared_sections=[
self.section_builder.build_gen_overview_section(rows, filtered_rows, importable_rows),
self.section_builder.build_importable_tables_section(db_tables_payload),
self.section_builder.build_gen_import_entry_section(importable_rows),
self.section_builder.build_gen_create_entry_section(),
],
search=search_context,
)
GEN_BROWSER_ADAPTER = GenBrowserAdapter()