build(deps): 升级 MyBatis Plus 并适配新版 API

(cherry picked from commit 290764e739fa093eb8187ecd0f9a30062af95f8e)
This commit is contained in:
PIGCLOUD committed 2026-11-04 21:01:49 +08:00
1 parent 8d37e48d1f
commit 467a1fea1b
197 files changed
+264 -223

No files matched your search

+13 -13
View File
@@ -237,9 +237,9 @@ CREATE TABLE `gen_template` (
-- ----------------------------
BEGIN;
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (1,'ControllerV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/controller/${ClassName}Controller.java','ControllerV202611','## 查询条件按需导入:字符串字段和组织关键字用 StrUtil,其余类型用 Objects;复选框与日期范围两者都不用\n#set($needStrUtil = false)\n#set($needObjects = false)\n#foreach($field in $queryList)\n#if($field.formType == \'checkbox\' || $field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#elseif($field.formType.startsWith(\'org-\') || $field.attrType == \'String\')\n#set($needStrUtil = true)\n#else\n#set($needObjects = true)\n#end\n#end\n#set($hasOrgQuery = false)\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrgQuery = true)\n#end\n#end\n## 组织字段以 [{id,name}] JSON 存储,按 ${attrName}Keyword 对整列模糊查询,分页和导出共用\n#macro(orgKeywordParams)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), @RequestParam(required = false) String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordDecl)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordArgs)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordFilters)\n#if($hasOrgQuery)\n // 组织字段对整列 JSON 做 LIKE:关键字为数字或 id/name 时会误命中,需精确匹配时改用数据库 JSON 函数\n#end\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n wrapper.like(StrUtil.isNotBlank(${field.attrName}Keyword), ${ClassName}Entity::$str.getProperty($field.attrName), ${field.attrName}Keyword);\n#end\n#end\n#end\n#set($permissionPrefix = \"${moduleName}_${functionName}\")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\npackage ${package}.${moduleName}.controller;\n\n#if($needStrUtil)\nimport cn.hutool.core.util.StrUtil;\n#end\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.collection.CollUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport ${package}.common.core.util.R;\nimport ${package}.common.log.annotation.SysLog;\n#if($opensource)\nimport com.pig4cloud.plugin.excel.annotation.ResponseExcel;\nimport com.pig4cloud.plugin.excel.annotation.RequestExcel;\n#else\nimport ${package}.common.excel.annotation.ResponseExcel;\nimport ${package}.common.excel.annotation.RequestExcel;\n#end\nimport ${entityClassName};\nimport ${package}.${moduleName}.service.${ClassName}Service;\n\nimport io.swagger.v3.oas.annotations.security.SecurityRequirement;\n#if($isSpringBoot3)\nimport ${package}.common.security.annotation.HasPermission;\nimport org.springdoc.core.annotations.ParameterObject;\n#else\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springdoc.api.annotations.ParameterObject;\n#end\nimport org.springframework.http.HttpHeaders;\nimport io.swagger.v3.oas.annotations.tags.Tag;\nimport io.swagger.v3.oas.annotations.Operation;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n#if($needObjects)\nimport java.util.Objects;\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@RestController\n@RequiredArgsConstructor\n@RequestMapping(\"/${functionName}\" )\n@Tag(description = \"${functionName}\" , name = \"${tableComment}管理\" )\n@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)\npublic class ${ClassName}Controller {\n\n private final ${ClassName}Service ${className}Service;\n\n /**\n * 分页查询\n * @param page 分页对象\n * @param ${className} ${tableComment}\n * @return\n */\n @Operation(summary = \"分页查询\" , description = \"分页查询\" )\n @GetMapping(\"/page\" )\n #if($isSpringBoot3)\n @HasPermission(\"${permissionPrefix}_view\")\n #else\n @PreAuthorize(\"@pms.hasPermission(\'${permissionPrefix}_view\')\" )\n #end\n public R get${ClassName}Page(@ParameterObject Page page, @ParameterObject ${ClassName}Entity ${className}#orgKeywordParams()) {\n return R.ok(${className}Service.page(page, buildQueryWrapper(${className}#orgKeywordArgs())));\n }\n\n /**\n * 列表与导出共用的查询条件,保证导出结果与列表一致\n */\n private LambdaQueryWrapper<${ClassName}Entity> buildQueryWrapper(${ClassName}Entity ${className}#orgKeywordDecl()) {\n LambdaQueryWrapper<${ClassName}Entity> wrapper = Wrappers.lambdaLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (2,'ServiceV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/${ClassName}Service.java','ServiceV202611','package ${package}.${moduleName}.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport ${entityClassName};\n\npublic interface ${ClassName}Service extends IService<${ClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (3,'ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','ServiceImplV202611','package ${package}.${moduleName}.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport org.springframework.stereotype.Service;\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Service\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (4,'实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport java.util.List;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = \"${tableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${tableComment}\")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description=\"$comment 查询范围\",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (2,'ServiceV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/${ClassName}Service.java','ServiceV202611','package ${package}.${moduleName}.service;\n\nimport com.baomidou.mybatisplus.spring.service.IService;\nimport ${entityClassName};\n\npublic interface ${ClassName}Service extends IService<${ClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (3,'ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','ServiceImplV202611','package ${package}.${moduleName}.service.impl;\n\nimport com.baomidou.mybatisplus.spring.service.impl.ServiceImpl;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport org.springframework.stereotype.Service;\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Service\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (4,'实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.spring.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport java.util.List;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = \"${tableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${tableComment}\")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description=\"$comment 查询范围\",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (5,'MapperV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/mapper/${ClassName}Mapper.java','MapperV202611','package ${package}.${moduleName}.mapper;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport ${entityClassName};\nimport org.apache.ibatis.annotations.Mapper;\n\n@Mapper\npublic interface ${ClassName}Mapper extends BaseMapper<${ClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (6,'Mapper.xmlV202611','${backendPath}/src/main/resources/mapper/${ClassName}Mapper.xml','Mapper.xmlV202611','<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"${package}.${moduleName}.mapper.${ClassName}Mapper\">\n\n <resultMap id=\"${className}Map\" type=\"${entityClassName}\">\n#foreach ($field in $fieldList)\n #if($field.primaryPk == \'1\')\n <id property=\"$field.attrName\" column=\"$field.fieldName\"/>\n #else\n <result property=\"$field.attrName\" column=\"$field.fieldName\"#if($field.formType.startsWith(\'org-\')) typeHandler=\"com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler\"#end/>\n #end\n#end\n </resultMap>\n</mapper>\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (7,'权限菜单V202611','${backendPath}/menu/${functionName}_menu.sql','权限菜单V202611','#set($permissionPrefix = \"${moduleName}_${functionName}\")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\n-- 该脚本不要直接执行, 注意维护菜单的父节点ID 默认 父节点-1 , #if(!$opensource)默认租户 1#end\n#set($menuId=${dateTool.getSystemTime()})\n\n-- 菜单SQL\ninsert into sys_menu ( menu_id,parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${menuId}, \'-1\', \'/${moduleName}/${functionName}/index\', \'\', \'0\', \'icon-bangzhushouji\', \'0\', null , \'8\', null , \'${tableComment}管理\'#if(!$opensource), 1#end);\n\n-- 菜单对应按钮SQL\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,1)},${menuId}, \'${permissionPrefix}_view\', \'1\', null, \'1\', \'0\', null, \'0\', null, \'${tableComment}查看\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,2)},${menuId}, \'${permissionPrefix}_add\', \'1\', null, \'1\', \'0\', null, \'1\', null, \'${tableComment}新增\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,3)},${menuId}, \'${permissionPrefix}_edit\', \'1\', null, \'1\', \'0\', null, \'2\', null, \'${tableComment}修改\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,4)},${menuId}, \'${permissionPrefix}_del\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'${tableComment}删除\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,5)},${menuId}, \'${permissionPrefix}_export\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'导入导出\'#if(!$opensource), 1#end);\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
@@ -247,21 +247,21 @@ INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_d
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (9,'表格V202611','${frontendPath}/src/views/${moduleName}/${functionName}/index.vue','表格V202611','## 有字典字段时才导入 useDict\n#set($hasDictField = false)\n#foreach($field in $queryList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n#foreach($field in $gridList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n## 开关:按属性类型决定开/关的值,Boolean 用 true/false,整型用 1/0,其余用 \'1\'/\'0\'\n#macro(switchValues $f)\n#if($f.attrType == \'Boolean\')\n#set($switchOn = \'true\')\n#set($switchOff = \'false\')\n#elseif($f.attrType == \'Integer\' || $f.attrType == \'Long\' || $f.attrType == \'Short\')\n#set($switchOn = \'1\')\n#set($switchOff = \'0\')\n#else\n#set($switchOn = "\'1\'")\n#set($switchOff = "\'0\'")\n#end\n#end\n#set($permissionPrefix = "${moduleName}_${functionName}")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\n<template>\n <div class="layout-padding">\n <div class="layout-padding-auto layout-padding-view">\n#if($queryList)\n <!-- 查询表单区域 -->\n <el-row v-show="showSearch">\n <el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))#set($queryKey = "${field.attrName}Keyword")#else#set($queryKey = $field.attrName)#end\n#if($field.queryFormType == \'select\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-select v-model="state.queryForm.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">\n#if($field.fieldDict)\n <el-option \n :label="item.label" \n :value="item.value" \n v-for="(item, index) in ${field.fieldDict}" \n :key="index"\n />\n#else\n <el-option label="请选择" value="0" />\n#end\n </el-select>\n </el-form-item>\n#elseif($field.queryFormType == \'date\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-date-picker\n type="date"\n placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"\n v-model="state.queryForm.${field.attrName}"\n :value-format="dateStr"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'daterange\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}Range">\n <el-date-picker\n type="daterange"\n range-separator="至"\n start-placeholder="开始日期"\n end-placeholder="结束日期"\n v-model="state.queryForm.${field.attrName}Range"\n :value-format="dateStr"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'datetime\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-date-picker\n type="datetime"\n placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"\n v-model="state.queryForm.${field.attrName}"\n :value-format="dateTimeStr"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'datetimerange\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}Range">\n <el-date-picker\n type="datetimerange"\n range-separator="至"\n start-placeholder="开始时间"\n end-placeholder="结束时间"\n v-model="state.queryForm.${field.attrName}Range"\n :value-format="dateTimeStr"\n />\n </el-form-item>\n#elseif($field.formType == \'radio\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-radio-group v-model="state.queryForm.${field.attrName}">\n#if($field.fieldDict)\n <el-radio \n :label="item.value" \n v-for="(item, index) in ${field.fieldDict}" \n border \n :key="index"\n >\n {{ item.label }}\n </el-radio>\n#else\n <el-radio label="${field.fieldComment}" border>\n ${field.fieldComment}\n </el-radio>\n#end\n </el-rLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (10,'表单V202611','${frontendPath}/src/views/${moduleName}/${functionName}/form.vue','表单V202611','## 有字典字段时才导入 useDict\n#set($hasDictField = false)\n#foreach($field in $formList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n#set($hasDuplicate = false)\n#foreach($field in $formList)\n#if($field.formValidator == \'duplicate\')\n#set($hasDuplicate = true)\n#end\n#end\n## 开关:按属性类型决定开/关的值,Boolean 用 true/false,整型用 1/0,其余用 \'1\'/\'0\'\n#macro(switchValues $f)\n#if($f.attrType == \'Boolean\')\n#set($switchOn = \'true\')\n#set($switchOff = \'false\')\n#elseif($f.attrType == \'Integer\' || $f.attrType == \'Long\' || $f.attrType == \'Short\')\n#set($switchOn = \'1\')\n#set($switchOff = \'0\')\n#else\n#set($switchOn = "\'1\'")\n#set($switchOff = "\'0\'")\n#end\n#end\n#set($hasOrg = false)\n#foreach($field in $formList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\n<template>\n <el-dialog :title="form.${pk.attrName} ? \'编辑\' : \'新增\'" v-model="visible"\n :close-on-click-modal="false" draggable>\n <el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="90px" v-loading="loading">\n <el-row :gutter="24">\n#foreach($field in $formList)\n#if($field.attrName != ${pk.attrName})\n#if($formLayout == 1)\n <el-col :span="24" class="mb20">\n#elseif($formLayout == 2)\n <el-col :span="12" class="mb20">\n#end\n#if($field.formType.startsWith(\'org-\'))\n#set($orgType = $field.formType.replace(\'org-\', \'\').replace(\'-multiple\', \'\'))\n <el-form-item label="${field.fieldComment}" prop="${field.attrName}">\n <OrgSelect v-model="form.${field.attrName}" value-type="item" type="${orgType}" :multiple="#if($field.formType.endsWith(\'-multiple\'))true#else false#end" label="${field.fieldComment}" :disabled="loading" />\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'switch\')\n#switchValues($field)\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-switch :model-value="String(form.${field.attrName}) === String($switchOn)" @change="(checked) => (form.${field.attrName} = checked ? $switchOn : $switchOff)" />\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'text\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'textarea\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-input type="textarea" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'select\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-select v-model="form.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">\n#if($field.fieldDict)\n <el-option :value="item.value" :label="item.label" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>\n#else\n <el-option label="请选择" value="0"></el-option>\n#end\n </el-select>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'radio\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-radio-group v-model="form.${field.attrName}">\n#if($field.fieldDict)\n <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}</el-radio>\n#else\n <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>\n#end\n </el-radio-group>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'checkbox\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-checkbox-group v-model="form.${field.attrName}">\n#if($field.fieldDict)\n <el-checkbox :label="item.value" v-for="(item, index) in ${field.fieldDict}" :key="index">{{ item.label }}</el-checkbox>\n#else\n <el-checkbox label="启用"Line truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (11,'主子ServiceV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/${ClassName}Service.java','主子ServiceV202611','#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPk = $field)\n#end\n#end\npackage ${package}.${moduleName}.service;\n\nimport com.github.yulichang.extension.mapping.base.MPJDeepService;\nimport ${entityClassName};\n\npublic interface ${ClassName}Service extends MPJDeepService<${ClassName}Entity> {\n Boolean saveDeep(${ClassName}Entity ${className});\n\n Boolean updateDeep(${ClassName}Entity ${className});\n\n Boolean removeDeep(${pk.attrType}[] ids);\n\n Boolean removeChild(${childPk.attrType}[] ids);\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (12,'主子ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','主子ServiceImplV202611','#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPk = $field)\n#end\n#end\npackage ${package}.${moduleName}.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport org.springframework.stereotype.Service;\nimport cn.hutool.core.collection.CollUtil;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport ${package}.${moduleName}.mapper.${ChildClassName}Mapper;\nimport org.springframework.transaction.annotation.Transactional;\nimport lombok.RequiredArgsConstructor;\nimport java.util.Objects;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Service\n@RequiredArgsConstructor\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n private final ${ChildClassName}Mapper ${childClassName}Mapper;\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean saveDeep(${ClassName}Entity ${className}) {\n baseMapper.insert(${className});\n for (${ChildClassName}Entity ${childClassName} : ${className}.get${ChildClassName}List()) {\n ${childClassName}.$str.setProperty($childField)(${className}.$str.getProperty($mainField)());\n ${childClassName}Mapper.insert( ${childClassName});\n }\n\n return Boolean.TRUE;\n }\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean updateDeep(${ClassName}Entity ${className}) {\n baseMapper.updateById(${className});\n for (${ChildClassName}Entity ${childClassName} : ${className}.get${ChildClassName}List()) {\n#set($getChildPkName=$str.getProperty(${childPk.attrName}))\n if (Objects.isNull(${childClassName}.$getChildPkName())) {\n ${childClassName}.$str.setProperty($childField)(${className}.$str.getProperty($mainField)());\n ${childClassName}Mapper.insert(${childClassName});\n } else {\n ${childClassName}Mapper.updateById(${childClassName});\n }\n }\n return Boolean.TRUE;\n }\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean removeDeep(${pk.attrType}[] ids) {\n List<${ClassName}Entity> records = baseMapper.selectBatchIds(CollUtil.toList(ids));\n if (CollUtil.isEmpty(records)) {\n return Boolean.TRUE;\n }\n ${childClassName}Mapper.delete(Wrappers.<${ChildClassName}Entity>lambdaQuery()\n .in(${ChildClassName}Entity::$str.getProperty($childField), records.stream()\n .map(${ClassName}Entity::$str.getProperty($mainField)).collect(Collectors.toList())));\n baseMapper.deleteBatchIds(CollUtil.toList(ids));\n return Boolean.TRUE;\n }\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean removeChild(${childPk.attrType}[] ids) {\n ${childClassName}Mapper.deleteBatchIds(CollUtil.toList(ids));\n return Boolean.TRUE;\n }\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (13,'主实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','主实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport com.github.yulichang.annotation.EntityMapping;\nimport java.util.List;\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = \"${tableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${tableComment}\")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n @TableField(typeHandler = JacksonTypeHandler.class)\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description=\"$comment 查询范围\",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n @ExcelIgnore\n @TableField(exist = false)\n @EntityMapping(thisField = \"$mainField\", joinField = \"$childField\")\n private List<${ChildClassName}Entity> ${childClassName}List;\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (12,'主子ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','主子ServiceImplV202611','#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPk = $field)\n#end\n#end\npackage ${package}.${moduleName}.service.impl;\n\nimport com.baomidou.mybatisplus.spring.service.impl.ServiceImpl;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport org.springframework.stereotype.Service;\nimport cn.hutool.core.collection.CollUtil;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport ${package}.${moduleName}.mapper.${ChildClassName}Mapper;\nimport org.springframework.transaction.annotation.Transactional;\nimport lombok.RequiredArgsConstructor;\nimport java.util.Objects;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Service\n@RequiredArgsConstructor\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n private final ${ChildClassName}Mapper ${childClassName}Mapper;\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean saveDeep(${ClassName}Entity ${className}) {\n baseMapper.insert(${className});\n for (${ChildClassName}Entity ${childClassName} : ${className}.get${ChildClassName}List()) {\n ${childClassName}.$str.setProperty($childField)(${className}.$str.getProperty($mainField)());\n ${childClassName}Mapper.insert( ${childClassName});\n }\n\n return Boolean.TRUE;\n }\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean updateDeep(${ClassName}Entity ${className}) {\n baseMapper.updateById(${className});\n for (${ChildClassName}Entity ${childClassName} : ${className}.get${ChildClassName}List()) {\n#set($getChildPkName=$str.getProperty(${childPk.attrName}))\n if (Objects.isNull(${childClassName}.$getChildPkName())) {\n ${childClassName}.$str.setProperty($childField)(${className}.$str.getProperty($mainField)());\n ${childClassName}Mapper.insert(${childClassName});\n } else {\n ${childClassName}Mapper.updateById(${childClassName});\n }\n }\n return Boolean.TRUE;\n }\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean removeDeep(${pk.attrType}[] ids) {\n List<${ClassName}Entity> records = baseMapper.selectBatchIds(CollUtil.toList(ids));\n if (CollUtil.isEmpty(records)) {\n return Boolean.TRUE;\n }\n ${childClassName}Mapper.delete(Wrappers.<${ChildClassName}Entity>lambdaQuery()\n .in(${ChildClassName}Entity::$str.getProperty($childField), records.stream()\n .map(${ClassName}Entity::$str.getProperty($mainField)).collect(Collectors.toList())));\n baseMapper.deleteBatchIds(CollUtil.toList(ids));\n return Boolean.TRUE;\n }\n\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean removeChild(${childPk.attrType}[] ids) {\n ${childClassName}Mapper.deleteBatchIds(CollUtil.toList(ids));\n return Boolean.TRUE;\n }\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (13,'主实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','主实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.spring.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport com.github.yulichang.annotation.EntityMapping;\nimport java.util.List;\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = \"${tableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${tableComment}\")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n @TableField(typeHandler = JacksonTypeHandler.class)\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description=\"$comment 查询范围\",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n @ExcelIgnore\n @TableField(exist = false)\n @EntityMapping(thisField = \"$mainField\", joinField = \"$childField\")\n private List<${ChildClassName}Entity> ${childClassName}List;\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (14,'MapperV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/mapper/${ClassName}Mapper.java','MapperV202611','package ${package}.${moduleName}.mapper;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport ${entityClassName};\nimport org.apache.ibatis.annotations.Mapper;\n\n@Mapper\npublic interface ${ClassName}Mapper extends BaseMapper<${ClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (15,'Mapper.xmlV202611','${backendPath}/src/main/resources/mapper/${ClassName}Mapper.xml','Mapper.xmlV202611','<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"${package}.${moduleName}.mapper.${ClassName}Mapper\">\n\n <resultMap id=\"${className}Map\" type=\"${entityClassName}\">\n#foreach ($field in $fieldList)\n #if($field.primaryPk == \'1\')\n <id property=\"$field.attrName\" column=\"$field.fieldName\"/>\n #else\n <result property=\"$field.attrName\" column=\"$field.fieldName\"#if($field.formType.startsWith(\'org-\')) typeHandler=\"com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler\"#end/>\n #end\n#end\n </resultMap>\n</mapper>\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (16,'权限菜单V202611','${backendPath}/menu/${functionName}_menu.sql','权限菜单V202611','#set($permissionPrefix = \"${moduleName}_${functionName}\")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\n-- 该脚本不要直接执行, 注意维护菜单的父节点ID 默认 父节点-1 , #if(!$opensource)默认租户 1#end\n#set($menuId=${dateTool.getSystemTime()})\n\n-- 菜单SQL\ninsert into sys_menu ( menu_id,parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${menuId}, \'-1\', \'/${moduleName}/${functionName}/index\', \'\', \'0\', \'icon-bangzhushouji\', \'0\', null , \'8\', null , \'${tableComment}管理\'#if(!$opensource), 1#end);\n\n-- 菜单对应按钮SQL\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,1)},${menuId}, \'${permissionPrefix}_view\', \'1\', null, \'1\', \'0\', null, \'0\', null, \'${tableComment}查看\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,2)},${menuId}, \'${permissionPrefix}_add\', \'1\', null, \'1\', \'0\', null, \'1\', null, \'${tableComment}新增\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,3)},${menuId}, \'${permissionPrefix}_edit\', \'1\', null, \'1\', \'0\', null, \'2\', null, \'${tableComment}修改\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,4)},${menuId}, \'${permissionPrefix}_del\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'${tableComment}删除\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,5)},${menuId}, \'${permissionPrefix}_export\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'导入导出\'#if(!$opensource), 1#end);\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (17,'api.tsV202611','${frontendPath}/src/api/${moduleName}/${functionName}.ts','api.tsV202611','import request from \"/@/utils/request\"\n\n// ========== 基础CRUD接口 ==========\n\n/**\n * 分页查询列表数据\n * @param query - 查询参数对象\n * @returns Promise<分页数据>\n */\nexport function fetchList(query?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/page\',\n method: \'get\',\n params: query\n })\n}\n\n/**\n * 新增数据\n * @param obj - 要新增的数据对象\n * @returns Promise<boolean> - 操作结果\n */\nexport function addObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}\',\n method: \'post\',\n data: obj\n })\n}\n\n/**\n * 获取详情数据\n * @param obj - 查询参数对象(包含ID等)\n * @returns Promise<数据详情>\n */\nexport function getObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/details\',\n method: \'get\',\n params: obj\n })\n}\n\n/**\n * 批量删除数据\n * @param ids - 要删除的ID数组\n * @returns Promise<操作结果>\n */\nexport function delObjs(ids?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}\',\n method: \'delete\',\n data: ids\n })\n}\n\n/**\n * 更新数据\n * @param obj - 要更新的数据对象\n * @returns Promise<操作结果>\n */\nexport function putObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}\',\n method: \'put\',\n data: obj\n })\n}\n\n// ========== 工具函数 ==========\n\n/**\n * 验证字段值唯一性\n * @param rule - 验证规则对象\n * @param value - 要验证的值\n * @param callback - 验证回调函数\n * @param isEdit - 是否为编辑模式\n * \n * @example\n * // 在表单验证规则中使用\n * fieldName: [\n * {\n * validator: (rule, value, callback) => {\n * validateExist(rule, value, callback, form.${pk.attrName} !== \'\');\n * },\n * trigger: \'blur\',\n * },\n * ]\n */\nexport function validateExist(rule: any, value: any, callback: any, isEdit: boolean) {\n // 编辑模式下跳过验证\n if (isEdit) {\n return callback();\n }\n\n // 查询是否存在相同值\n getObj({ [rule.field]: value }).then((response) => {\n const result = response.data;\n if (result !== null && result.length > 0) {\n callback(new Error(\'数据已经存在\'));\n } else {\n callback();\n }\n });\n}\n\n#if($ChildClassName)\n// ========== 子表相关接口 ==========\n\n/**\n * 删除子表数据\n * @param ids - 要删除的子表数据ID数组\n * @returns Promise<操作结果>\n */\nexport function delChildObj(ids?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/child\',\n method: \'delete\',\n data: ids\n })\n}\n#end\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (18,'子实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ChildClassName}Entity.java','子实体V202611','#set($hasOrg = false)\n#foreach($field in $childFieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\n#if($isChildTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport java.util.List;\n#end\n#set($childImports = [])\n#foreach($field in $childFieldList)\n#if($field.packageName && !$field.packageName.startsWith(\'java.lang.\') && !$childImports.contains($field.packageName))\n#set($void = $childImports.add($field.packageName))\n#end\n#end\n#foreach($import in $childImports)\nimport $import;\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isChildTenant)\n@TenantTable\n#end\n@TableName(value = \"${childTableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${childTableName}\")\npublic class ${ChildClassName}Entity extends Model<${ChildClassName}Entity> {\n\n#foreach ($field in $childFieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end \n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (18,'子实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ChildClassName}Entity.java','子实体V202611','#set($hasOrg = false)\n#foreach($field in $childFieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.spring.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\n#if($isChildTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport java.util.List;\n#end\n#set($childImports = [])\n#foreach($field in $childFieldList)\n#if($field.packageName && !$field.packageName.startsWith(\'java.lang.\') && !$childImports.contains($field.packageName))\n#set($void = $childImports.add($field.packageName))\n#end\n#end\n#foreach($import in $childImports)\nimport $import;\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isChildTenant)\n@TenantTable\n#end\n@TableName(value = \"${childTableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${childTableName}\")\npublic class ${ChildClassName}Entity extends Model<${ChildClassName}Entity> {\n\n#foreach ($field in $childFieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end \n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (19,'主子ControllerV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/controller/${ClassName}Controller.java','主子ControllerV202611','## 查询条件按需导入:字符串字段和组织关键字用 StrUtil,其余类型用 Objects;复选框与日期范围两者都不用\n#set($needStrUtil = false)\n#set($needObjects = false)\n#foreach($field in $queryList)\n#if($field.formType == \'checkbox\' || $field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#elseif($field.formType.startsWith(\'org-\') || $field.attrType == \'String\')\n#set($needStrUtil = true)\n#else\n#set($needObjects = true)\n#end\n#end\n#set($hasOrgQuery = false)\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrgQuery = true)\n#end\n#end\n## 组织字段以 [{id,name}] JSON 存储,按 ${attrName}Keyword 对整列模糊查询,分页和导出共用\n#macro(orgKeywordParams)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), @RequestParam(required = false) String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordDecl)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordArgs)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordFilters)\n#if($hasOrgQuery)\n // 组织字段对整列 JSON 做 LIKE:关键字为数字或 id/name 时会误命中,需精确匹配时改用数据库 JSON 函数\n#end\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n wrapper.like(StrUtil.isNotBlank(${field.attrName}Keyword), ${ClassName}Entity::$str.getProperty($field.attrName), ${field.attrName}Keyword);\n#end\n#end\n#end\n#set($permissionPrefix = \"${moduleName}_${functionName}\")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\n#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPk = $field)\n#end\n#end\npackage ${package}.${moduleName}.controller;\n\n#if($needStrUtil)\nimport cn.hutool.core.util.StrUtil;\n#end\nimport cn.hutool.core.util.ArrayUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport ${package}.common.core.util.R;\nimport ${package}.common.log.annotation.SysLog;\n#if($opensource)\nimport com.pig4cloud.plugin.excel.annotation.ResponseExcel;\nimport com.pig4cloud.plugin.excel.annotation.RequestExcel;\n#else\nimport ${package}.common.excel.annotation.ResponseExcel;\nimport ${package}.common.excel.annotation.RequestExcel;\n#end\nimport ${entityClassName};\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport io.swagger.v3.oas.annotations.security.SecurityRequirement;\n#if($isSpringBoot3)\nimport ${package}.common.security.annotation.HasPermission;\nimport org.springdoc.core.annotations.ParameterObject;\n#else\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springdoc.api.annotations.ParameterObject;\n#end\nimport org.springframework.http.HttpHeaders;\nimport io.swagger.v3.oas.annotations.tags.Tag;\nimport io.swagger.v3.oas.annotations.Operation;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n#if($needObjects)\nimport java.util.Objects;\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@RestController\n@RequiredArgsConstructor\n@RequestMapping(\"/${functionName}\" )\n@Tag(description = \"${functionName}\" , name = \"${tableComment}管理\" )\n@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)\npublic class ${ClassName}Controller {\n\n private final ${ClassName}Service ${className}Service;\n\n /**\n * 分页查询\n * @param page 分页对象\n * @param ${className} ${tableComment}\n * @return\n */\n @Operation(summary = \"分页查询\" , description = \"分页查询\" )\n @GetMapping(\"/page\" )\n #if($isSpringBoot3)\n @HasPermission(\"${permissionPrefix}_view\")\n #else\n @PreAuthorize(\"@pms.hasPermission(\'${permissionPrefix}_view\')\" )\n #end\n public R get${ClassName}Page(@ParameterObject Page page, @ParameterObject ${ClassName}Entity ${className}#orgKeywordParams()) {\n return R.ok(${className}Service.page(page, buildQueryWrapper(${className}#orgKeywordArgs())));\n }\n\n /**\n * 列表与导出共用的查询条件,保证导出结果与列表一致\n */\n private LambdaQueryWrapper<${ClassName}Entity> buildQueryWrapper(${ClassName}Entity ${className}#orgKeywordDecl()) {\Line truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (20,'主子表单V202611','${frontendPath}/src/views/${moduleName}/${functionName}/form.vue','主子表单V202611','## 有字典字段时才导入 useDict\n#set($hasDictField = false)\n#foreach($field in $formList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n#set($hasDuplicate = false)\n#foreach($field in $formList)\n#if($field.formValidator == \'duplicate\')\n#set($hasDuplicate = true)\n#end\n#end\n## 开关:按属性类型决定开/关的值,Boolean 用 true/false,整型用 1/0,其余用 \'1\'/\'0\'\n#macro(switchValues $f)\n#if($f.attrType == \'Boolean\')\n#set($switchOn = \'true\')\n#set($switchOff = \'false\')\n#elseif($f.attrType == \'Integer\' || $f.attrType == \'Long\' || $f.attrType == \'Short\')\n#set($switchOn = \'1\')\n#set($switchOff = \'0\')\n#else\n#set($switchOn = "\'1\'")\n#set($switchOff = "\'0\'")\n#end\n#end\n#set($hasOrg = false)\n#foreach($field in $formList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\n#foreach($field in $childFieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\n<template>\n <el-drawer :title="form.${pk.attrName} ? (detail ? \'详情\' : \'编辑\') : \'添加\'" v-model="visible" size="50%">\n <el-form ref="dataFormRef" :model="form" :rules="dataRules" :disabled="detail" v-loading="loading">\n <el-row :gutter="24">\n#foreach($field in $formList)\n#if($field.attrName != ${pk.attrName})\n#if($formLayout == 1)\n <el-col :span="24" class="mb20">\n#elseif($formLayout == 2)\n <el-col :span="12" class="mb20">\n#end\n#if($field.formType.startsWith(\'org-\'))\n#set($orgType = $field.formType.replace(\'org-\', \'\').replace(\'-multiple\', \'\'))\n <el-form-item label="${field.fieldComment}" prop="${field.attrName}">\n <OrgSelect v-model="form.${field.attrName}" value-type="item" type="${orgType}" :multiple="#if($field.formType.endsWith(\'-multiple\'))true#else false#end" label="${field.fieldComment}" :disabled="loading || detail" />\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'switch\')\n#switchValues($field)\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-switch :model-value="String(form.${field.attrName}) === String($switchOn)" @change="(checked) => (form.${field.attrName} = checked ? $switchOn : $switchOff)" />\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'text\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end" prop="${field.attrName}">\n <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end"/>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'textarea\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end" prop="${field.attrName}">\n <el-input type="textarea" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end"/>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'select\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end" prop="${field.attrName}">\n <el-select v-model="form.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end">\n#if($field.fieldDict)\n <el-option :value="item.value" :label="item.label" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>\n#else\n <el-option label="请选择" value="0"></el-option>\n#end\n </el-select>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'radio\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end" prop="${field.attrName}">\n <el-radio-group v-model="form.${field.attrName}">\n#if($field.fieldDict)\n <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}</el-radio>\n#else\n <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>\n#end\n </el-radio-group>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'checkbox\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.fieldName}#end" prop="${field.attrName}">\n <el-checkbox-group v-model="form.${field.attrName}">\n#if($field.fieldDict)\n <el-checkbox :label="item.value" v-fLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (21,'主子表格V202611','${frontendPath}/src/views/${moduleName}/${functionName}/index.vue','主子表格V202611','## 有字典字段时才导入 useDict\n#set($hasDictField = false)\n#foreach($field in $queryList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n#foreach($field in $gridList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n## 开关:按属性类型决定开/关的值,Boolean 用 true/false,整型用 1/0,其余用 \'1\'/\'0\'\n#macro(switchValues $f)\n#if($f.attrType == \'Boolean\')\n#set($switchOn = \'true\')\n#set($switchOff = \'false\')\n#elseif($f.attrType == \'Integer\' || $f.attrType == \'Long\' || $f.attrType == \'Short\')\n#set($switchOn = \'1\')\n#set($switchOff = \'0\')\n#else\n#set($switchOn = "\'1\'")\n#set($switchOff = "\'0\'")\n#end\n#end\n#set($permissionPrefix = "${moduleName}_${functionName}")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\n<template>\n <div class="layout-padding">\n <div class="layout-padding-auto layout-padding-view">\n#if($queryList)\n <el-row v-show="showSearch">\n <el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))#set($queryKey = "${field.attrName}Keyword")#else#set($queryKey = $field.attrName)#end\n#if($field.queryFormType == \'select\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-select v-model="state.queryForm.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">\n#if($field.fieldDict)\n <el-option \n :label="item.label" \n :value="item.value" \n v-for="(item, index) in ${field.fieldDict}" \n :key="index">\n </el-option>\n#else\n <el-option label="请选择">0</el-option>\n#end\n </el-select>\n </el-form-item>\n#elseif($field.queryFormType == \'date\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-date-picker\n type="date"\n placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"\n :value-format="dateStr"\n v-model="state.queryForm.${field.attrName}"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'daterange\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}Range">\n <el-date-picker\n type="daterange"\n range-separator="至"\n start-placeholder="开始日期"\n end-placeholder="结束日期"\n v-model="state.queryForm.${field.attrName}Range"\n :value-format="dateStr"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'datetime\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-date-picker\n type="datetime"\n placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"\n :value-format="dateTimeStr"\n v-model="state.queryForm.${field.attrName}"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'datetimerange\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}Range">\n <el-date-picker\n type="datetimerange"\n range-separator="至"\n start-placeholder="开始时间"\n end-placeholder="结束时间"\n v-model="state.queryForm.${field.attrName}Range"\n :value-format="dateTimeStr"\n />\n </el-form-item>\n#elseif($field.formType == \'radio\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-radio-group v-model="state.queryForm.${field.attrName}">\n#if($field.fieldDict)\n <el-radio \n :label="item.value" \n v-for="(item, index) in ${field.fieldDict}" \n border \n :key="index">\n {{ item.label }}\n </el-radio>\n#else\n <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>\n#end\n </el-radio-group>\n </el-form-item>\n#else\n <elLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (22,'子MapperV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/mapper/${ChildClassName}Mapper.java','子MapperV202611','package ${package}.${moduleName}.mapper;\n\nimport ${package}.common.data.datascope.PigxBaseMapper;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport org.apache.ibatis.annotations.Mapper;\n\n@Mapper\npublic interface ${ChildClassName}Mapper extends PigxBaseMapper<${ChildClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (23,'树形ControllerV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/controller/${ClassName}Controller.java','树形ControllerV202611','## 查询条件按需导入:字符串字段用 StrUtil,其余类型用 Objects;复选框与日期范围两者都不用\n#set($needStrUtil = false)\n#set($needObjects = false)\n#foreach($field in $queryList)\n#if($field.formType == \'checkbox\' || $field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#elseif($field.formType.startsWith(\'org-\') || $field.attrType == \'String\')\n#set($needStrUtil = true)\n#else\n#set($needObjects = true)\n#end\n#end\n#set($hasOrgQuery = false)\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrgQuery = true)\n#end\n#end\n## 组织字段以 [{id,name}] JSON 存储,按 ${attrName}Keyword 对整列模糊查询,分页和导出共用\n#macro(orgKeywordParams)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), @RequestParam(required = false) String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordDecl)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordArgs)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordFilters)\n#if($hasOrgQuery)\n // 组织字段对整列 JSON 做 LIKE:关键字为数字或 id/name 时会误命中,需精确匹配时改用数据库 JSON 函数\n#end\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n wrapper.like(StrUtil.isNotBlank(${field.attrName}Keyword), ${ClassName}Entity::$str.getProperty($field.attrName), ${field.attrName}Keyword);\n#end\n#end\n#end\npackage ${package}.${moduleName}.controller;\n\n#if($queryList)\n#if($needStrUtil)\nimport cn.hutool.core.util.StrUtil;\n#end\n#end\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.collection.CollUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport ${package}.common.core.util.R;\nimport ${package}.common.log.annotation.SysLog;\n#if($opensource)\nimport com.pig4cloud.plugin.excel.annotation.ResponseExcel;\nimport com.pig4cloud.plugin.excel.annotation.RequestExcel;\n#else\nimport ${package}.common.excel.annotation.ResponseExcel;\nimport ${package}.common.excel.annotation.RequestExcel;\n#end\nimport ${entityClassName};\nimport ${package}.${moduleName}.service.${ClassName}Service;\n\nimport io.swagger.v3.oas.annotations.security.SecurityRequirement;\n#if($isSpringBoot3)\nimport ${package}.common.security.annotation.HasPermission;\nimport org.springdoc.core.annotations.ParameterObject;\n#else\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springdoc.api.annotations.ParameterObject;\n#end\nimport org.springframework.http.HttpHeaders;\nimport io.swagger.v3.oas.annotations.tags.Tag;\nimport io.swagger.v3.oas.annotations.Operation;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n#if($needObjects)\nimport java.util.Objects;\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@RestController\n@RequiredArgsConstructor\n@RequestMapping("/${functionName}" )\n@Tag(description = "${functionName}" , name = "${tableComment}管理" )\n@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)\npublic class ${ClassName}Controller {\n\n private final ${ClassName}Service ${className}Service;\n\n /**\n * 获取树形列表\n * @param ${className} ${tableComment}\n * @return\n */\n @Operation(summary = "获取树形列表" , description = "获取树形列表" )\n @GetMapping("/tree" )\n #if($isSpringBoot3)\n @HasPermission("$str.lowerCase($moduleName)_$str.lowerCase($functionName)_view")\n #else\n @PreAuthorize("@pms.hasPermission(\'$str.lowerCase($moduleName)_$str.lowerCase($functionName)_view\')" )\n #end\n public R get${ClassName}Tree(@ParameterObject ${ClassName}Entity ${className}#orgKeywordParams()) {\n return R.ok(${className}Service.buildTree(buildQueryWrapper(${className}#orgKeywordArgs())));\n }\n\n /**\n * 列表与导出共用的查询条件,保证导出结果与列表一致\n */\n private LambdaQueryWrapper<${ClassName}Entity> buildQueryWrapper(${ClassName}Entity ${className}#orgKeywordDecl()) {\n LambdaQueryWrapper<${ClassName}Entity> wrapper = Wrappers.lambdaQuery();\n#orgKeywordFilters()\n#foreach ($field in $queryList)\n#if(!$field.formType.startsWith(\'org-\'))\n#set($getAttrName=$str.getProperty($field.attLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (24,'树形ServiceV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/${ClassName}Service.java','树形ServiceV202611','package ${package}.${moduleName}.service;\n\nimport cn.hutool.core.lang.tree.Tree;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport ${entityClassName};\n\nimport java.util.List;\n\n/**\n * ${tableComment} Service接口\n *\n * @author ${author}\n * @date ${datetime}\n */\npublic interface ${ClassName}Service extends IService<${ClassName}Entity> {\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n List<Tree<${pk.attrType}>> buildTree(LambdaQueryWrapper<${ClassName}Entity> wrapper);\n\n /**\n * 递归删除节点及其子节点\n * @param ids 要删除的节点ID列表\n * @return 删除结果\n */\n boolean removeBatchByIds(List<${pk.attrType}> ids);\n} ','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (25,'树形ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','树形ServiceImplV202611','## 根节点 ID 按主键类型生成,与 Tree<${pk.attrType}> 类型一致\n#if($pk.attrType == \'Long\')\n#set($treeRootId = \'0L\')\n#elseif($pk.attrType == \'String\')\n#set($treeRootId = \'"0"\')\n#else\n#set($treeRootId = \'0\')\n#end\npackage ${package}.${moduleName}.service.impl;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.lang.tree.Tree;\nimport cn.hutool.core.lang.tree.TreeNode;\nimport cn.hutool.core.lang.tree.TreeUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport jakarta.validation.constraints.NotNull;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\n/**\n * ${tableComment} Service实现类\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Service\n@RequiredArgsConstructor\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n @Override\n public List<Tree<${pk.attrType}>> buildTree(LambdaQueryWrapper<${ClassName}Entity> wrapper) {\n // 查询命中节点,再按层补齐祖先,保留完整树路径\n List<${ClassName}Entity> allList = list(wrapper);\n \n if (CollUtil.isEmpty(allList)) {\n return new ArrayList<>();\n }\n\n Map<${pk.attrType}, ${ClassName}Entity> nodes = new LinkedHashMap<>();\n allList.forEach(entity -> nodes.put(entity.$str.getProperty($pk.attrName)(), entity));\n List<${ClassName}Entity> level = allList;\n while (!level.isEmpty()) {\n List<${pk.attrType}> parentIds = level.stream()\n .map(${ClassName}Entity::$str.getProperty($parentField))\n .filter(id -> id != null && !Objects.equals(id, ${treeRootId}) && !nodes.containsKey(id))\n .distinct()\n .toList();\n if (parentIds.isEmpty()) {\n break;\n }\n level = listByIds(parentIds);\n level.forEach(entity -> nodes.put(entity.$str.getProperty($pk.attrName)(), entity));\n }\n\n // 转换为TreeNode,仅包含命中节点及其祖先\n List<TreeNode<${pk.attrType}>> collect = nodes.values().stream().map(getNodeFunction()).toList();\n\n // 使用TreeUtil构建树形结构,根节点ID为0\n return TreeUtil.build(collect, ${treeRootId});\n }\n\n /**\n * 获取TreeNode转换函数\n * @return TreeNode转换函数\n */\n @NotNull\n private Function<${ClassName}Entity, TreeNode<${pk.attrType}>> getNodeFunction() {\n return entity -> {\n TreeNode<${pk.attrType}> node = new TreeNode<>();\n node.setId(entity.$str.getProperty($pk.attrName)());\n node.setName(entity.$str.getProperty($nameField)());\n node.setParentId(entity.$str.getProperty($parentField)() != null ? entity.$str.getProperty($parentField)() : ${treeRootId});\n\n // 扩展属性\n Map<String, Object> extra = new HashMap<>();\n#foreach($field in $fieldList)\n extra.put(${ClassName}Entity.Fields.${field.attrName}, entity.$str.getProperty($field.attrName)());\n#end\n node.setExtra(extra);\n return node;\n };\n }\n\n /**\n * 递归删除节点及其子节点\n * @param ids 要删除的节点ID列表\n * @return 删除结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public boolean removeBatchByIds(List<${pk.attrType}> ids) {\n if (CollUtil.isEmpty(ids)) {\n return true;\n }\n\n // 获取所有要删除的ID(包括子节点)\n List<${pk.attrType}> allDeleteIds = new ArrayList<>(ids);\n \n for (${pk.attrType} id : ids) {\n List<${pk.attrType}> childIds = getChildIdsRecursive(id);\n allDeleteIds.addAll(childIds);\n }\n\n // 去重\n Line truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (26,'树形实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','树形实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.FieldNameConstants;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport java.util.List;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n@FieldNameConstants\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = "${tableName}"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = "${tableComment}")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description="$comment"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description="$comment 查询范围",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (24,'树形ServiceV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/${ClassName}Service.java','树形ServiceV202611','package ${package}.${moduleName}.service;\n\nimport cn.hutool.core.lang.tree.Tree;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.spring.service.IService;\nimport ${entityClassName};\n\nimport java.util.List;\n\n/**\n * ${tableComment} Service接口\n *\n * @author ${author}\n * @date ${datetime}\n */\npublic interface ${ClassName}Service extends IService<${ClassName}Entity> {\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n List<Tree<${pk.attrType}>> buildTree(LambdaQueryWrapper<${ClassName}Entity> wrapper);\n\n /**\n * 递归删除节点及其子节点\n * @param ids 要删除的节点ID列表\n * @return 删除结果\n */\n boolean removeBatchByIds(List<${pk.attrType}> ids);\n} ','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (25,'树形ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','树形ServiceImplV202611','## 根节点 ID 按主键类型生成,与 Tree<${pk.attrType}> 类型一致\n#if($pk.attrType == \'Long\')\n#set($treeRootId = \'0L\')\n#elseif($pk.attrType == \'String\')\n#set($treeRootId = \'"0"\')\n#else\n#set($treeRootId = \'0\')\n#end\npackage ${package}.${moduleName}.service.impl;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.lang.tree.Tree;\nimport cn.hutool.core.lang.tree.TreeNode;\nimport cn.hutool.core.lang.tree.TreeUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.spring.service.impl.ServiceImpl;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport jakarta.validation.constraints.NotNull;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\n/**\n * ${tableComment} Service实现类\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Service\n@RequiredArgsConstructor\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n @Override\n public List<Tree<${pk.attrType}>> buildTree(LambdaQueryWrapper<${ClassName}Entity> wrapper) {\n // 查询命中节点,再按层补齐祖先,保留完整树路径\n List<${ClassName}Entity> allList = list(wrapper);\n \n if (CollUtil.isEmpty(allList)) {\n return new ArrayList<>();\n }\n\n Map<${pk.attrType}, ${ClassName}Entity> nodes = new LinkedHashMap<>();\n allList.forEach(entity -> nodes.put(entity.$str.getProperty($pk.attrName)(), entity));\n List<${ClassName}Entity> level = allList;\n while (!level.isEmpty()) {\n List<${pk.attrType}> parentIds = level.stream()\n .map(${ClassName}Entity::$str.getProperty($parentField))\n .filter(id -> id != null && !Objects.equals(id, ${treeRootId}) && !nodes.containsKey(id))\n .distinct()\n .toList();\n if (parentIds.isEmpty()) {\n break;\n }\n level = listByIds(parentIds);\n level.forEach(entity -> nodes.put(entity.$str.getProperty($pk.attrName)(), entity));\n }\n\n // 转换为TreeNode,仅包含命中节点及其祖先\n List<TreeNode<${pk.attrType}>> collect = nodes.values().stream().map(getNodeFunction()).toList();\n\n // 使用TreeUtil构建树形结构,根节点ID为0\n return TreeUtil.build(collect, ${treeRootId});\n }\n\n /**\n * 获取TreeNode转换函数\n * @return TreeNode转换函数\n */\n @NotNull\n private Function<${ClassName}Entity, TreeNode<${pk.attrType}>> getNodeFunction() {\n return entity -> {\n TreeNode<${pk.attrType}> node = new TreeNode<>();\n node.setId(entity.$str.getProperty($pk.attrName)());\n node.setName(entity.$str.getProperty($nameField)());\n node.setParentId(entity.$str.getProperty($parentField)() != null ? entity.$str.getProperty($parentField)() : ${treeRootId});\n\n // 扩展属性\n Map<String, Object> extra = new HashMap<>();\n#foreach($field in $fieldList)\n extra.put(${ClassName}Entity.Fields.${field.attrName}, entity.$str.getProperty($field.attrName)());\n#end\n node.setExtra(extra);\n return node;\n };\n }\n\n /**\n * 递归删除节点及其子节点\n * @param ids 要删除的节点ID列表\n * @return 删除结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public boolean removeBatchByIds(List<${pk.attrType}> ids) {\n if (CollUtil.isEmpty(ids)) {\n return true;\n }\n\n // 获取所有要删除的ID(包括子节点)\n List<${pk.attrType}> allDeleteIds = new ArrayList<>(ids);\n \n for (${pk.attrType} id : ids) {\n List<${pk.attrType}> childIds = getChildIdsRecursive(id);\n allDeleteIds.addAll(childIds);\n }\n\n // 去重\n allLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (26,'树形实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','树形实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.spring.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.FieldNameConstants;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport java.util.List;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n@FieldNameConstants\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = "${tableName}"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = "${tableComment}")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description="$comment"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description="$comment 查询范围",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (27,'MapperV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/mapper/${ClassName}Mapper.java','MapperV202611','package ${package}.${moduleName}.mapper;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport ${entityClassName};\nimport org.apache.ibatis.annotations.Mapper;\n\n@Mapper\npublic interface ${ClassName}Mapper extends BaseMapper<${ClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (28,'Mapper.xmlV202611','${backendPath}/src/main/resources/mapper/${ClassName}Mapper.xml','Mapper.xmlV202611','<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"${package}.${moduleName}.mapper.${ClassName}Mapper\">\n\n <resultMap id=\"${className}Map\" type=\"${entityClassName}\">\n#foreach ($field in $fieldList)\n #if($field.primaryPk == \'1\')\n <id property=\"$field.attrName\" column=\"$field.fieldName\"/>\n #else\n <result property=\"$field.attrName\" column=\"$field.fieldName\"#if($field.formType.startsWith(\'org-\')) typeHandler=\"com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler\"#end/>\n #end\n#end\n </resultMap>\n</mapper>\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (29,'权限菜单V202611','${backendPath}/menu/${functionName}_menu.sql','权限菜单V202611','#set($permissionPrefix = \"${moduleName}_${functionName}\")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\n-- 该脚本不要直接执行, 注意维护菜单的父节点ID 默认 父节点-1 , #if(!$opensource)默认租户 1#end\n#set($menuId=${dateTool.getSystemTime()})\n\n-- 菜单SQL\ninsert into sys_menu ( menu_id,parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${menuId}, \'-1\', \'/${moduleName}/${functionName}/index\', \'\', \'0\', \'icon-bangzhushouji\', \'0\', null , \'8\', null , \'${tableComment}管理\'#if(!$opensource), 1#end);\n\n-- 菜单对应按钮SQL\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,1)},${menuId}, \'${permissionPrefix}_view\', \'1\', null, \'1\', \'0\', null, \'0\', null, \'${tableComment}查看\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,2)},${menuId}, \'${permissionPrefix}_add\', \'1\', null, \'1\', \'0\', null, \'1\', null, \'${tableComment}新增\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,3)},${menuId}, \'${permissionPrefix}_edit\', \'1\', null, \'1\', \'0\', null, \'2\', null, \'${tableComment}修改\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,4)},${menuId}, \'${permissionPrefix}_del\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'${tableComment}删除\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,5)},${menuId}, \'${permissionPrefix}_export\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'导入导出\'#if(!$opensource), 1#end);\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
@@ -269,12 +269,12 @@ INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_d
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (31,'树形表格V202611','${frontendPath}/src/views/${moduleName}/${functionName}/index.vue','树形表格V202611','## 有字典字段时才导入 useDict\n#set($hasDictField = false)\n#foreach($field in $queryList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n#foreach($field in $gridList)\n#if($field.fieldDict)\n#set($hasDictField = true)\n#end\n#end\n## 开关:按属性类型决定开/关的值,Boolean 用 true/false,整型用 1/0,其余用 \'1\'/\'0\'\n#macro(switchValues $f)\n#if($f.attrType == \'Boolean\')\n#set($switchOn = \'true\')\n#set($switchOff = \'false\')\n#elseif($f.attrType == \'Integer\' || $f.attrType == \'Long\' || $f.attrType == \'Short\')\n#set($switchOn = \'1\')\n#set($switchOff = \'0\')\n#else\n#set($switchOn = "\'1\'")\n#set($switchOff = "\'0\'")\n#end\n#end\n<template>\n <div class="layout-padding">\n <div class="layout-padding-auto layout-padding-view">\n#if($queryList)\n <!-- 查询表单区域 -->\n <el-row v-show="showSearch">\n <el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))#set($queryKey = "${field.attrName}Keyword")#else#set($queryKey = $field.attrName)#end\n#if($field.queryFormType == \'select\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${queryKey}">\n <el-select v-model="state.queryForm.${queryKey}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">\n#if($field.fieldDict)\n <el-option \n :label="item.label" \n :value="item.value" \n v-for="(item, index) in ${field.fieldDict}" \n :key="index"\n />\n#else\n <el-option label="请选择" value="0" />\n#end\n </el-select>\n </el-form-item>\n#elseif($field.queryFormType == \'date\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${queryKey}">\n <el-date-picker \n type="date" \n placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" \n v-model="state.queryForm.${queryKey}"\n :value-format="dateStr"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'datetime\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${queryKey}">\n <el-date-picker\n type="datetime"\n placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"\n v-model="state.queryForm.${queryKey}"\n :value-format="dateTimeStr"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'daterange\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}Range">\n <el-date-picker\n type="daterange"\n range-separator="至"\n start-placeholder="开始日期"\n end-placeholder="结束日期"\n v-model="state.queryForm.${field.attrName}Range"\n :value-format="dateStr"\n />\n </el-form-item>\n#elseif($field.queryFormType == \'datetimerange\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}Range">\n <el-date-picker\n type="datetimerange"\n range-separator="至"\n start-placeholder="开始时间"\n end-placeholder="结束时间"\n v-model="state.queryForm.${field.attrName}Range"\n :value-format="dateTimeStr"\n />\n </el-form-item>\n#elseif($field.formType == \'radio\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${queryKey}">\n <el-radio-group v-model="state.queryForm.${queryKey}">\n#if($field.fieldDict)\n <el-radio \n :label="item.value" \n v-for="(item, index) in ${field.fieldDict}" \n border \n :key="index"\n >\n {{ item.label }}\n </el-radio>\n#else\n <el-radio label="${field.fieldComment}" border>\n ${field.fieldComment}\n </el-radio>\n#end\n </el-radio-group>\n </el-form-item>\n#else\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#enLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (32,'树形表单V202611','${frontendPath}/src/views/${moduleName}/${functionName}/form.vue','树形表单V202611','#set($hasDuplicate = false)\n#foreach($field in $formList)\n#if($field.formValidator == \'duplicate\')\n#set($hasDuplicate = true)\n#end\n#end\n## 开关:按属性类型决定开/关的值,Boolean 用 true/false,整型用 1/0,其余用 \'1\'/\'0\'\n#macro(switchValues $f)\n#if($f.attrType == \'Boolean\')\n#set($switchOn = \'true\')\n#set($switchOff = \'false\')\n#elseif($f.attrType == \'Integer\' || $f.attrType == \'Long\' || $f.attrType == \'Short\')\n#set($switchOn = \'1\')\n#set($switchOff = \'0\')\n#else\n#set($switchOn = "\'1\'")\n#set($switchOff = "\'0\'")\n#end\n#end\n#set($hasOrg = false)\n#foreach($field in $formList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\n<template>\n <el-dialog :title="form.${pk.attrName} ? \'编辑\' : \'新增\'" v-model="visible"\n :close-on-click-modal="false" draggable>\n <el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">\n <el-row :gutter="24">\n <!-- 父级节点选择 -->\n#if($formLayout == 1)\n <el-col :span="24" class="mb20">\n#elseif($formLayout == 2)\n <el-col :span="12" class="mb20">\n#end\n <el-form-item label="父级节点" prop="${parentField}">\n <el-tree-select\n v-model="form.${parentField}"\n :data="parentNodes"\n :props="treeSelectProps"\n check-strictly\n :render-after-expand="false"\n placeholder="请选择父级节点"\n style="width: 100%"\n clearable\n filterable\n />\n </el-form-item>\n </el-col>\n#foreach($field in $formList)\n#if($field.attrName != ${pk.attrName} && $field.attrName != ${parentField})\n#if($formLayout == 1)\n <el-col :span="24" class="mb20">\n#elseif($formLayout == 2)\n <el-col :span="12" class="mb20">\n#end\n#if($field.formType.startsWith(\'org-\'))\n#set($orgType = $field.formType.replace(\'org-\', \'\').replace(\'-multiple\', \'\'))\n <el-form-item label="${field.fieldComment}" prop="${field.attrName}">\n <OrgSelect v-model="form.${field.attrName}" value-type="item" type="${orgType}" :multiple="#if($field.formType.endsWith(\'-multiple\'))true#else false#end" label="${field.fieldComment}" :disabled="loading" />\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'switch\')\n#switchValues($field)\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-switch :model-value="String(form.${field.attrName}) === String($switchOn)" @change="(checked) => (form.${field.attrName} = checked ? $switchOn : $switchOff)" />\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'text\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'textarea\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-input type="textarea" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'select\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-select v-model="form.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">\n#if($field.fieldDict)\n <el-option :value="item.value" :label="item.label" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>\n#else\n <el-option label="请选择" value="0"></el-option>\n#end\n </el-select>\n </el-form-item>\n </el-col>\n#elseif($field.formType == \'radio\')\n <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">\n <el-radio-group v-model="form.${field.attrName}">\n#if($field.fieldDict)\n <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}</el-radio>\n#else\n <el-radio label="${field.fieldComment}" bordLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (33,'左树右表ControllerV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/controller/${ClassName}Controller.java','左树右表ControllerV202611','## 查询条件按需导入 StrUtil(字符串字段);Objects 用于树节点筛选,始终导入\n#set($needStrUtil = false)\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\') || ($field.formType != \'checkbox\' && $field.queryFormType != \'daterange\' && $field.queryFormType != \'datetimerange\' && $field.attrType == \'String\'))\n#set($needStrUtil = true)\n#end\n#end\n#set($hasOrgQuery = false)\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrgQuery = true)\n#end\n#end\n## 组织字段以 [{id,name}] JSON 存储,按 ${attrName}Keyword 对整列模糊查询,分页和导出共用\n#macro(orgKeywordParams)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), @RequestParam(required = false) String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordDecl)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), String ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordArgs)#foreach($field in $queryList)#if($field.formType.startsWith(\'org-\')), ${field.attrName}Keyword#end#end#end\n#macro(orgKeywordFilters)\n#if($hasOrgQuery)\n // 组织字段对整列 JSON 做 LIKE:关键字为数字或 id/name 时会误命中,需精确匹配时改用数据库 JSON 函数\n#end\n#foreach($field in $queryList)\n#if($field.formType.startsWith(\'org-\'))\n wrapper.like(StrUtil.isNotBlank(${field.attrName}Keyword), ${ClassName}Entity::$str.getProperty($field.attrName), ${field.attrName}Keyword);\n#end\n#end\n#end\npackage ${package}.${moduleName}.controller;\n\n#if($needStrUtil)\nimport cn.hutool.core.util.StrUtil;\n#end\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.collection.CollUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport ${package}.common.core.util.R;\nimport ${package}.common.log.annotation.SysLog;\n#if($opensource)\nimport com.pig4cloud.plugin.excel.annotation.ResponseExcel;\nimport com.pig4cloud.plugin.excel.annotation.RequestExcel;\n#else\nimport ${package}.common.excel.annotation.ResponseExcel;\nimport ${package}.common.excel.annotation.RequestExcel;\n#end\nimport ${entityPackage}.${ChildClassName}Entity;\nimport ${entityClassName};\nimport ${package}.${moduleName}.service.${ClassName}Service;\n\nimport io.swagger.v3.oas.annotations.security.SecurityRequirement;\n#if($isSpringBoot3)\nimport ${package}.common.security.annotation.HasPermission;\nimport org.springdoc.core.annotations.ParameterObject;\n#else\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springdoc.api.annotations.ParameterObject;\n#end\nimport org.springframework.http.HttpHeaders;\nimport io.swagger.v3.oas.annotations.tags.Tag;\nimport io.swagger.v3.oas.annotations.Operation;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPkField = $field)\n#break\n#end\n#end\n#set($childFieldGetter = $str.getProperty($childField))\n@RestController\n@RequiredArgsConstructor\n@RequestMapping("/${functionName}" )\n@Tag(description = "${functionName}" , name = "${tableComment}管理" )\n@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)\npublic class ${ClassName}Controller {\n\n private final ${ClassName}Service ${className}Service;\n\n /**\n * 分页查询\n * @param page 分页对象\n * @param ${className} ${tableComment}\n * @return\n */\n @Operation(summary = "分页查询" , description = "分页查询" )\n @GetMapping("/page" )\n #if($isSpringBoot3)\n @HasPermission("$str.lowerCase($moduleName)_$str.lowerCase($functionName)_view")\n #else\n @PreAuthorize("@pms.hasPermission(\'$str.lowerCase($moduleName)_$str.lowerCase($functionName)_view\')" )\n #end\n public R get${ClassName}Page(@ParameterObject Page page, @ParameterObject ${ClassName}Entity ${className}#orgKeywordParams()) {\n return R.ok(${className}Service.page(page, buildQueryWrapper(${className}#orgKeywordArgs())));\n }\n\n /**\n * 列表与导出共用的查询条件,保证导出结果与列表一致\n */\n private LambdaQueryWrapper<${ClassName}Entity> buildQueryWrapper(${ClassName}Entity ${className}#orgKeywordDecl()) {\n LambLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (34,'左树右表ServiceV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/${ClassName}Service.java','左树右表ServiceV202611','package ${package}.${moduleName}.service;\n\nimport cn.hutool.core.lang.tree.Tree;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport ${entityClassName};\n\nimport java.util.List;\n\n/**\n * ${tableComment} Service接口\n *\n * @author ${author}\n * @date ${datetime}\n */\n#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPkField = $field)\n#break\n#end\n#end\npublic interface ${ClassName}Service extends IService<${ClassName}Entity> {\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n List<Tree<${childPkField.attrType}>> buildTree(LambdaQueryWrapper<${ChildClassName}Entity> wrapper);\n\n /**\n * 获取树节点详情\n * @param ${childClassName} 树节点查询对象\n * @return 树节点详情列表\n */\n List<${ChildClassName}Entity> getTreeDetails(${ChildClassName}Entity ${childClassName});\n\n /**\n * 保存树节点\n * @param ${childClassName} 树节点对象\n * @return 保存结果\n */\n Boolean saveTree(${ChildClassName}Entity ${childClassName});\n\n /**\n * 更新树节点\n * @param ${childClassName} 树节点对象\n * @return 更新结果\n */\n Boolean updateTree(${ChildClassName}Entity ${childClassName});\n\n /**\n * 批量删除树节点\n * @param ids 树节点ID列表\n * @return 删除结果\n */\n Boolean removeTreeByIds(${childPkField.attrType}[] ids);\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (35,'左树右表ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','左树右表ServiceImplV202611','package ${package}.${moduleName}.service.impl;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.lang.tree.Tree;\nimport cn.hutool.core.lang.tree.TreeNode;\nimport cn.hutool.core.lang.tree.TreeUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ChildClassName}Mapper;\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Function;\n\n/**\n * ${tableComment} Service实现类\n *\n * @author ${author}\n * @date ${datetime}\n */\n#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPkField = $field)\n#set($childPkGetter = $str.getProperty($childPkField.attrName))\n#break\n#end\n#end\n#set($parentGetter = $str.getProperty($parentField))\n#set($childFieldGetter = $str.getProperty($childField))\n#if($childPkField.attrType == \'Long\')\n#set($treeRootId = \'0L\')\n#elseif($childPkField.attrType == \'String\')\n#set($treeRootId = \'\"0\"\')\n#else\n#set($treeRootId = \'0\')\n#end\n@Service\n@RequiredArgsConstructor\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n private final ${ChildClassName}Mapper ${childClassName}Mapper;\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n @Override\n public List<Tree<${childPkField.attrType}>> buildTree(LambdaQueryWrapper<${ChildClassName}Entity> wrapper) {\n List<${ChildClassName}Entity> allList = ${childClassName}Mapper.selectList(wrapper);\n\n if (CollUtil.isEmpty(allList)) {\n return new ArrayList<>();\n }\n\n List<TreeNode<${childPkField.attrType}>> collect = allList.stream().map(getNodeFunction()).toList();\n return TreeUtil.build(collect, ${treeRootId});\n }\n\n /**\n * 获取树节点详情\n * @param ${childClassName} 树节点查询对象\n * @return 树节点详情列表\n */\n @Override\n public List<${ChildClassName}Entity> getTreeDetails(${ChildClassName}Entity ${childClassName}) {\n return ${childClassName}Mapper.selectList(Wrappers.query(${childClassName}));\n }\n\n /**\n * 保存树节点\n * @param ${childClassName} 树节点对象\n * @return 保存结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean saveTree(${ChildClassName}Entity ${childClassName}) {\n ${childClassName}.$str.setProperty($parentField)(validateParentRelation(null, ${childClassName}.$str.getProperty($parentField)()));\n return ${childClassName}Mapper.insert(${childClassName}) > 0;\n }\n\n /**\n * 更新树节点\n * @param ${childClassName} 树节点对象\n * @return 更新结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean updateTree(${ChildClassName}Entity ${childClassName}) {\n ${childClassName}.$str.setProperty($parentField)(validateParentRelation(${childClassName}.$str.getProperty($childPkField.attrName)(), ${childClassName}.$str.getProperty($parentField)()));\n return ${childClassName}Mapper.updateById(${childClassName}) > 0;\n }\n\n /**\n * 批量删除树节点\n * @param ids 树节点ID列表\n * @return 删除结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean removeTreeByIds(${childPkField.attrType}[] ids) {\n if (ArrayUtil.isEmpty(ids)) {\n return Boolean.TRUE;\n }\n\n for (${childPkField.attrType} id : ids) {\n if (hasChildNodes(id)) {\n throw new RuntimeException(\"当前节点存在子节点,不能删除\");\n }\n if (hasMainRecords(id)) {\n throw new RuntimeException(\"当前节点已关联主表数据,不能删除\");\n }\n }\n\n return ${childClassNLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (36,'实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport java.util.List;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = \"${tableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${tableComment}\")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description=\"$comment 查询范围\",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (34,'左树右表ServiceV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/${ClassName}Service.java','左树右表ServiceV202611','package ${package}.${moduleName}.service;\n\nimport cn.hutool.core.lang.tree.Tree;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.spring.service.IService;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport ${entityClassName};\n\nimport java.util.List;\n\n/**\n * ${tableComment} Service接口\n *\n * @author ${author}\n * @date ${datetime}\n */\n#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPkField = $field)\n#break\n#end\n#end\npublic interface ${ClassName}Service extends IService<${ClassName}Entity> {\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n List<Tree<${childPkField.attrType}>> buildTree(LambdaQueryWrapper<${ChildClassName}Entity> wrapper);\n\n /**\n * 获取树节点详情\n * @param ${childClassName} 树节点查询对象\n * @return 树节点详情列表\n */\n List<${ChildClassName}Entity> getTreeDetails(${ChildClassName}Entity ${childClassName});\n\n /**\n * 保存树节点\n * @param ${childClassName} 树节点对象\n * @return 保存结果\n */\n Boolean saveTree(${ChildClassName}Entity ${childClassName});\n\n /**\n * 更新树节点\n * @param ${childClassName} 树节点对象\n * @return 更新结果\n */\n Boolean updateTree(${ChildClassName}Entity ${childClassName});\n\n /**\n * 批量删除树节点\n * @param ids 树节点ID列表\n * @return 删除结果\n */\n Boolean removeTreeByIds(${childPkField.attrType}[] ids);\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (35,'左树右表ServiceImplV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/service/impl/${ClassName}ServiceImpl.java','左树右表ServiceImplV202611','package ${package}.${moduleName}.service.impl;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.lang.tree.Tree;\nimport cn.hutool.core.lang.tree.TreeNode;\nimport cn.hutool.core.lang.tree.TreeUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.spring.service.impl.ServiceImpl;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport ${entityClassName};\nimport ${package}.${moduleName}.mapper.${ChildClassName}Mapper;\nimport ${package}.${moduleName}.mapper.${ClassName}Mapper;\nimport ${package}.${moduleName}.service.${ClassName}Service;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Function;\n\n/**\n * ${tableComment} Service实现类\n *\n * @author ${author}\n * @date ${datetime}\n */\n#foreach($field in $childFieldList)\n#if($field.primaryPk == \'1\')\n#set($childPkField = $field)\n#set($childPkGetter = $str.getProperty($childPkField.attrName))\n#break\n#end\n#end\n#set($parentGetter = $str.getProperty($parentField))\n#set($childFieldGetter = $str.getProperty($childField))\n#if($childPkField.attrType == \'Long\')\n#set($treeRootId = \'0L\')\n#elseif($childPkField.attrType == \'String\')\n#set($treeRootId = \'\"0\"\')\n#else\n#set($treeRootId = \'0\')\n#end\n@Service\n@RequiredArgsConstructor\npublic class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> implements ${ClassName}Service {\n\n private final ${ChildClassName}Mapper ${childClassName}Mapper;\n\n /**\n * 构建树形结构数据\n * @param wrapper 查询条件\n * @return 树形结构数据\n */\n @Override\n public List<Tree<${childPkField.attrType}>> buildTree(LambdaQueryWrapper<${ChildClassName}Entity> wrapper) {\n List<${ChildClassName}Entity> allList = ${childClassName}Mapper.selectList(wrapper);\n\n if (CollUtil.isEmpty(allList)) {\n return new ArrayList<>();\n }\n\n List<TreeNode<${childPkField.attrType}>> collect = allList.stream().map(getNodeFunction()).toList();\n return TreeUtil.build(collect, ${treeRootId});\n }\n\n /**\n * 获取树节点详情\n * @param ${childClassName} 树节点查询对象\n * @return 树节点详情列表\n */\n @Override\n public List<${ChildClassName}Entity> getTreeDetails(${ChildClassName}Entity ${childClassName}) {\n return ${childClassName}Mapper.selectList(Wrappers.query(${childClassName}));\n }\n\n /**\n * 保存树节点\n * @param ${childClassName} 树节点对象\n * @return 保存结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean saveTree(${ChildClassName}Entity ${childClassName}) {\n ${childClassName}.$str.setProperty($parentField)(validateParentRelation(null, ${childClassName}.$str.getProperty($parentField)()));\n return ${childClassName}Mapper.insert(${childClassName}) > 0;\n }\n\n /**\n * 更新树节点\n * @param ${childClassName} 树节点对象\n * @return 更新结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean updateTree(${ChildClassName}Entity ${childClassName}) {\n ${childClassName}.$str.setProperty($parentField)(validateParentRelation(${childClassName}.$str.getProperty($childPkField.attrName)(), ${childClassName}.$str.getProperty($parentField)()));\n return ${childClassName}Mapper.updateById(${childClassName}) > 0;\n }\n\n /**\n * 批量删除树节点\n * @param ids 树节点ID列表\n * @return 删除结果\n */\n @Override\n @Transactional(rollbackFor = Exception.class)\n public Boolean removeTreeByIds(${childPkField.attrType}[] ids) {\n if (ArrayUtil.isEmpty(ids)) {\n return Boolean.TRUE;\n }\n\n for (${childPkField.attrType} id : ids) {\n if (hasChildNodes(id)) {\n throw new RuntimeException(\"当前节点存在子节点,不能删除\");\n }\n if (hasMainRecords(id)) {\n throw new RuntimeException(\"当前节点已关联主表数据,不能删除\");\n }\n }\n\n return ${childClassNameLine truncated
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (36,'实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ClassName}Entity.java','实体V202611','#set($hasOrg = false)\n#foreach($field in $fieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.spring.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport org.apache.fesod.sheet.annotation.ExcelIgnore;\nimport java.util.List;\n#end\n#if($isTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\n#foreach($import in $importList)\n#if(!$import.startsWith(\'java.lang.\'))\nimport $import;\n#end\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isTenant)\n@TenantTable\n#end\n@TableName(value = \"${tableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${tableComment}\")\npublic class ${ClassName}Entity extends Model<${ClassName}Entity> {\n\n#foreach ($field in $fieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n @ExcelIgnore\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#elseif($field.formType == \'daterange\' || $field.formType == \'datetimerange\')\n private String[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end\n#end\n#foreach ($field in $queryList)\n#if($field.queryFormType == \'daterange\' || $field.queryFormType == \'datetimerange\')\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n\n /**\n * $comment 查询范围\n */\n @TableField(exist = false)\n @Schema(description=\"$comment 查询范围\",hidden=true)\n private String[] ${field.attrName}Range;\n#end\n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (37,'MapperV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/mapper/${ClassName}Mapper.java','MapperV202611','package ${package}.${moduleName}.mapper;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport ${entityClassName};\nimport org.apache.ibatis.annotations.Mapper;\n\n@Mapper\npublic interface ${ClassName}Mapper extends BaseMapper<${ClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (38,'Mapper.xmlV202611','${backendPath}/src/main/resources/mapper/${ClassName}Mapper.xml','Mapper.xmlV202611','<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"${package}.${moduleName}.mapper.${ClassName}Mapper\">\n\n <resultMap id=\"${className}Map\" type=\"${entityClassName}\">\n#foreach ($field in $fieldList)\n #if($field.primaryPk == \'1\')\n <id property=\"$field.attrName\" column=\"$field.fieldName\"/>\n #else\n <result property=\"$field.attrName\" column=\"$field.fieldName\"#if($field.formType.startsWith(\'org-\')) typeHandler=\"com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler\"#end/>\n #end\n#end\n </resultMap>\n</mapper>\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (39,'子实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ChildClassName}Entity.java','子实体V202611','#set($hasOrg = false)\n#foreach($field in $childFieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\n#if($isChildTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport java.util.List;\n#end\n#set($childImports = [])\n#foreach($field in $childFieldList)\n#if($field.packageName && !$field.packageName.startsWith(\'java.lang.\') && !$childImports.contains($field.packageName))\n#set($void = $childImports.add($field.packageName))\n#end\n#end\n#foreach($import in $childImports)\nimport $import;\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isChildTenant)\n@TenantTable\n#end\n@TableName(value = \"${childTableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${childTableName}\")\npublic class ${ChildClassName}Entity extends Model<${ChildClassName}Entity> {\n\n#foreach ($field in $childFieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end \n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (39,'子实体V202611','${entityPath}/src/main/java/${entityPackagePath}/${ChildClassName}Entity.java','子实体V202611','#set($hasOrg = false)\n#foreach($field in $childFieldList)\n#if($field.formType.startsWith(\'org-\'))\n#set($hasOrg = true)\n#end\n#end\npackage ${entityPackage};\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.spring.activerecord.Model;\nimport io.swagger.v3.oas.annotations.media.Schema;\n#if($isChildTenant)\nimport ${package}.common.core.util.TenantTable;\n#end\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if($hasOrg)\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport ${package}.common.core.util.OrgRef;\nimport java.util.List;\n#end\n#set($childImports = [])\n#foreach($field in $childFieldList)\n#if($field.packageName && !$field.packageName.startsWith(\'java.lang.\') && !$childImports.contains($field.packageName))\n#set($void = $childImports.add($field.packageName))\n#end\n#end\n#foreach($import in $childImports)\nimport $import;\n#end\n\n/**\n * ${tableComment}\n *\n * @author ${author}\n * @date ${datetime}\n */\n@Data\n#if($isChildTenant)\n@TenantTable\n#end\n@TableName(value = \"${childTableName}\"#if($hasOrg), autoResultMap = true#end)\n@EqualsAndHashCode(callSuper = true)\n@Schema(description = \"${childTableName}\")\npublic class ${ChildClassName}Entity extends Model<${ChildClassName}Entity> {\n\n#foreach ($field in $childFieldList)\n#if(${field.fieldComment})#set($comment=${field.fieldComment})#else #set($comment=${field.attrName})#end\n /**\n * $comment\n */\n#if($field.primaryPk == \'1\')\n @TableId(type = IdType.ASSIGN_ID)\n#end\n#if($field.formType.startsWith(\'org-\'))\n @TableField(typeHandler = JacksonTypeHandler.class#if($field.autoFill == \'INSERT\' || $field.autoFill == \'INSERT_UPDATE\' || $field.autoFill == \'UPDATE\'), fill = FieldFill.${field.autoFill}#end)\n#elseif($field.autoFill == \'INSERT\')\n @TableField(fill = FieldFill.INSERT)\n#elseif($field.autoFill == \'INSERT_UPDATE\')\n @TableField(fill = FieldFill.INSERT_UPDATE)\n#elseif($field.autoFill == \'UPDATE\')\n @TableField(fill = FieldFill.UPDATE)\n#end\n#if($field.fieldName == \'del_flag\')\n @TableLogic\n @TableField(fill = FieldFill.INSERT)\n#end\n @Schema(description=\"$comment\"#if($field.hidden),hidden=$field.hidden#end)\n#if($field.formType.startsWith(\'org-\'))\n private List<OrgRef> $field.attrName;\n#elseif($field.formType == \'checkbox\')\n private ${field.attrType}[] $field.attrName;\n#else\n private $field.attrType $field.attrName;\n#end \n#end\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (40,'子MapperV202611','${backendPath}/src/main/java/${packagePath}/${moduleName}/mapper/${ChildClassName}Mapper.java','子MapperV202611','package ${package}.${moduleName}.mapper;\n\nimport ${package}.common.data.datascope.PigxBaseMapper;\nimport ${entityPackage}.${ChildClassName}Entity;\nimport org.apache.ibatis.annotations.Mapper;\n\n@Mapper\npublic interface ${ChildClassName}Mapper extends PigxBaseMapper<${ChildClassName}Entity> {\n\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (41,'权限菜单V202611','${backendPath}/menu/${functionName}_menu.sql','权限菜单V202611','#set($permissionPrefix = \"${moduleName}_${functionName}\")\n#set($permissionPrefix = $permissionPrefix.toLowerCase())\n-- 该脚本不要直接执行, 注意维护菜单的父节点ID 默认 父节点-1 , #if(!$opensource)默认租户 1#end\n#set($menuId=${dateTool.getSystemTime()})\n\n-- 菜单SQL\ninsert into sys_menu ( menu_id,parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${menuId}, \'-1\', \'/${moduleName}/${functionName}/index\', \'\', \'0\', \'icon-bangzhushouji\', \'0\', null , \'8\', null , \'${tableComment}管理\'#if(!$opensource), 1#end);\n\n-- 菜单对应按钮SQL\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,1)},${menuId}, \'${permissionPrefix}_view\', \'1\', null, \'1\', \'0\', null, \'0\', null, \'${tableComment}查看\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,2)},${menuId}, \'${permissionPrefix}_add\', \'1\', null, \'1\', \'0\', null, \'1\', null, \'${tableComment}新增\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,3)},${menuId}, \'${permissionPrefix}_edit\', \'1\', null, \'1\', \'0\', null, \'2\', null, \'${tableComment}修改\'#if(!$opensource), 1#end);\n\ninsert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,4)},${menuId}, \'${permissionPrefix}_del\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'${tableComment}删除\'#if(!$opensource), 1#end);\n\ninsert into sys_menu ( menu_id,parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name#if(!$opensource), tenant_id#end)\nvalues (${math.add($menuId,5)},${menuId}, \'${permissionPrefix}_export\', \'1\', null, \'1\', \'0\', null, \'3\', null, \'导入导出\'#if(!$opensource), 1#end);\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');
INSERT INTO `gen_template` (`id`, `template_name`, `generator_path`, `template_desc`, `template_code`, `create_time`, `update_time`, `del_flag`, `tenant_id`, `create_by`, `update_by`) VALUES (42,'左树右表api.tsV202611','${frontendPath}/src/api/${moduleName}/${functionName}.ts','左树右表api.tsV202611','import request from \"/@/utils/request\"\n\n// ========== 基础CRUD接口 ==========\n\n/**\n * 分页查询列表数据\n * @param query - 查询参数对象\n * @returns Promise<分页数据>\n */\nexport function fetchList(query?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/page\',\n method: \'get\',\n params: query\n })\n}\n\n/**\n * 新增数据\n * @param obj - 要新增的数据对象\n * @returns Promise<boolean> - 操作结果\n */\nexport function addObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}\',\n method: \'post\',\n data: obj\n })\n}\n\n/**\n * 获取详情数据\n * @param obj - 查询参数对象(包含ID等)\n * @returns Promise<数据详情>\n */\nexport function getObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/details\',\n method: \'get\',\n params: obj\n })\n}\n\n/**\n * 批量删除数据\n * @param ids - 要删除的ID数组\n * @returns Promise<操作结果>\n */\nexport function delObjs(ids?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}\',\n method: \'delete\',\n data: ids\n })\n}\n\n/**\n * 更新数据\n * @param obj - 要更新的数据对象\n * @returns Promise<操作结果>\n */\nexport function putObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}\',\n method: \'put\',\n data: obj\n })\n}\n\n// ========== 树形CRUD接口 ==========\n\n/**\n * 获取树形列表数据\n * @param query - 查询参数对象\n * @returns Promise<树形数据>\n */\nexport function fetchTreeList(query?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/tree\',\n method: \'get\',\n params: query\n })\n}\n\n/**\n * 获取树节点详情\n * @param obj - 查询参数对象(包含ID等)\n * @returns Promise<树节点详情>\n */\nexport function getTreeObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/tree/details\',\n method: \'get\',\n params: obj\n })\n}\n\n/**\n * 新增树节点\n * @param obj - 要新增的树节点对象\n * @returns Promise<操作结果>\n */\nexport function addTreeObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/tree\',\n method: \'post\',\n data: obj\n })\n}\n\n/**\n * 更新树节点\n * @param obj - 要更新的树节点对象\n * @returns Promise<操作结果>\n */\nexport function putTreeObj(obj?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/tree\',\n method: \'put\',\n data: obj\n })\n}\n\n/**\n * 删除树节点\n * @param ids - 要删除的树节点ID数组\n * @returns Promise<操作结果>\n */\nexport function delTreeObjs(ids?: Object) {\n return request({\n url: \'/${moduleName}/${functionName}/tree\',\n method: \'delete\',\n data: ids\n })\n}\n\n// ========== 工具函数 ==========\n\n/**\n * 验证字段值唯一性\n * @param rule - 验证规则对象\n * @param value - 要验证的值\n * @param callback - 验证回调函数\n * @param isEdit - 是否为编辑模式\n *\n * @example\n * // 在表单验证规则中使用\n * fieldName: [\n * {\n * validator: (rule, value, callback) => {\n * validateExist(rule, value, callback, form.${pk.attrName} !== \'\');\n * },\n * trigger: \'blur\',\n * },\n * ]\n */\nexport function validateExist(rule: any, value: any, callback: any, isEdit: boolean) {\n // 编辑模式下跳过验证\n if (isEdit) {\n return callback();\n }\n\n // 查询是否存在相同值\n getObj({ [rule.field]: value }).then((response) => {\n const result = response.data;\n if (result !== null && result.length > 0) {\n callback(new Error(\'数据已经存在\'));\n } else {\n callback();\n }\n });\n}\n','2026-04-08 17:38:24','2026-04-08 17:38:24','0',1,'admin','admin');