概述
EzAdmin DSL 配置生成助手用于生成和维护 EzAdmin DSL 配置文件,包括 list JSON、form JSON、express .ql 脚本和组件配置。
根据用户描述或数据库表结构,生成列表页 list、表单页 form、iframe 子表、组件配置及 express .ql 脚本。
工作流程
- 收集模块名、功能名、表名、主键字段、字段列表、枚举/外键/子表/流程信息。
- 读取同模块已有 DSL 文件,优先沿用当前项目风格。
- 生成或修改以下路径的文件。
- 对涉及的组件读取对应子 skill,按子 skill 里的详细配置生成。
- 修改完成后运行能覆盖本次改动的最小测试或语法检查。
文件结构
src/main/resources/topezadmin/config/layui/dsl/
├── form/{模块名}/
│ ├── {功能名}.json
│ ├── {功能名}_initExpress.ql
│ ├── {功能名}_submitExpress.ql
│ └── {功能名}_deleteExpress.ql
└── list/{模块名}/
├── {功能名}.json
└── {功能名}_express_main.ql
URL 规则
框架路由
框架路由使用相对路径,不加 / 前缀:
"url": "form/page-product/base-product?ID={{=d.ID}}"
"url": "list/page-product/base-product"
"url": "form/delete-product/base-product?ID={{=d.ID}}"
业务 Controller
业务 Controller 使用绝对路径,保留 /:
"url": "/purchase/inbound/label/printPage?inboundItemId={{=d.ID}}"
"url": "/mycamunda/check/history/Process_product?id=${ID}"
新增表单日期默认值
新增表单需要把日期字段默认成当天时,优先在打开表单的新增 URL 上传框架内置默认参数:
"url": "form/page-finance/finance-arap-flow?FINANCE_BILL_ID=${ID}&TRADER_TIME=EZ_TODAY_DATE_NORMAL"
EZ_TODAY_DATE_NORMAL 会被框架替换为 yyyy-MM-dd 格式当天日期。只给新增入口加;编辑入口带 ID 时不要加,避免覆盖数据库已有日期。
List DSL 要点
基本结构
{
"id": "base-product",
"name": "产品管理",
"dataSource": "dataSource",
"body": {
"emptyShow": "-",
"showIndex": true,
"selectable": false,
"rowActionWidth": 175
},
"tabList": [],
"search": [{"row": []}],
"column": [],
"tableButton": [],
"rowButton": [],
"express": {
"main": "@import(base-product_express_main.ql)",
"orderBy": "ORDER BY t.PROD_ID DESC",
"groupBy": ""
}
}
搜索 operator 常用值
| 值 | SQL | 场景 |
|---|---|---|
like |
LIKE '%?%' |
文本模糊搜索 |
EQ |
= |
精确匹配、枚举 |
= |
= |
精确匹配的另一种写法 |
BETWEEN |
BETWEEN ? AND ? |
日期/数值区间,配合 props.range: true |
IN |
IN (...) |
多选 |
GTE / LTE |
>= / <= |
数值范围 |
日期搜索默认规则
List 搜索项使用 component: "date" 时,默认生成 operator: "BETWEEN" 和 props.range: true。
{"item_name": "ADD_TIME", "label": "添加时间", "component": "date",
"operator": "BETWEEN", "props": {"range": true}}
{"item_name": "ADD_DATE", "label": "添加日期", "component": "date", "operator": "EQ"}
多字段切换搜索(unioninput)
{"item_name": "PROD_NAME_PROD_MODEL_PROD_SPEC", "label": "编码", "component": "unioninput",
"operator": "like", "props": {"placeholder": "请输入名称、型号、规格"},
"options": [
{"label": "产品名称", "value": "PROD_NAME", "operator": "like"},
{"label": "产品型号", "value": "PROD_MODEL", "operator": "like"},
{"label": "产品规格", "value": "PROD_SPEC", "operator": "like"}
]
},
{"item_name": "PROD_NAME", "label": "名称", "component": "hidden", "operator": "like"},
{"item_name": "PROD_MODEL", "label": "型号", "component": "hidden", "operator": "like"},
{"item_name": "PROD_SPEC", "label": "规格", "component": "hidden", "operator": "like"}
日期范围切换(uniondate)
{"item_name": "UNIONDATE", "label": "搜索", "component": "uniondate", "operator": "BETWEEN",
"props": {"range": true},
"options": [
{"label": "添加时间", "value": "ADD_TIME"},
{"label": "发货时间", "value": "DELIVERY_TIME"}
]
},
{"item_name": "ADD_TIME", "component": "hidden", "jdbcType": "DATETIME"},
{"item_name": "DELIVERY_TIME", "component": "hidden", "jdbcType": "DATETIME"}
Express 主查询
列表 express 主查询必须给主键别名 ID,主表建议别名 t:
StringBuilder sql = new StringBuilder();
companyId = $$("COMPANY_ID");
sql.append("
SELECT
t.PROD_ID ID,
t.PROD_CODE,
t.PROD_NAME
FROM T_BASE_PRODUCT t
WHERE t.DELETE_FLAG = 0
AND t.COMPANY_ID = " + companyId);
return search(sql);
search(sql) 自动拼接 search 栏的过滤条件。
Form DSL 要点
基本结构
{
"id": "base-product",
"name": "产品表单",
"dataSource": "dataSource",
"successUrl": "reload",
"definitionKey": "",
"cardList": [],
"buttonList": [],
"initExpress": "@import(base-product_initExpress.ql)",
"submitExpress": "@import(base-product_submitExpress.ql)",
"deleteExpress": "@import(base-product_deleteExpress.ql)",
"statusExpress": [],
"appendHead": "",
"appendFoot": ""
}
successUrl 取值
| 值 | 说明 |
|---|---|
reload |
刷新父页面(默认) |
reloadlocal |
刷新当前表单 |
reloadTableData |
仅刷新父表格数据 |
refreshcard.{item_name} |
刷新父表单指定 iframe card |
parent.refreshcard.{item_name} |
子表单在 iframe 内弹出时,刷新父窗口里指定的 iframe card |
普通字段 card 示例
{
"type": "card",
"label": "基本信息",
"fieldList": [
{"row": [
{"item_name": "PROD_NAME", "label": "名称", "component": "input",
"classAppend": "layui-col-md8", "props": {"lay-verify": "required"}},
{"item_name": "STATUS", "label": "状态", "component": "select",
"classAppend": "layui-col-md4",
"initData": {"dataJson": [{"value": 1, "label": "启用"}, {"value": 0, "label": "禁用"}]}}
]}
],
"buttonList": []
}
layui-col-md12、layui-col-md8、layui-col-md6、layui-col-md4、layui-col-md3、layui-col-md0(纯隐藏不占位)。同一 row 内字段宽度之和应 ≤ 12。
Express 速查
常用函数
| 函数 | 说明 |
|---|---|
$("KEY") |
取请求参数 |
$$("KEY") |
取 Session 参数 |
isBlank("KEY") / isNotBlank("KEY") |
判断请求参数空/非空 |
search(sql) |
列表查询,自动拼接 search 条件 |
select(sql) / selectOne(sql) |
查询多行/单行 |
count(sql) |
查询计数,常用于唯一性/存在性校验 |
insert(sql) / update(sql) |
执行写入 |
insertSimple(InsertParam) / updateSimple(UpdateParam) |
构建式新增/更新 |
spring("beanName").method(args) |
调用 Spring Bean |
Session 常用 key
COMPANY_IDEZ_SESSION_USER_ID_KEYEZ_SESSION_USER_NAME_KEY
生命周期
表单 appendFoot 在页面中按以下顺序执行:
initGlobal- 组件渲染
- 异步赋值
initFunction(data)- 用户交互
submitHandler()(如有)submitSuccess()
initFunction(data),不要在顶层脚本或 layui.use 刚进入时读取异步回填值做业务初始化,此时数据可能还没回填。
initFunction 示例
function initFunction(data) {
if ($("#ID").val()) {
$("[name=FIELD]").attr("disabled", "disabled");
layui.form.render();
}
}
submitSuccess 示例
var submitSuccess = function(data) {
if (data && data.code == 0) {
layer.alert("保存成功", function(index) {
layer.close(index);
window.location.reload();
});
return;
}
layer.alert((data && data.message) || "保存失败");
}
校验规则
简单必填
使用 props.lay-verify: "required",或新式写法 props.required: true + props.validate.rule.required: true。
复杂/条件校验
条件校验、跨字段校验、格式校验统一用 jQuery Validate 的 $.validator.addMethod 注册自定义规则名,DSL 侧 props.validate.rule.{规则名}: true 引用。
{
"item_name": "PRODUCT_CATEGORY_ID",
"component": "input",
"props": {
"validate": {
"rule": {"categoryPairRequired": true},
"message": {"categoryPairRequired": "新国标分类与旧国标分类不能同时为空"}
}
}
}
对应 appendFoot/initFunction 里注册规则:
$.validator.addMethod("categoryPairRequired", function(value, element){
var a = $.trim($("[name='PRODUCT_CATEGORY_ID']").val() || "");
var b = $.trim($("[name='OLD_CATEGORY_ID']").val() || "");
return a !== "" || b !== "";
}, "新国标分类与旧国标分类不能同时为空");
$('[name=FIELD]').rules('add', ...) 动态增删校验规则——validator 实例未初始化时会报错,优先在 DSL props.validate 里静态声明。
表单组件
组件细节不放在主 skill。需要使用某个组件时,必须读取对应子 skill。
input 组件
单行文本输入,最常用的表单字段组件。
基本配置
{
"item_name": "PROD_NAME",
"label": "产品名称",
"component": "input",
"classAppend": "layui-col-md8",
"props": {
"lay-verify": "required",
"maxlength": 100,
"placeholder": "请输入产品名称"
}
}
props
| 配置 | 说明 |
|---|---|
lay-verify |
简单必填校验 |
maxlength |
最大输入长度 |
placeholder |
占位提示文字 |
validate |
jQuery Validate 规则 |
lay-verify 取值范围
项目实际只出现过 "required" 单个取值。文档理论上支持 number/phone/email 及组合写法,但当前项目里没有真实用例,遇到需要格式校验的场景优先走 jQuery Validate 方式。
复杂/条件校验
{
"item_name": "PRODUCT_CATEGORY_ID",
"component": "input",
"props": {
"validate": {
"rule": {"categoryPairRequired": true},
"message": {"categoryPairRequired": "新国标分类与旧国标分类不能同时为空"}
}
}
}
textarea 组件
多行文本输入。
基本配置
{
"item_name": "COMMENT",
"label": "备注",
"component": "textarea",
"classAppend": "layui-col-md12",
"props": {
"rows": 4,
"maxlength": 500
}
}
props
| 配置 | 说明 |
|---|---|
rows |
显示行数 |
maxlength |
最大输入长度 |
placeholder |
占位提示文字 |
layui-col-md12 占满整行。校验规则写法与 input 组件一致。
span 组件
只读展示,不可编辑。三种典型用途:
1. 占位提示(值尚未生成)
{
"item_name": "PURCHASE_ORDER_NO",
"label": "订单编号",
"component": "span",
"classAppend": "layui-col-md6",
"props": {"placeholder": "自动生成"}
}
2. 说明文字
{
"item_name": "PROD_REG_NAME",
"label": "产品注册名称",
"component": "span",
"classAppend": "layui-col-md12",
"props": {"description": "产品注册证上的名称,关联注册证后自动生成"}
}
3. 只读展示字典值
{
"item_name": "ORDER_TYPE",
"label": "订单类型",
"component": "span",
"classAppend": "layui-col-md6",
"initData": {
"dataJson": [
{"label": "订单采购", "value": "1"},
{"label": "批量采购", "value": "2"}
]
}
}
props / jdbcType
| 配置 | 说明 |
|---|---|
props.placeholder |
值为空时展示的占位文字 |
props.description |
字段下方的说明文字 |
jdbcType: "DATETIME" |
配合后端返回的日期值自动格式化展示 |
initData.dataJson |
有字典值时按 value/label 展示对应文字 |
select 组件
下拉单选。initData 支持三种数据来源,按需选择。
1. dataJson 内联枚举
{
"item_name": "STATUS",
"label": "状态",
"component": "select",
"classAppend": "layui-col-md4",
"initData": {
"dataJson": [
{"value": 1, "label": "启用"},
{"value": 0, "label": "禁用"}
]
}
}
2. dataJson 引用外部文件
{
"item_name": "CHECK_STATUS",
"component": "select",
"initData": {
"dataJson": "@import(checkstatus.json)"
}
}
@import(checkstatus.json) 会去同目录下找 checkstatus.json,内容就是一个 [{"value":...,"label":...}] 数组。
3. dataSql 动态查询
{
"item_name": "BRAND_ID",
"label": "品牌",
"component": "select",
"classAppend": "layui-col-md12",
"initData": {
"dataSql": "select brand_id value,brand_name label from T_BASE_BRAND WHERE COMPANY_ID=${COMPANY_ID} and DELETE_FLAG=0",
"dataSource": "datasource"
}
}
SQL 结果集必须包含 value、label 两列(列名固定,大小写不敏感)。
dataSql 里过滤条件别忘了 DELETE_FLAG=0 和 COMPANY_ID=${COMPANY_ID}(多租户隔离)。需要多选时不要用 select + multiple,用专门的 select-multiple 组件。
select-span 组件
只读展示枚举值对应的文字,不可编辑。和 select 的 initData 语法完全一致,区别只是渲染为纯文本而不是下拉框。
1. dataJson 静态枚举
{
"item_name": "EXPIRY_STATUS",
"label": "到期状态",
"component": "select-span",
"classAppend": "layui-col-md6",
"initData": {
"dataJson": [
{"value": "VALID", "label": "有效"},
{"value": "EXPIRING", "label": "即将到期"},
{"value": "EXPIRED", "label": "已过期"},
{"value": "UNKNOWN", "label": "未维护有效期"}
]
}
}
2. dataSql 动态查询
{
"item_name": "TRADER_ID",
"label": "客户名称",
"component": "select-span",
"classAppend": "layui-col-md12",
"initData": {
"dataSql": "SELECT TRADER_ID value,TRADER_NAME label FROM T_BASE_TRADER WHERE TRADER_ID=${TRADER_ID} AND COMPANY_ID=${COMPANY_ID}",
"dataSource": "dataSource"
}
}
select-span。纯文本、说明、自动生成提示用 span。
select-multiple 组件(别名 xmselect)
多选下拉。项目里 select-multiple 和 xmselect 是同一个组件的两种命名,写法完全一致。
1. 远程搜索多选
{
"item_name": "PROD_ID",
"label": "产品名称",
"component": "select-multiple",
"classAppend": "layui-col-md12",
"props": {
"remoteSearch": true,
"toolbar": {
"show": true,
"list": ["ALL", "REVERSE", "CLEAR"]
}
},
"initData": {
"dataUrl": "/jxc/product/search.html"
}
}
2. 限制为单选
{
"item_name": "MANUFACTURER_ID",
"label": "生产厂家",
"component": "xmselect",
"classAppend": "layui-col-md12",
"props": {
"max": 1,
"remoteSearch": true,
"required": true,
"validate": {
"rule": {"required": true},
"message": {"required": "请选择生产厂家"}
}
},
"initData": {
"dataUrl": "/jxc/manufacturer/search.html"
}
}
props
| 配置 | 说明 |
|---|---|
remoteSearch |
是否启用远程搜索 |
max |
最多可选数量,1 即"单选" |
toolbar.show + toolbar.list |
是否显示全选/反选/清空工具条 |
select + dataSql 一次性查全表,改用远程搜索。max:1 时提交的值仍然是数组/逗号分隔的形式。
pop-list-select 组件
用于表单字段需要打开列表页选择一行或多行,并把选中行 ID 保存到隐藏字段的场景。
基本配置
{
"item_name": "MANUFACTURER_ID",
"label": "生产厂家",
"component": "pop-list-select",
"classAppend": "layui-col-md12",
"props": {
"url": "list/page-med/manufacturer-select",
"idField": "ID",
"multiple": true,
"displayFields": "MANUFACTURER_NAME,MANUFACTURER_NAME_EN",
"title": "请选择生产厂家",
"width": "900px",
"height": "620px",
"description": "可选择多个生产厂家"
}
}
props
| 配置 | 必填 | 说明 |
|---|---|---|
url / pageUrl |
是 | 弹框打开的列表页 URL |
initUrl / dataUrl |
否 | 初始化回显数据接口 |
idField |
否 | 唯一字段,默认 ID |
multiple |
否 | 是否多选,默认 true |
displayFields |
否 | 回显表格展示字段,英文逗号分隔 |
title |
否 | 弹框标题 |
width / height |
否 | 弹框尺寸 |
description |
否 | 按钮下方辅助说明 |
实例与外部 API
// 初始化页面上所有 pop-list-select
window.EZ_POP_LIST_SELECT.init();
// 只初始化某一个 item_name
window.EZ_POP_LIST_SELECT.init('MANUFACTURER_ID');
// 根据当前 hidden input 的 value 调初始化接口并渲染回显 table
window.EZ_POP_LIST_SELECT.initFromInputValue('MANUFACTURER_ID');
// 外部直接设置某个组件值,并触发初始化回显
window.EZ_POP_LIST_SELECT.setValue('MANUFACTURER_ID', '7994');
// 清空某个组件
window.EZ_POP_LIST_SELECT.clear('MANUFACTURER_ID');
window.EZ_INPUT_POP_SELECT(该名字已废弃,2026-07-09 起统一改为 pop-list-select/EZ_POP_LIST_SELECT)。
cascader 组件
级联选择,用于分类树、地区树等有父子层级的数据。
基本配置
{
"item_name": "CATEGORY_ID",
"label": "分类",
"component": "cascader",
"classAppend": "layui-col-md12",
"jdbcType": "NUMBER",
"initData": {
"dataSql": "select PARENT_ID parent_id,category_id value,category_id ID,category_name label from T_BASE_CATEGORY WHERE COMPANY_ID=${COMPANY_ID} and DELETE_FLAG=0",
"dataSource": "datasource"
}
}
dataSql 列名要求
| 列名 | 说明 |
|---|---|
value |
节点值,保存到表单字段 |
parent_id |
父节点值,0/NULL/根值表示顶层节点 |
label |
节点展示文字 |
checkStrictly 配置
{
"item_name": "REGION_ID",
"label": "地区",
"component": "cascader",
"classAppend": "layui-col-md12",
"initData": {
"dataSql": "SELECT A.REGION_FULL_ID value, A.PARENT_ID parent_id, A.REGION_FULL_NAME label FROM T_BASE_REGION A where delete_flag=0 AND PARENT_ID>=0",
"dataSource": "datasource"
},
"props": {
"props": {
"checkStrictly": false
}
}
}
注意这里是 props.props.checkStrictly(嵌套两层)。checkStrictly: false(默认)要求必须选到叶子节点;设为 true 允许选中任意层级的节点。
parent_id 字段名必须小写,value/label 同理。外键字段是数字类型时建议加 "jdbcType": "NUMBER"。
radio 组件
单选框。
基本配置
{
"item_name": "STATUS",
"label": "状态",
"component": "radio",
"classAppend": "layui-col-md12",
"initValue": 1,
"initData": {
"dataJson": [
{"value": 1, "label": "启用"},
{"value": 0, "label": "禁用"}
]
}
}
默认值两种写法
- 字段级
initValue(如上例)——新建表单时该字段的默认选中值。 props.defaultValue(字符串形式):
{
"item_name": "TYPE",
"component": "radio",
"props": {"defaultValue": "1"},
"initData": {"dataJson": [{"value": "1", "label": "普通"}, {"value": "2", "label": "特殊"}]}
}
新文件优先用 initValue,跟同模块已有文件保持一致即可。
dataJson 静态枚举,不支持 dataSql/dataUrl。
checkbox 组件
复选框,支持多选。当前项目里没有找到真实用例,以下写法基于 radio 的语法类推。
基本配置(类推写法)
{
"item_name": "TAGS",
"label": "标签",
"component": "checkbox",
"classAppend": "layui-col-md12",
"initData": {
"dataJson": [
{"value": "A", "label": "标签A"},
{"value": "B", "label": "标签B"}
]
}
}
数据格式
提交值预期为逗号分隔字符串(如 "A,B"),与多选的 pop-list-select、select-multiple 提交格式一致。
radio 而不是单个 checkbox。真正需要多选的场景,先看是否更适合用 select-multiple。
date 组件(表单字段)
表单里的日期选择字段。
基本配置
{
"item_name": "BC_ISSUE_DATE",
"label": "营业执照发证日期",
"component": "date",
"classAppend": "layui-col-md4",
"jdbcType": "DATE",
"props": {
"format": "yyyy-MM-dd"
}
}
带必填校验
{
"item_name": "ISSUING_DATE",
"label": "批准日期",
"component": "date",
"classAppend": "layui-col-md4",
"jdbcType": "DATE",
"props": {
"format": "yyyy-MM-dd",
"required": true,
"validate": {
"rule": {"required": true},
"message": {"required": "请选择批准日期"}
}
}
}
props
| 配置 | 说明 |
|---|---|
format |
日期格式,项目里统一用 yyyy-MM-dd |
required + validate.rule.required |
新式必填写法 |
表单默认当天
新增表单里的日期字段如果需要默认当天,优先在打开表单的新增 URL 里传框架内置参数:
"url": "form/page-finance/finance-arap-flow?FINANCE_BILL_ID=${ID}&TRADER_TIME=EZ_TODAY_DATE_NORMAL"
只给新增入口加默认参数;编辑入口带 ID 时不要加。
List 搜索与 Form 字段
List 搜索项使用 component: "date" 时,默认生成日期范围。Form 日期字段保持单日期,不要自动添加 range: true。
upload 组件
文件/图片上传。
图片上传
{
"item_name": "PROD_PIC_IDS",
"label": "图片",
"component": "upload",
"classAppend": "layui-col-md12",
"props": {
"accept": "images",
"multiple": true,
"size": 2048,
"number": 5,
"description": "支持jpg、png格式,最多上传5张图片,每张大小不超过2MB"
}
}
文件上传(带数量上限校验)
{
"item_name": "FILE_OSS_ID",
"label": "资质附件",
"component": "upload",
"classAppend": "layui-col-md12",
"props": {
"description": "允许 JPG、JPEG、PNG、BMP、PDF,最多上传1个文件",
"multiple": false,
"required": false,
"number": 1,
"accept": "file",
"validate": {
"rule": {"uploadMax": 1},
"message": {"uploadMax": "最多上传1个文件"}
}
}
}
props 全量字段
| 配置 | 取值 | 说明 |
|---|---|---|
accept |
"images" / "file" |
限制文件类型大类 |
multiple |
true / false |
是否允许多文件上传 |
number |
整数 | 最多上传文件数 |
size |
整数(KB) | 单文件大小上限 |
description |
字符串 | 按钮下方的说明文字 |
validate.rule.uploadMax |
整数 | 自定义校验:限制最多上传N个文件 |
number 只是前端组件层面的数量提示/限制,真正阻止超量提交要配 validate.rule.uploadMax,两者建议同时配置且取值一致。
tinymce 组件
富文本编辑器,用于正文类长文本(如文章内容),保存 HTML 字符串。
基本配置
{
"item_name": "BLOG_CONTENT",
"label": "内容",
"component": "tinymce",
"classAppend": "layui-col-md12"
}
- 一律用
layui-col-md12占满整行,富文本编辑器需要足够宽度。 - 保存到数据库的是完整 HTML 字符串,
submitExpress里作为普通文本字段处理(#{FIELD})。 - 展示时如果要在列表里预览,注意富文本内容长度可能很长,list 的
column一般不直接展示这个字段。
iframe 子表 Card
用于表单中内嵌子列表或子页面。父表单主键为空时,必须使用 iframe.params 做结构化参数和空值拦截。
推荐配置
{
"type": "iframe",
"item_name": "brandManufacturerList",
"label": "关联生产厂家",
"iframe": {
"url": "list/page-product/base-brand-manufacturer-list",
"height": "326px",
"params": {
"BRAND_ID": "${ID}"
},
"emptyText": "请先保存品牌,再维护关联生产厂家"
},
"buttonList": []
}
iframe 配置项
| 配置 | 必填 | 说明 |
|---|---|---|
url |
是 | iframe 基础 URL |
params |
否 | 结构化查询参数,值支持 ${ID} 等占位符 |
height |
否 | iframe 高度 |
width |
否 | iframe 宽度 |
emptyText |
否 | 任意 params 解析为空时展示的提示 |
行为规则
- 渲染前先解析
iframe.params中的占位符。 - 任意参数解析后为空字符串、
null或缺失时,不渲染 iframesrc。 - 不渲染
src时展示emptyText,避免新增页${ID}为空导致子列表 HTTP 400。 item_name用于定向刷新,例如successUrl: "refreshcard.brandManufacturerList"。
props.display 可以叠加使用
{
"type": "iframe",
"item_name": "suppliercert",
"label": "资质台账",
"iframe": {
"url": "list/page-supplier/supplier-cert-list",
"height": "326px",
"params": {"SUPPLIER_ID": "${ID}"},
"emptyText": "请先保存供应商,再维护资质台账"
},
"buttonList": [],
"props": {
"display": "{{ if(!'${ID}'){ }} none {{ } else { }} {{ } }}"
}
}
列表组件
列表侧渲染/操作用的是另一套 component,不要跟表单字段组件混用。
列渲染组件(column)
list JSON 的 column 数组里,每个字段用 component 指定渲染方式。
tdText(默认文本)
{"item_name": "PROD_CODE", "label": "编码", "component": "tdText"}
带日期格式化:
{"item_name": "ADD_TIME", "label": "录入时间", "jdbcType": "DATETIME", "component": "tdText",
"props": {"format": "yyyy-MM-dd HH:mm:ss", "width": 175}}
jdbcType 取值:DATE、DATETIME、NUMBER(数字千分位/右对齐)。
tdLink(可点击链接)
{"item_name": "PROD_CODE", "label": "编码", "component": "tdLink",
"props": {"url": "form/page-product/base-product?ID={{= d.ID}}", "opentype": "FORM",
"windowname": "编辑", "width": 110}}
tdSelect(枚举值显示)
// dataJson 内联
{"item_name": "QUALITY_STATUS", "label": "质量状态", "component": "tdSelect",
"initData": {"dataJson": [{"value":"PASS","label":"通过"},{"value":"WARN","label":"预警"}]}}
// dataJson 引用外部文件
{"item_name": "CHECK_STATUS", "label": "审核状态", "component": "tdSelect",
"initData": {"dataJson": "@import(checkstatus.json)"}}
// dataSql 动态查询
{"item_name": "ADD_ID", "label": "添加人", "component": "tdSelect",
"initData": {"dataSql": "SELECT USER_ID value, USER_NAME label FROM T_SYS_USER WHERE COMPANY_ID=${COMPANY_ID}",
"dataSource": "dataSource"}, "props": {"width": 100}}
tdSelectMultiple(多选值显示)
用法同 tdSelect,值为逗号分隔的多个 value,按 initData 映射逐个展示成多个标签。
tdCascader(级联路径显示)
{"item_name": "CATEGORY_ID", "label": "分类", "component": "tdCascader",
"initData": {
"dataSql": "select PARENT_ID parent_id,category_id value,category_id id,category_name label from T_BASE_CATEGORY WHERE COMPANY_ID=${COMPANY_ID} and DELETE_FLAG=0",
"dataSource": "datasource"}}
tdPic(图片)
{"item_name": "LOGO", "label": "公司logo", "component": "tdPic"}
固定尺寸:
{"item_name": "PROD_PIC_IDS", "label": "图片", "component": "tdPic",
"props": {"width": 85, "minWidth": 85}}
prodInfo、numberInfo 等自定义 component,这些是项目自行扩展的前端渲染器,不是框架内置组件。新模块生成 DSL 时不要照抄这些名字。
父子关系(父表单 iframe 嵌套子列表)
适用场景
父记录与子记录是一对多关系,子记录需要独立新增/编辑/删除(不随父表单一次性提交)。典型例子:供应商-资质台账、客户资质-经营范围、注册证-关联厂家、订单-商品。
总体文件结构
form/{模块}/
{父功能}.json ← 父表单,含 iframe card
{子功能}.json ← 子表单(新增/编辑子记录)
{子功能}_initExpress.ql
{子功能}_submitExpress.ql
{子功能}_deleteExpress.ql
list/{模块}/
{子功能}-list.json ← 子列表(嵌在 iframe 里)
{子功能}-list_express_main.ql
1. 父表单 — iframe card
{
"type": "iframe",
"item_name": "suppliercert",
"label": "资质台账",
"iframe": {
"url": "list/page-supplier/supplier-cert-list",
"height": "326px",
"params": {"SUPPLIER_ID": "${ID}"},
"emptyText": "请先保存供应商,再维护资质台账"
},
"buttonList": [],
"props": {
"display": "{{ if(!'${ID}'){ }} none {{ } else { }} {{ } }}"
}
}
2. 子列表 DSL
{
"id": "registration-manufacturer-list",
"name": "关联厂家列表",
"dataSource": "dataSource",
"hideSearch": true,
"body": { "emptyShow": "-", "showIndex": true, "selectable": false, "rowActionWidth": 175 },
"tabList": [], "search": [],
"column": [
{"item_name": "MANUFACTURER_NAME", "label": "厂家名称", "component": "tdText"},
{"item_name": "PRODUCTION_TYPE", "label": "生产类型", "component": "tdSelect",
"initData": {"dataJson": [{"value": 0, "label": "自行生产"}, {"value": 1, "label": "委托生产"}]}}
],
"tableButton": [
{"item_name": "新增", "label": "新增", "component": "button-table",
"props": {
"url": "form/page-med/registration-manufacturer?REGISTRATION_ID=${REGISTRATION_ID}",
"opentype": "parent.MODAL",
"windowname": "新增关联厂家"
}}
],
"rowButton": [
{"item_name": "编辑", "label": "编辑", "component": "button-single",
"classAppend": "layui-border-blue",
"props": {
"url": "form/page-med/registration-manufacturer?ID={{= d.ID}}®ISTRATION_ID={{= d.REGISTRATION_ID}}",
"opentype": "parent.MODAL",
"windowname": "编辑关联厂家"
}},
{"item_name": "删除", "label": "删除", "component": "button-single",
"classAppend": "layui-border-red",
"props": {
"url": "form/delete-med/registration-manufacturer?ID={{= d.ID}}",
"opentype": "script",
"windowname": "删除"
}}
],
"express": {
"main": "@import(registration-manufacturer-list_express_main.ql)",
"orderBy": [], "groupBy": []
},
"appendHead": "", "appendFoot": ""
}
3. 子列表 express
companyId = $$("COMPANY_ID");
StringBuilder sql = new StringBuilder();
sql.append("SELECT R.ID, R.REGISTRATION_ID, R.MANUFACTURER_ID, R.PRODUCTION_TYPE, M.MANUFACTURER_NAME ");
sql.append("FROM T_MED_REGISTRATION_MANUFACTURER R ");
sql.append("LEFT JOIN T_MED_MANUFACTURER M ON R.MANUFACTURER_ID = M.MANUFACTURER_ID ");
sql.append("WHERE R.DELETE_FLAG=0 AND R.REGISTRATION_ID=${REGISTRATION_ID} ");
sql.append("AND R.COMPANY_ID=").append(companyId);
return search(sql);
4. 子表单 form DSL
{
"id": "registration-manufacturer",
"name": "关联厂家",
"dataSource": "dataSource",
"successUrl": "parent.refreshcard.registrationManufacturerList",
"cardList": [{
"type": "card", "label": "关联厂家信息",
"fieldList": [
{"row": [
{"item_name": "ID", "label": "ID", "component": "hidden", "classAppend": "layui-col-md0"},
{"item_name": "REGISTRATION_ID", "label": "注册证ID", "component": "hidden", "classAppend": "layui-col-md0"}
]},
{"row": [
{"item_name": "MANUFACTURER_ID", "label": "厂家", "component": "xmselect",
"classAppend": "layui-col-md12",
"props": {"max": 1, "remoteSearch": true, "required": true,
"validate": {"rule": {"required": true}, "message": {"required": "请选择厂家"}}},
"initData": {"dataUrl": "/jxc/manufacturer/search.html"}}
]},
{"row": [
{"item_name": "PRODUCTION_TYPE", "label": "生产类型", "component": "select",
"classAppend": "layui-col-md12",
"initData": {"dataJson": [{"value": "0", "label": "自行生产"}, {"value": "1", "label": "委托生产"}]},
"props": {"lay-verify": "required"}}
]}
],
"buttonList": []
}],
"buttonList": [],
"initExpress": "@import(registration-manufacturer_initExpress.ql)",
"submitExpress": "@import(registration-manufacturer_submitExpress.ql)",
"deleteExpress": "@import(registration-manufacturer_deleteExpress.ql)",
"statusExpress": [], "appendHead": "", "appendFoot": ""
}
5. 子表单 initExpress
companyId = $$("COMPANY_ID");
if (!isNotBlank("ID")) {
// 新增:从 URL 参数取父 ID 回填 hidden 域
resp = new HashMap();
resp.put("REGISTRATION_ID", $("REGISTRATION_ID"));
resp.put("PRODUCTION_TYPE", "0"); // 默认值
return resp;
}
// 编辑:按子表主键查询
resp = selectOne("SELECT R.ID, R.REGISTRATION_ID, R.MANUFACTURER_ID, R.PRODUCTION_TYPE "
+ "FROM T_MED_REGISTRATION_MANUFACTURER R "
+ "WHERE R.DELETE_FLAG=0 AND R.ID=#{ID} AND R.COMPANY_ID=" + companyId);
return resp;