xls2ddl/aidocs/xls2crud.md
2025-10-12 13:57:44 +08:00

13 KiB
Raw Blame History

xls2crud.py 技术文档

工具名称xls2crud.py
功能描述:从 Excel 模型文件(.xlsx)自动生成基于模板的 CRUD 前后端界面代码,支持数据浏览器、新增、编辑、删除、查询及关联子表操作。
适用场景:快速构建基于数据库模型的 Web 应用前端 UI 和后端接口描述。


目录


1. 简介

本脚本通过读取 .xlsx 表格定义的数据模型和 JSON 配置文件,自动为指定数据表生成完整的 CRUD 界面组件:

  • 数据浏览页(index.ui
  • 新增表单(add_*.dspy
  • 编辑表单(update_*.dspy
  • 删除逻辑(delete_*.dspy
  • 数据获取接口(get_*.dspy
  • 关联字段状态检查(check_changed.dspy

所有输出均基于预设的 Jinja-like 模板渲染,并支持动态参数替换。


2. 依赖说明

import os
import sys
import codecs
import json
import argparse

from appPublic.dictObject import DictObject
from xlsxData import xlsxFactory
from appPublic.folderUtils import listFile, _mkdir
from appPublic.myTE import MyTemplateEngine
from tmpls import (
    data_browser_tmpl,
    get_data_tmpl,
    data_new_tmpl,
    data_update_tmpl,
    data_delete_tmpl,
    check_changed_tmpls
)
from appPublic.argsConvert import ArgsConvert

外部模块说明

模块 功能
appPublic.dictObject 将字典转换为可点式访问的对象(类似 JavaScript 的对象)
xlsxData.xlsxFactory 解析 .xlsx 文件并提取结构化数据
appPublic.folderUtils.listFile, _mkdir 文件遍历与目录创建工具
appPublic.myTE.MyTemplateEngine 轻量级模板引擎,支持变量替换
tmpls.* 内置字符串形式的模板内容HTML/UI/DSPY
appPublic.argsConvert 支持 ${var}$[[var]] 形式的变量替换

3. 使用方式

命令行语法

python xls2crud.py [-m models_dir] [-o output_dir] modulename json_file [...]

参数说明

参数 是否必需 说明
modulename 当前模块名,用于数据库上下文解析
json_file 至少一个 CRUD 配置 JSON 文件路径
-m, --models_dir .xlsx 模型文件所在目录(可在 JSON 中覆盖)
-o, --output_dir 输出根目录,默认为当前路径

示例命令

python xls2crud.py -m ./models -o ./ui_output user_module user_config.json role_config.json

4. 核心函数说明

build_dbdesc(models_dir: str) -> dict

功能

扫描指定目录下的所有 .xlsx 文件,将其解析为统一的数据库描述对象。

输入

  • models_dir: 字符串或列表,包含模型文件路径

输出

  • dict: 键为表名(来自 summary[0].name),值为该表的完整描述对象(含字段、编码表、子表等)

流程

  1. 遍历目录中所有 .xlsx 文件
  2. 使用 xlsxFactory 加载每个文件
  3. 提取其 get_data() 结果
  4. 取第一项 summary 的 name 作为表名注册进 db_desc

subtable2toolbar(desc)

功能

desc.subtables 中定义的子表信息转化为工具栏按钮及弹窗绑定事件。

参数

  • desc: 当前表的描述对象DictObject

行为

  • 若无 toolbar,初始化为空对象
  • 为每个子表添加:
    • 工具栏图标按钮SVG 图标 + label
    • 绑定点击事件打开 PopupWindow
    • POST 请求跳转至对应 URL支持相对路径
    • 自动映射主键 id 和引用控件 referer_widget
    • 支持额外字段映射via mapping

示例生成的 bind 结构

{
  "wid": "self",
  "event": "child_table",
  "actiontype": "urlwidget",
  "target": "PopupWindow",
  "popup_options": {
    "title": "子表标题",
    "width": "70%",
    "height": "70%"
  },
  "params_mapping": {
    "mapping": { "id": "parent_id", "referer_widget": "referer_widget" }
  },
  "options": {
    "method": "POST",
    "url": "{{entire_url('../child_table')}}"
  }
}

build_crud_ui(crud_data: dict, dbdesc: dict)

功能

根据传入的配置和数据库描述,驱动整个 CRUD 界面生成流程。

参数

  • crud_data: 来自 JSON 文件的配置对象DictObject
  • dbdesc: 所有表的元数据集合

步骤

  1. 获取目标表名 tblname
  2. 更新 desc 参数(如权限、标题等)
  3. 调用 subtable2toolbar(desc) 添加子表按钮
  4. 如果存在 relation 字段,则启用“行选中联动”机制
  5. 渲染 binds 为 JSON 字符串
  6. 调用 build_table_crud_ui() 开始生成具体文件

build_table_crud_ui(uidir: str, desc: dict) -> None

功能

协调生成所有与当前表相关的 UI 文件。

行为

  • 创建输出目录(若不存在)
  • 生成:
    • index.ui(数据浏览器)
    • get_{tblname}.dspy(数据获取)
  • 若有外键关系(desc.relation
    • 仅生成 check_changed.dspy
  • 否则生成标准三件套:
    • add_*.dspy
    • update_*.dspy
    • delete_*.dspy

field_list(desc: dict) -> list

功能

构造适用于前端展示的字段列表包含类型、宽度、标签、UI 类型等信息。

逻辑

  1. 遍历 desc.fields
  2. 判断是否是码表字段(在 codes 中定义)
    • 是 → 调用 get_code_desc
    • 否 → 调用 setup_ui_info
  3. 应用 browserfields.alters 进行个性化覆盖
  4. 返回最终字段数组

get_code_desc(field: dict, desc: dict) -> dict

功能

处理码表字段(如性别、状态),将其转换为下拉选择框或远程数据源字段。

输出字段说明

属性 说明
uitype 'code' 表示码表类型
valueField / textField 实际值与显示文本字段名
params 请求码表数据所需参数dbname, table, cond 等)
dataurl 固定为 /appbase/get_code.dspy

特性支持

  • 支持条件表达式中的变量替换(如 ${dept_id}$
  • 使用 ArgsConvert 解析并注入运行时变量

setup_ui_info(field:dict, confidential_fields=[]) ->dict

功能

为普通字段设置默认 UI 显示属性。

类型映射规则

数据库类型 uitype 说明
date date 日期输入框
time time 时间输入框
int, short, etc. int 整数输入
float, double, decimal float 浮点数输入
text text 多行文本
其他 str 默认字符串
名称以 _date 结尾 date 智能识别
confidential_fields password 密码掩码

宽度计算

  • cwidth = min(max(length, 4), 18)
  • 最小 4最大 18单位字符宽

construct_get_data_sql(desc: dict) -> str

功能

构建用于获取主表及其码表连接数据的 SQL 查询语句。

分支逻辑

A. 存在外键关联且有码表

生成 LEFT JOIN 查询,判断是否存在外键记录(has_xxx 标志位),并带出码表文本。

SELECT '${param_field}$' AS param_field,
       CASE WHEN b.param_field IS NULL THEN 0 ELSE 1 END has_param_field,
       a.value AS code_field,
       a.text AS code_field_text
FROM code_table a
LEFT JOIN (SELECT * FROM main_table WHERE param_field = ${param_field}$) b
  ON a.value = b.code_field;
B. 无码表

直接查询主表 + 占位符 [[filterstr]]

SELECT * FROM table_name WHERE 1=1 [[filterstr]]
C. 有一般码表(非外键)

构建多个 LEFT JOIN 子查询,别名为 b, c, ...,拼接成完整查询。

SELECT a.*, b.type_text, c.status_text
FROM (SELECT * FROM main WHERE 1=1 [[filterstr]]) a
LEFT JOIN (SELECT value AS status, text AS status_text FROM status_codes WHERE 1=1) c
  ON a.status = c.status;

其他辅助函数

函数 功能
alter_field(field, desc) 使用 desc.browserfields.alters[name] 修改特定字段属性
filter_backslash(s) 替换字符串中的 \\//,防止模板路径错误
build_data_browser(pat, desc) 渲染 data_browser_tmplindex.ui
build_data_new / update / delete 分别生成增删改页面
build_get_data 生成数据查询接口 .dspy 文件
build_check_changed 生成用于检测外键关联变化的特殊接口

5. 模板系统与输出结构

模板来源

所有模板来自 tmpls 模块,包括:

模板变量 用途
data_browser_tmpl 主列表界面index.ui
get_data_tmpl 数据获取接口
data_new_tmpl 新增页面
data_update_tmpl 编辑页面
data_delete_tmpl 删除确认/执行页面
check_changed_tmpls 外键关联状态检查接口

模板语法支持

  • {{ var }}:变量插入
  • ${ var }$:环境变量占位符(由 ArgsConvert 替换)
  • [[ filterstr ]]SQL 过滤条件注入点

6. 配置文件格式 (json_file)

{
  "tblname": "user",
  "alias": "user_manage",
  "params": {
    "title": "用户管理",
    "pagesize": 20,
    "confidential_fields": ["password"],
    "relation": {
      "param_field": "org_id",
      "outter_field": "id",
      "table": "organization"
    },
    "codes": [
      {
        "field": "status",
        "table": "sys_codes",
        "valuefield": "c_value",
        "textfield": "c_text",
        "cond": "ctype='USER_STATUS'"
      }
    ],
    "subtables": [
      {
        "subtable": "user_role",
        "title": "角色分配",
        "field": "user_id",
        "url": "../user_role",
        "mapping": {}
      }
    ],
    "toolbar": null,
    "binds": [],
    "browserfields": {
      "alters": {
        "name": { "label": "姓名", "uitype": "str", "cwidth": 20 }
      }
    }
  },
  "models_dir": "./models"
}

字段说明

字段 类型 说明
tblname string 主表名(必须存在于 .xlsx 中)
alias string 输出目录名(可选,默认为 tblname
params object 表级配置对象
params.title string 页面标题
params.confidential_fields array 需隐藏显示的字段(变为密码框)
params.relation object 外键关联信息(启用 check_changed
params.codes array 码表配置
params.subtables array 子表配置(生成工具栏按钮)
params.browserfields.alters object 字段显示定制
models_dir string .xlsx 模型目录(优先级高于命令行)

7. 输出目录结构示例

假设命令为:

python xls2crud.py -o ./dist -m ./models user_mod user_conf.json

user_conf.json"alias": "users""tblname": "user"

则输出结构如下:

./dist/
└── users/
    ├── index.ui                         # 数据浏览器
    ├── add_user.dspy                    # 新增页面
    ├── update_user.dspy                 # 编辑页面
    ├── delete_user.dspy                 # 删除页面
    ├── get_user.dspy                    # 数据获取接口
    └── check_changed.dspy               # (如果有 relation状态检查接口

8. 注意事项与限制

⚠️ 已知限制

  1. Excel 文件要求

    • 必须包含 summary 工作表
    • 第一行 summary[0].name 作为表名
    • fields 表格需定义字段元信息name, type, title, length...
  2. 模板路径问题

    • 模板内使用 {{entire_url(...)}} 构造绝对路径,请确保前端框架支持此函数
  3. SQL 注入防护

    • [[filterstr]] 不做转义,应由调用端保证安全
  4. 并发写入风险

    • 多个 JSON 文件同时处理同一张表可能导致文件覆盖
  5. 编码要求

    • 所有 .xlsx.json 文件必须为 UTF-8 编码

最佳实践建议

  • 使用 alias 区分不同视图的输出路径
  • alters 中统一设置中文标签和列宽
  • 对敏感字段显式加入 confidential_fields
  • 使用 cond + 变量实现动态码表过滤

版本信息

  • 创建时间:未知
  • 最后更新:根据代码注释推测近期维护
  • 维护者:内部团队(appPublic, xslxDATA 为私有库)

📝 文档版本v1.0
审核状态:已完成初稿
💬 如需扩展模板字段或增加校验逻辑,请联系开发组。