1. 统一包名修改

This commit is contained in:
chenbowen
2025-09-22 11:55:27 +08:00
parent a001fc8f16
commit 0d46897482
2739 changed files with 512 additions and 512 deletions

View File

@@ -0,0 +1,101 @@
--- #################### 数据库相关配置 ####################
spring:
# 数据源配置项
autoconfigure:
exclude:
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
enabled: true
stat-view-servlet:
enabled: true
allow: # 设置白名单,不填则允许所有访问
url-pattern: /druid/*
login-username: # 控制台管理用户名和密码
login-password:
filter:
stat:
enabled: true
log-slow-sql: true # 慢 SQL 记录
slow-sql-millis: 100
merge-sql: true
wall:
config:
multi-statement-allow: true
dynamic: # 多数据源配置
druid: # Druid 【连接池】相关的全局配置
initial-size: 5 # 初始连接数
min-idle: 10 # 最小连接池数量
max-active: 20 # 最大连接池数量
max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
test-while-idle: true
test-on-borrow: false
test-on-return: false
primary: master
datasource:
master:
url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO
username: SYSDBA
password: pgbsci6ddJ6Sqj@e
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO
username: SYSDBA
password: pgbsci6ddJ6Sqj@e
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
host: 172.16.46.63 # 地址
port: 30379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################
# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
name-server: 172.16.46.63:30876 # RocketMQ Namesrv
--- #################### 定时任务相关配置 ####################
xxl:
job:
admin:
addresses: http://172.16.46.63:30082/xxl-job-admin # 调度中心部署跟地址
--- #################### 服务保障相关配置 ####################
# Lock4j 配置项
lock4j:
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
--- #################### 监控相关配置 ####################
# Actuator 监控端点的配置项
management:
endpoints:
web:
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# Spring Boot Admin 配置项
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
instance:
service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
# Spring Boot Admin Server 服务端的相关配置
context-path: /admin # 配置 Spring
--- #################### ZT相关配置 ####################

View File

@@ -0,0 +1,127 @@
--- #################### 数据库相关配置 ####################
spring:
# 数据源配置项
autoconfigure:
exclude:
- de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置
- de.codecentric.boot.admin.server.cloud.config.AdminServerDiscoveryAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置
- de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置
- de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
enabled: true
stat-view-servlet:
enabled: true
allow: # 设置白名单,不填则允许所有访问
url-pattern: /druid/*
login-username: # 控制台管理用户名和密码
login-password:
filter:
stat:
enabled: true
log-slow-sql: true # 慢 SQL 记录
slow-sql-millis: 100
merge-sql: true
wall:
config:
multi-statement-allow: true
dynamic: # 多数据源配置
druid: # Druid 【连接池】相关的全局配置
initial-size: 1 # 初始连接数
min-idle: 1 # 最小连接池数量
max-active: 20 # 最大连接池数量
max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
test-while-idle: true
test-on-borrow: false
test-on-return: false
primary: master
datasource:
master:
url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO
username: SYSDBA
password: pgbsci6ddJ6Sqj@e
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO
username: SYSDBA
password: pgbsci6ddJ6Sqj@e
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
host: 172.16.46.63 # 地址
port: 30379 # 端口
database: 0 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################
# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
name-server: 172.16.46.63:30876 # RocketMQ Namesrv
--- #################### 定时任务相关配置 ####################
xxl:
job:
enabled: false # 是否开启调度中心,默认为 true 开启
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin # 调度中心部署跟地址
--- #################### 服务保障相关配置 ####################
# Lock4j 配置项
lock4j:
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
--- #################### 监控相关配置 ####################
# Actuator 监控端点的配置项
management:
endpoints:
web:
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# Spring Boot Admin 配置项
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
instance:
service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
# Spring Boot Admin Server 服务端的相关配置
context-path: /admin # 配置 Spring
# 日志文件配置
logging:
level:
# 配置自己写的 MyBatis Mapper 打印日志
com.zt.plat.module.infra.dal.mysql: debug
com.zt.plat.module.infra.dal.mysql.logger.ApiErrorLogMapper: INFO # 配置 ApiErrorLogMapper 的日志级别为 info避免和 GlobalExceptionHandler 重复打印
com.zt.plat.module.infra.dal.mysql.file.FileConfigMapper: INFO # 配置 FileConfigMapper 的日志级别为 info
org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿先禁用Spring Boot 3.X 存在部分错误的 WARN 提示
--- #################### ZT相关配置 ####################
# ZT配置项设置当前项目所有自定义的配置
cloud:
env: # 多环境的配置项
tag: ${HOSTNAME}
security:
mock-enable: true
access-log: # 访问日志的配置项
enable: true
# 固定验证码
verify-code: 666666
file:
download-expire-seconds: 20

View File

@@ -0,0 +1,202 @@
spring:
application:
name: infra-server
profiles:
active: ${env.name}
#统一nacos配置使用 profile 管理
cloud:
nacos:
server-addr: ${config.server-addr} # Nacos 服务器地址
username: ${config.username} # Nacos 账号
password: ${config.password} # Nacos 密码
discovery: # 【配置中心】配置项
namespace: ${config.namespace} # 命名空间。这里使用 maven Profile 资源过滤进行动态替换
group: ${config.group} # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
metadata:
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
config: # 【注册中心】配置项
namespace: ${config.namespace} # 命名空间。这里使用 maven Profile 资源过滤进行动态替换
group: ${config.group} # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务
config:
import:
- optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置
# Servlet 配置
servlet:
# 文件上传相关配置项
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
# Jackson 配置项
jackson:
serialization:
write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
fail-on-empty-beans: false # 允许序列化无属性的 Bean
# Cache 配置项
cache:
type: REDIS
redis:
time-to-live: 1h # 设置过期时间为 1 小时
server:
port: 48082
logging:
file:
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
--- #################### 接口文档配置 ####################
springdoc:
api-docs:
enabled: true # 1. 是否开启 Swagger 接文档的元数据
path: /v3/api-docs
swagger-ui:
enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面
path: /swagger-ui
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
setting:
language: zh_cn
# MyBatis Plus 的配置项
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
global-config:
db-config:
id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
# id-type: AUTO # 自增 ID适合 MySQL 等直接自增的数据库
# id-type: INPUT # 用户输入 ID适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
# id-type: ASSIGN_ID # 分配 ID默认使用雪花算法。注意Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
banner: false # 关闭控制台的 Banner 打印
type-aliases-package: ${cloud.info.base-package}.dal.dataobject
encryptor:
password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成
mybatis-plus-join:
banner: false # 关闭控制台的 Banner 打印
# Spring Data Redis 配置
spring:
data:
redis:
repositories:
enabled: false # 项目未使用到 Spring Data Redis 的 Repository所以直接禁用保证启动速度
# VO 转换(数据翻译)相关
easy-trans:
is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口
--- #################### RPC 远程调用相关配置 ####################
--- #################### 消息队列相关 ####################
# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
# Producer 配置项
producer:
group: ${spring.application.name}_PRODUCER # 生产者分组
spring:
# Kafka 配置项,对应 KafkaProperties 配置类
kafka:
# Kafka Producer 配置项
producer:
acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。
retries: 3 # 发送失败时,重试发送的次数
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化
# Kafka Consumer 配置项
consumer:
auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
properties:
spring.json.trusted.packages: '*'
# Kafka Consumer Listener 监听器配置
listener:
missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错
--- #################### 定时任务相关配置 ####################
xxl:
job:
executor:
appname: ${spring.application.name} # 执行器 AppName
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
accessToken: default_token # 执行器通讯TOKEN
--- #################### ZT相关配置 ####################
cloud:
# 附件加密相关配置
AES:
key: "0123456789abcdef0123456789abcdef"
# 附件预览
kkfile: "http://172.16.46.63:30012/onlinePreview?url="
info:
version: 1.0.0
base-package: com.zt.plat.module.infra
web:
admin-ui:
url: http://dashboard.cloud.iocoder.cn # Admin 管理后台 UI 的地址
xss:
enable: false
exclude-urls: # 如下两个 url仅仅是为了演示去掉配置也没关系
- ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
- ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
websocket:
enable: true # websocket的开关
path: /infra/ws # 路径
sender-type: local # 消息发送的类型,可选值为 local、redis、rocketmq、kafka、rabbitmq
sender-rocketmq:
topic: ${spring.application.name}-websocket # 消息发送的 RocketMQ Topic
consumer-group: ${spring.application.name}-websocket-consumer # 消息发送的 RocketMQ Consumer Group
sender-rabbitmq:
exchange: ${spring.application.name}-websocket-exchange # 消息发送的 RabbitMQ Exchange
queue: ${spring.application.name}-websocket-queue # 消息发送的 RabbitMQ Queue
sender-kafka:
topic: ${spring.application.name}-websocket # 消息发送的 Kafka Topic
consumer-group: ${spring.application.name}-websocket-consumer # 消息发送的 Kafka Consumer Group
swagger:
title: 管理后台
description: 提供管理员管理的所有功能
version: ${cloud.info.version}
codegen:
base-package: com.zt.plat
db-schemas: ${spring.datasource.dynamic.datasource.master.name}
front-type: 20 # 前端模版的类型,参见 CodegenFrontTypeEnum 枚举类
vo-type: 10 # VO 的类型,参见 CodegenVOTypeEnum 枚举类
delete-batch-enable: true # 是否生成批量删除接口
unit-test-enable: false # 是否生成单元测试
tenant: # 多租户相关配置项
enable: true
ignore-urls:
- /admin-api/infra/doc-file/file-content
- /admin-api/infra/doc-file/callback* # OnlyOffice回调接口
ignore-tables:
- infra_std_name
- infra_doc_file
- infra_doc_file_version
debug: false
# OnlyOffice 配置
onlyoffice:
base-url: http://172.16.46.63:30085 # OnlyOffice 服务地址
callback-base-url: http://172.16.46.62:30081 # 应用服务回调地址OnlyOffice需要能访问到
jwt-secret: P@ssword25 # JWT 密钥

View File

@@ -0,0 +1,302 @@
package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName};
import org.springframework.web.bind.annotation.*;
import ${jakartaPackage}.annotation.Resource;
import org.springframework.validation.annotation.Validated;
#if ($sceneEnum.scene == 1)
import org.springframework.security.access.prepost.PreAuthorize;
#end
#if($isBusiness && $isBusiness == true)
import ${basePackage}.framework.business.interceptor.BusinessControllerMarker;
#end
#if($isFileUpload && $isFileUpload == true)
import ${basePackage}.framework.business.annotation.FileUploadController;
import ${basePackage}.framework.business.controller.AbstractFileUploadController;
#end
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import ${jakartaPackage}.validation.constraints.*;
import ${jakartaPackage}.validation.*;
import ${jakartaPackage}.servlet.http.*;
import java.util.*;
import java.io.IOException;
import ${basePackage}.framework.common.pojo.vo.BatchDeleteReqVO;
import ${PageParamClassName};
import ${PageResultClassName};
import ${CommonResultClassName};
import ${BeanUtils};
import static ${CommonResultClassName}.success;
import ${ExcelUtilsClassName};
import ${ApiAccessLogClassName};
import static ${OperateTypeEnumClassName}.*;
import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
#end
import ${basePackage}.module.${table.moduleName}.service.${table.businessName}.${table.className}Service;
@Tag(name = "${sceneEnum.name} - ${table.classComment}")
@RestController
##二级的 businessName 暂时不算在 HTTP 路径上,可以根据需要写
@RequestMapping("/${table.moduleName}/${simpleClassName_strikeCase}")
@Validated
#if($isFileUpload && $isFileUpload == true)
@FileUploadController(source = "${table.moduleName}.${table.businessName}")
#end
## 支持业务基类标记isBusiness=true 时继承 BusinessControllerMarker
#if($isBusiness && $isBusiness == true && (!$isFileUpload || !$isFileUpload == true))
public class ${sceneEnum.prefixClass}${table.className}Controller implements BusinessControllerMarker {
#elseif((!$isBusiness || !$isBusiness == true) && (!$isFileUpload || !$isFileUpload == true))
public class ${sceneEnum.prefixClass}${table.className}Controller {
#elseif($isBusiness && $isBusiness == true && $isFileUpload && $isFileUpload == true)
public class ${sceneEnum.prefixClass}${table.className}Controller extends AbstractFileUploadController implements BusinessControllerMarker{
#elseif((!$isBusiness || !$isBusiness == true) && $isFileUpload && $isFileUpload == true)
public class ${sceneEnum.prefixClass}${table.className}Controller extends AbstractFileUploadController {
#end
#if($isFileUpload && $isFileUpload == true)
static {
FileUploadController annotation = ${sceneEnum.prefixClass}${table.className}Controller.class.getAnnotation(FileUploadController.class);
if (annotation != null) {
setFileUploadInfo(annotation);
}
}
#end
@Resource
private ${table.className}Service ${classNameVar}Service;
@PostMapping("/create")
@Operation(summary = "创建${table.classComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')")
#end
public CommonResult<${respVOClass}> create${simpleClassName}(@Valid @RequestBody ${saveReqVOClass} ${saveReqVOVar}) {
return success(${classNameVar}Service.create${simpleClassName}(${saveReqVOVar}));
}
@PutMapping("/update")
@Operation(summary = "更新${table.classComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')")
#end
public CommonResult<Boolean> update${simpleClassName}(@Valid @RequestBody ${updateReqVOClass} ${updateReqVOVar}) {
${classNameVar}Service.update${simpleClassName}(${updateReqVOVar});
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除${table.classComment}")
@Parameter(name = "id", description = "编号", required = true)
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")
#end
public CommonResult<Boolean> delete${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
${classNameVar}Service.delete${simpleClassName}(id);
return success(true);
}
#if ( $table.templateType != 2 && $deleteBatchEnable)
@DeleteMapping("/delete-list")
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除${table.classComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")
#end
public CommonResult<Boolean> delete${simpleClassName}List(@RequestBody BatchDeleteReqVO req) {
${classNameVar}Service.delete${simpleClassName}ListByIds(req.getIds());
return success(true);
}
#end
@GetMapping("/get")
@Operation(summary = "获得${table.classComment}")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<${respVOClass}> get${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
${table.className}DO ${classNameVar} = ${classNameVar}Service.get${simpleClassName}(id);
#if ($voType == 10)
return success(BeanUtils.toBean(${classNameVar}, ${respVOClass}.class));
#else
return success(${classNameVar});
#end
}
#if ( $table.templateType != 2 )
@GetMapping("/page")
@Operation(summary = "获得${table.classComment}分页")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<PageResult<${respVOClass}>> get${simpleClassName}Page(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) {
PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO);
#if ($voType == 10)
return success(BeanUtils.toBean(pageResult, ${respVOClass}.class));
#else
return success(pageResult);
#end
}
## 特殊:树表专属逻辑(树不需要分页接口)
#else
@GetMapping("/list")
@Operation(summary = "获得${table.classComment}列表")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<List<${respVOClass}>> get${simpleClassName}List(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) {
List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO);
#if ($voType == 10)
return success(BeanUtils.toBean(list, ${respVOClass}.class));
#else
return success(list);
#end
}
#end
@GetMapping("/export-excel")
@Operation(summary = "导出${table.classComment} Excel")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:export')")
#end
@ApiAccessLog(operateType = EXPORT)
#if ( $table.templateType != 2 )
public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${respVOClass}.class,
BeanUtils.toBean(list, ${respVOClass}.class));
}
## 特殊:树表专属逻辑(树不需要分页接口)
#else
public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO,
HttpServletResponse response) throws IOException {
List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO);
// 导出 Excel
ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${table.className}RespVO.class,
BeanUtils.toBean(list, ${table.className}RespVO.class));
}
#end
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
#set ($subClassNameVar = $subClassNameVars.get($index))
// ==================== 子表($subTable.classComment ====================
## 情况一MASTER_ERP 时,需要分查询页子表
#if ( $table.templateType == 11 )
@GetMapping("/${subSimpleClassName_strikeCase}/page")
@Operation(summary = "获得${subTable.classComment}分页")
@Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<PageResult<${subTable.className}DO>> get${subSimpleClassName}Page(PageParam pageReqVO,
@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return success(${classNameVar}Service.get${subSimpleClassName}Page(pageReqVO, ${subJoinColumn.javaField}));
}
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ( $subTable.subJoinMany )
@GetMapping("/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}")
@Operation(summary = "获得${subTable.classComment}列表")
@Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<List<${subTable.className}DO>> get${subSimpleClassName}ListBy${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return success(${classNameVar}Service.get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}));
}
#else
@GetMapping("/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}")
@Operation(summary = "获得${subTable.classComment}")
@Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<${subTable.className}DO> get${subSimpleClassName}By${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return success(${classNameVar}Service.get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}));
}
#end
#end
## 特殊MASTER_ERP 时,支持单个的新增、修改、删除操作
#if ( $table.templateType == 11 )
@PostMapping("/${subSimpleClassName_strikeCase}/create")
@Operation(summary = "创建${subTable.classComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')")
#end
public CommonResult<${subPrimaryColumn.javaType}> create${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) {
return success(${classNameVar}Service.create${subSimpleClassName}(${subClassNameVar}));
}
@PutMapping("/${subSimpleClassName_strikeCase}/update")
@Operation(summary = "更新${subTable.classComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')")
#end
public CommonResult<Boolean> update${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) {
${classNameVar}Service.update${subSimpleClassName}(${subClassNameVar});
return success(true);
}
@DeleteMapping("/${subSimpleClassName_strikeCase}/delete")
@Parameter(name = "id", description = "编号", required = true)
@Operation(summary = "删除${subTable.classComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")
#end
public CommonResult<Boolean> delete${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) {
${classNameVar}Service.delete${subSimpleClassName}(id);
return success(true);
}
#if ($deleteBatchEnable)
@DeleteMapping("/${subSimpleClassName_strikeCase}/delete-list")
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除${subTable.classComment}")
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")
#end
public CommonResult<Boolean> delete${subSimpleClassName}List(@RequestParam("ids") List<${subPrimaryColumn.javaType}> ids) {
${classNameVar}Service.delete${subSimpleClassName}ListByIds(ids);
return success(true);
}
#end
@GetMapping("/${subSimpleClassName_strikeCase}/get")
@Operation(summary = "获得${subTable.classComment}")
@Parameter(name = "id", description = "编号", required = true)
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<${subTable.className}DO> get${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) {
return success(${classNameVar}Service.get${subSimpleClassName}(id));
}
#end
#end
}

View File

@@ -0,0 +1,45 @@
package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import ${PageParamClassName};
#foreach ($column in $columns)
#if (${column.javaType} == "BigDecimal")
import java.math.BigDecimal;
#break
#end
#end
## 处理 LocalDateTime 字段的引入
#foreach ($column in $columns)
#if (${column.listOperation} && ${column.javaType} == "LocalDateTime")
import java.time.LocalDateTime;
import org.springframework.format.annotation.DateTimeFormat;
import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
#break
#end
#end
## 字段模板
#macro(columnTpl $prefix $prefixStr)
@Schema(description = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end)
private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end;
#end
@Schema(description = "${sceneEnum.name} - ${table.classComment}列表 Request VO")
@Data
public class ${sceneEnum.prefixClass}${table.className}ListReqVO {
#foreach ($column in $columns)
#if (${column.listOperation})##查询操作
#if (${column.listOperationCondition} == "BETWEEN")## 情况一Between 的时候
@Schema(description = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end)
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private ${column.javaType}[] ${column.javaField};
#else##情况二,非 Between 的时间
#columnTpl('', '')
#end
#end
#end
}

View File

@@ -0,0 +1,45 @@
package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import ${PageParamClassName};
#foreach ($column in $columns)
#if (${column.javaType} == "BigDecimal")
import java.math.BigDecimal;
#break
#end
#end
## 处理 LocalDateTime 字段的引入
#foreach ($column in $columns)
#if (${column.listOperationCondition} && ${column.javaType} == "LocalDateTime")
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
#break
#end
#end
## 字段模板
#macro(columnTpl $prefix $prefixStr)
@Schema(description = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end)
private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end;
#end
@Schema(description = "${sceneEnum.name} - ${table.classComment}分页 Request VO")
@Data
public class ${sceneEnum.prefixClass}${table.className}PageReqVO extends PageParam {
#foreach ($column in $columns)
#if (${column.listOperation})##查询操作
#if (${column.listOperationCondition} == "BETWEEN")## 情况一Between 的时候
@Schema(description = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end)
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private ${column.javaType}[] ${column.javaField};
#else##情况二,非 Between 的时间
#columnTpl('', '')
#end
#end
#end
}

View File

@@ -0,0 +1,53 @@
package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
## 处理 BigDecimal 字段的引入
#foreach ($column in $columns)
#if (${column.javaType} == "BigDecimal")
import java.math.BigDecimal;
#break
#end
#end
## 处理 LocalDateTime 字段的引入
#foreach ($column in $columns)
#if (${column.listOperationResult} && ${column.javaType} == "LocalDateTime")
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
#break
#end
#end
## 处理 Excel 导出
import com.alibaba.excel.annotation.*;
#foreach ($column in $columns)
#if ("$!column.dictType" != "")## 有设置数据字典
import ${DictFormatClassName};
import ${DictConvertClassName};
#break
#end
#end
@Schema(description = "${sceneEnum.name} - ${table.classComment} Response VO")
@Data
@ExcelIgnoreUnannotated
public class ${sceneEnum.prefixClass}${table.className}RespVO {
## 逐个处理字段
#foreach ($column in $columns)
#if (${column.listOperationResult})
## 1. 处理 Swagger 注解
@Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end)
## 2. 处理 Excel 导出
#if ("$!column.dictType" != "")##处理枚举值
@ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class)
@DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
#else
@ExcelProperty("${column.columnComment}")
#end
## 3. 处理字段定义
private ${column.javaType} ${column.javaField};
#end
#end
}

View File

@@ -0,0 +1,64 @@
package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import ${jakartaPackage}.validation.constraints.*;
## 处理 BigDecimal 字段的引入
#foreach ($column in $columns)
#if (${column.javaType} == "BigDecimal")
import java.math.BigDecimal;
#break
#end
#end
## 处理 LocalDateTime 字段的引入
#foreach ($column in $columns)
#if ((${column.createOperation} || ${column.updateOperation}) && ${column.javaType} == "LocalDateTime")
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
#break
#end
#end
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
#end
@Schema(description = "${sceneEnum.name} - ${table.classComment}新增/修改 Request VO")
@Data
public class ${sceneEnum.prefixClass}${table.className}SaveReqVO {
## 逐个处理字段
#foreach ($column in $columns)
#if (${column.createOperation} || ${column.updateOperation})
## 1. 处理 Swagger 注解
@Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end)
## 2. 处理 Validator 参数校验
#if (!${column.nullable} && !${column.primaryKey})
#if (${column.javaType} == 'String')
@NotEmpty(message = "${column.columnComment}不能为空")
#else
@NotNull(message = "${column.columnComment}不能为空")
#end
#end
## 3. 处理字段定义
private ${column.javaType} ${column.javaField};
#end
#end
## 特殊:主子表专属逻辑(非 ERP 模式)
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#if ( $subTable.subJoinMany)
@Schema(description = "${subTable.classComment}列表")
private List<${subTable.className}DO> ${subClassNameVars.get($index)}s;
#else
@Schema(description = "${subTable.classComment}")
private ${subTable.className}DO ${subClassNameVars.get($index)};
#end
#end
#end
}

View File

@@ -0,0 +1,132 @@
package ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName};
import lombok.*;
import java.util.*;
#foreach ($column in $columns)
#if (${column.javaType} == "BigDecimal")
import java.math.BigDecimal;
#end
#if (${column.javaType} == "LocalDateTime")
import java.time.LocalDateTime;
#end
#end
import com.baomidou.mybatisplus.annotation.*;
## 导入基类
#if($isBusiness && $isBusiness == true)
import ${basePackage}.framework.mybatis.core.dataobject.BusinessBaseDO;
#else
import ${BaseDOClassName};
#end
## 处理 Excel 导出 + Schema 注解(仅 DO 模式)
#if ($voType == 20)
import io.swagger.v3.oas.annotations.media.Schema;
import com.alibaba.excel.annotation.*;
#foreach ($column in $columns)
#if ("$!column.dictType" != "")## 有设置数据字典
import ${DictFormatClassName};
import ${DictConvertClassName};
#break
#end
#end
#end
/**
* ${table.classComment} DO
*
* @author ${table.author}
*/
@TableName("${table.tableName.toLowerCase()}")
@KeySequence("${table.tableName.toLowerCase()}_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
## 处理 Excel 导出 + Schema 注解(仅 DO 模式)
#if ($voType == 20)
@Schema(description = "${sceneEnum.name} - ${table.classComment} Response VO")
@ExcelIgnoreUnannotated
#end
/**
* 支持业务基类继承isBusiness=true 时继承 BusinessBaseDO否则继承 BaseDO
*/
#if($isBusiness && $isBusiness == true)
public class ${table.className}DO extends BusinessBaseDO {
#else
public class ${table.className}DO extends BaseDO {
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
public static final Long ${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT = 0L;
#end
## 字段定义宏,统一渲染字段
#macro(renderField $column $isStandardized)
/**
* ${column.columnComment}
#if ("$!column.dictType" != "")
*
* 枚举 {@link TODO ${column.dictType} 对应的类}
#end
*/
#if (${column.primaryKey})
@TableId#if (${column.javaType} == 'String')(type = IdType.INPUT)#else(type = IdType.ASSIGN_ID)#end
#end
#if ($voType == 20)
@Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if (
"$!column.example" != ""), example = "${column.example}"#end)
#if ("$!column.dictType" != "")
@ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class)
@DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
#else
@ExcelProperty("${column.columnComment}")
#end
#end
#if($isStandardized == true)
#if(!${column.primaryKey})
@TableField("${column.columnName}")
#end
#end
private ${column.javaType} ${column.javaField};
#end
## 字段定义,分支避免嵌套,保证 Velocity 兼容性
#if($isBusiness == true)
#foreach ($column in $columns)
#if (!${businessBaseDOFields.contains(${column.javaField})})
#renderField($column $isStandardized)
#end
#end
#else
#foreach ($column in $columns)
#if (!${baseDOFields.contains(${column.javaField})})
#renderField($column $isStandardized)
#end
#end
#end
## 特殊:主子表专属逻辑(非 ERP 模式)
#if ( $voType == 20 && $subTables && $subTables.size() > 0 && $table.templateType != 11 )
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#if ( $subTable.subJoinMany)
/**
* ${subTable.classComment}列表
*/
@Schema(description = "${subTable.classComment}列表")
@TableField(exist = false)
private List
<${subTable.className}DO> ${subClassNameVars.get($index)}s;
#else
/**
* ${subTable.classComment}
*/
@Schema(description = "${subTable.classComment}")
@TableField(exist = false)
private ${subTable.className}DO ${subClassNameVars.get($index)};
#end
#end
#end
}

View File

@@ -0,0 +1,74 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
package ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName};
import lombok.*;
import java.util.*;
#foreach ($column in $subColumns)
#if (${column.javaType} == "BigDecimal")
import java.math.BigDecimal;
#end
#if (${column.javaType} == "LocalDateTime")
import java.time.LocalDateTime;
#end
#end
import com.baomidou.mybatisplus.annotation.*;
import ${BaseDOClassName};
## 处理 Schema 注解(仅 DO 模式)
#if ($voType == 20)
import io.swagger.v3.oas.annotations.media.Schema;
#foreach ($column in $columns)
#if ("$!column.dictType" != "")## 有设置数据字典
import ${DictFormatClassName};
import ${DictConvertClassName};
#break
#end
#end
#end
/**
* ${subTable.classComment} DO
*
* @author ${subTable.author}
*/
@TableName("${subTable.tableName.toLowerCase()}")
@KeySequence("${subTable.tableName.toLowerCase()}_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
## 处理 Schema 注解(仅 DO 模式)
#if ($voType == 20)
@Schema(description = "${sceneEnum.name} - ${table.classComment} Response VO")
#end
public class ${subTable.className}DO extends BaseDO {
#foreach ($column in $subColumns)
#if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段
/**
* ${column.columnComment}
#if ("$!column.dictType" != "")##处理枚举值
*
* 枚举 {@link TODO ${column.dictType} 对应的类}
#end
*/
#if (${column.primaryKey})##处理主键
@TableId#if (${column.javaType} == 'String')(type = IdType.INPUT)#else(type = IdType.ASSIGN_ID)#end
#end
#if($isStandardized == true)
#if(!${column.primaryKey})
@TableField("${column.columnName}")
#end
#end
#if ($voType == 20)
## 1. 处理 Swagger 注解
@Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end)
#end
## 2. 处理字段定义
private ${column.javaType} ${column.javaField};
#end
#end
}

View File

@@ -0,0 +1,82 @@
package ${basePackage}.module.${table.moduleName}.dal.dao.${table.businessName};
import java.util.*;
import ${PageResultClassName};
import ${QueryWrapperClassName};
import ${BaseMapperClassName};
import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
import org.apache.ibatis.annotations.Mapper;
import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
## 字段模板
#macro(listCondition)
#foreach ($column in $columns)
#if (${column.listOperation})
#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写
#if (${column.listOperationCondition} == "=")##情况一,= 的时候
.eqIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#if (${column.listOperationCondition} == "!=")##情况二,!= 的时候
.neIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#if (${column.listOperationCondition} == ">")##情况三,> 的时候
.gtIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#if (${column.listOperationCondition} == ">=")##情况四,>= 的时候
.geIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#if (${column.listOperationCondition} == "<")##情况五,< 的时候
.ltIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#if (${column.listOperationCondition} == "<=")##情况五,<= 的时候
.leIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#if (${column.listOperationCondition} == "LIKE")##情况七Like 的时候
.likeIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#if (${column.listOperationCondition} == "BETWEEN")##情况八Between 的时候
.betweenIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}())
#end
#end
#end
#end
/**
* ${table.classComment} Mapper
*
* @author ${table.author}
*/
@Mapper
public interface ${table.className}Mapper extends BaseMapperX<${table.className}DO> {
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
default PageResult<${table.className}DO> selectPage(${sceneEnum.prefixClass}${table.className}PageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<${table.className}DO>()
#listCondition()
.orderByDesc(${table.className}DO::getId));## 大多数情况下id 倒序
}
#else
default List<${table.className}DO> selectList(${sceneEnum.prefixClass}${table.className}ListReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<${table.className}DO>()
#listCondition()
.orderByDesc(${table.className}DO::getId));## 大多数情况下id 倒序
}
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
default ${table.className}DO selectBy${TreeParentJavaField}And${TreeNameJavaField}(Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) {
return selectOne(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField}, ${table.className}DO::get${TreeNameJavaField}, ${treeNameColumn.javaField});
}
default Long selectCountBy${TreeParentJavaField}(${treeParentColumn.javaType} ${treeParentColumn.javaField}) {
return selectCount(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField});
}
#end
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${basePackage}.module.${table.moduleName}.dal.dao.${table.businessName}.${table.className}Mapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

View File

@@ -0,0 +1,63 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subJoinColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
package ${basePackage}.module.${subTable.moduleName}.dal.dao.${subTable.businessName};
import java.util.*;
import ${PageResultClassName};
import ${PageParamClassName};
import ${QueryWrapperClassName};
import ${BaseMapperClassName};
import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
import org.apache.ibatis.annotations.Mapper;
/**
* ${subTable.classComment} Mapper
*
* @author ${subTable.author}
*/
@Mapper
public interface ${subTable.className}Mapper extends BaseMapperX<${subTable.className}DO> {
## 情况一MASTER_ERP 时,需要分查询页子表
#if ( $table.templateType == 11 )
default PageResult<${subTable.className}DO> selectPage(PageParam reqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return selectPage(reqVO, new LambdaQueryWrapperX<${subTable.className}DO>()
.eq(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField})
.orderByDesc(${subTable.className}DO::getId));## 大多数情况下id 倒序
}
## 主表与子表是一对一时
#if (!$subTable.subJoinMany)
default ${subTable.className}DO selectBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return selectOne(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField});
}
#end
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ( $subTable.subJoinMany)
default List<${subTable.className}DO> selectListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return selectList(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField});
}
#else
default ${subTable.className}DO selectBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return selectOne(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField});
}
#end
#end
default int deleteBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return delete(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField});
}
#if ( $table.templateType != 2 && $deleteBatchEnable)
default int deleteBy${SubJoinColumnName}s(List<${subJoinColumn.javaType}> ${subJoinColumn.javaField}s) {
return deleteBatch(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}s);
}
#end
}

View File

@@ -0,0 +1,22 @@
// TODO 待办:请将下面的错误码复制到 cloud-module-${table.moduleName} 模块的 ErrorCodeConstants 类中。注意请给“TODO 补充编号”设置一个错误码编号!!!
// ========== ${table.classComment} TODO 补充编号 ==========
ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${table.classComment}不存在");
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子${table.classComment},无法删除");
ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级${table.classComment}不存在");
ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父${table.classComment}");
ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该${treeNameColumn.columnComment}的${table.classComment}");
ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子${table.className}为父${table.className}");
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 )## 特殊ERP 情况
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index))
ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}不存在");
#if ( !$subTable.subJoinMany )
ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}已存在");
#end
#end
#end

View File

@@ -0,0 +1,165 @@
package ${basePackage}.module.${table.moduleName}.service.${table.businessName};
import java.util.*;
import ${jakartaPackage}.validation.*;
import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
#end
import ${PageResultClassName};
import ${PageParamClassName};
/**
* ${table.classComment} Service 接口
*
* @author ${table.author}
*/
public interface ${table.className}Service {
/**
* 创建${table.classComment}
*
* @param ${saveReqVOVar} 创建信息
* @return 编号
*/
${respVOClass} create${simpleClassName}(@Valid ${saveReqVOClass} ${saveReqVOVar});
/**
* 更新${table.classComment}
*
* @param ${updateReqVOVar} 更新信息
*/
void update${simpleClassName}(@Valid ${updateReqVOClass} ${updateReqVOVar});
/**
* 删除${table.classComment}
*
* @param id 编号
*/
void delete${simpleClassName}(${primaryColumn.javaType} id);
#if ( $table.templateType != 2 && $deleteBatchEnable)
/**
* 批量删除${table.classComment}
*
* @param ids 编号
*/
void delete${simpleClassName}ListByIds(List<${primaryColumn.javaType}> ids);
#end
/**
* 获得${table.classComment}
*
* @param id 编号
* @return ${table.classComment}
*/
${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id);
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
/**
* 获得${table.classComment}分页
*
* @param pageReqVO 分页查询
* @return ${table.classComment}分页
*/
PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO);
#else
/**
* 获得${table.classComment}列表
*
* @param listReqVO 查询条件
* @return ${table.classComment}列表
*/
List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO);
#end
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subClassNameVar = $subClassNameVars.get($index))
// ==================== 子表($subTable.classComment ====================
## 情况一MASTER_ERP 时,需要分查询页子表
#if ( $table.templateType == 11 )
/**
* 获得${subTable.classComment}分页
*
* @param pageReqVO 分页查询
* @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment}
* @return ${subTable.classComment}分页
*/
PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField});
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ( $subTable.subJoinMany )
/**
* 获得${subTable.classComment}列表
*
* @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment}
* @return ${subTable.classComment}列表
*/
List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField});
#else
/**
* 获得${subTable.classComment}
*
* @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment}
* @return ${subTable.classComment}
*/
${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField});
#end
#end
## 特殊MASTER_ERP 时,支持单个的新增、修改、删除操作
#if ( $table.templateType == 11 )
/**
* 创建${subTable.classComment}
*
* @param ${subClassNameVar} 创建信息
* @return 编号
*/
${subPrimaryColumn.javaType} create${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar});
/**
* 更新${subTable.classComment}
*
* @param ${subClassNameVar} 更新信息
*/
void update${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar});
/**
* 删除${subTable.classComment}
*
* @param id 编号
*/
void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id);
#if ($deleteBatchEnable)
/**
* 批量删除${subTable.classComment}
*
* @param ids 编号
*/
void delete${subSimpleClassName}ListByIds(List<${subPrimaryColumn.javaType}> ids);
#end
/**
* 获得${subTable.classComment}
*
* @param id 编号
* @return ${subTable.classComment}
*/
${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id);
#end
#end
}

View File

@@ -0,0 +1,422 @@
package ${basePackage}.module.${table.moduleName}.service.${table.businessName};
import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import ${jakartaPackage}.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
#end
import ${PageResultClassName};
import ${PageParamClassName};
import ${BeanUtils};
import ${basePackage}.module.${table.moduleName}.dal.dao.${table.businessName}.${table.className}Mapper;
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
import ${basePackage}.module.${subTable.moduleName}.dal.dao.${subTable.businessName}.${subTable.className}Mapper;
#end
import static ${ServiceExceptionUtilClassName}.exception;
import static ${CollectionUtilsClassName}.convertList;
import static ${CollectionUtilsClassName}.diffList;
import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*;
/**
* ${table.classComment} Service 实现类
*
* @author ${table.author}
*/
@Service
@Validated
public class ${table.className}ServiceImpl implements ${table.className}Service {
@Resource
private ${table.className}Mapper ${classNameVar}Mapper;
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
@Resource
private ${subTable.className}Mapper ${subClassNameVars.get($index)}Mapper;
#end
@Override
## 特殊:主子表专属逻辑(非 ERP 模式)
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
@Transactional(rollbackFor = Exception.class)
#end
public ${respVOClass} create${simpleClassName}(${saveReqVOClass} ${saveReqVOVar}) {
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
// 校验${treeParentColumn.columnComment}的有效性
validateParent${simpleClassName}(null, ${saveReqVOVar}.get${TreeParentJavaField}());
// 校验${treeNameColumn.columnComment}的唯一性
validate${simpleClassName}${TreeNameJavaField}Unique(null, ${saveReqVOVar}.get${TreeParentJavaField}(), ${saveReqVOVar}.get${TreeNameJavaField}());
#end
// 插入
#if ($voType == 10)
## TODO @puhui999insert 也要加下 clean。万一前端乱传递哈哈哈。这个就是 do 模式的缺点;(只在 do 模式下看看主子表是不是也可能存在insert 的时候;
${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class);
#end
${classNameVar}Mapper.insert(${classNameVar});
## 特殊:主子表专属逻辑(非 ERP 模式)
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
// 插入子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#if ( $subTable.subJoinMany)
create${subSimpleClassName}List(${classNameVar}.getId(), ${saveReqVOVar}.get${subSimpleClassNames.get($index)}s());
#else
create${subSimpleClassName}(${classNameVar}.getId(), ${saveReqVOVar}.get${subSimpleClassNames.get($index)}());
#end
#end
#end
// 返回
return BeanUtils.toBean(${classNameVar}, ${respVOClass}.class);
}
@Override
## 特殊:主子表专属逻辑(非 ERP 模式)
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
@Transactional(rollbackFor = Exception.class)
#end
public void update${simpleClassName}(${updateReqVOClass} ${updateReqVOVar}) {
// 校验存在
validate${simpleClassName}Exists(${updateReqVOVar}.getId());
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
// 校验${treeParentColumn.columnComment}的有效性
validateParent${simpleClassName}(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${TreeParentJavaField}());
// 校验${treeNameColumn.columnComment}的唯一性
validate${simpleClassName}${TreeNameJavaField}Unique(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${TreeParentJavaField}(), ${updateReqVOVar}.get${TreeNameJavaField}());
#end
// 更新
#if ($voType == 10)
${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class);
${classNameVar}Mapper.updateById(updateObj);
#else
${classNameVar}Mapper.updateById(${updateReqVOVar});
#end
## 特殊:主子表专属逻辑(非 ERP 模式)
#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11)
// 更新子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#if ( $subTable.subJoinMany)
update${subSimpleClassName}List(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${subSimpleClassNames.get($index)}s());
#else
update${subSimpleClassName}(${updateReqVOVar}.getId(), ${updateReqVOVar}.get${subSimpleClassNames.get($index)}());
#end
#end
#end
}
@Override
## 特殊:主子表专属逻辑
#if ( $subTables && $subTables.size() > 0)
@Transactional(rollbackFor = Exception.class)
#end
public void delete${simpleClassName}(${primaryColumn.javaType} id) {
// 校验存在
validate${simpleClassName}Exists(id);
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
#set ($ParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
// 校验是否有子${table.classComment}
if (${classNameVar}Mapper.selectCountBy${ParentJavaField}(id) > 0) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN);
}
#end
// 删除
${classNameVar}Mapper.deleteById(id);
## 特殊:主子表专属逻辑
#if ( $subTables && $subTables.size() > 0)
// 删除子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
delete${subSimpleClassName}By${SubJoinColumnName}(id);
#end
#end
}
#if ( $table.templateType != 2 && $deleteBatchEnable)
@Override
## 特殊:主子表专属逻辑
#if ( $subTables && $subTables.size() > 0)
@Transactional(rollbackFor = Exception.class)
#end
public void delete${simpleClassName}ListByIds(List<${primaryColumn.javaType}> ids) {
// 校验存在
validate${simpleClassName}Exists(ids);
// 删除
${classNameVar}Mapper.deleteByIds(ids);
## 特殊:主子表专属逻辑
#if ( $subTables && $subTables.size() > 0)
// 删除子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
delete${subSimpleClassName}By${SubJoinColumnName}s(ids);
#end
#end
}
private void validate${simpleClassName}Exists(List<${primaryColumn.javaType}> ids) {
List<${table.className}DO> list = ${classNameVar}Mapper.selectByIds(ids);
if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
}
}
#end
private void validate${simpleClassName}Exists(${primaryColumn.javaType} id) {
if (${classNameVar}Mapper.selectById(id) == null) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
}
}
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
private void validateParent${simpleClassName}(Long id, Long ${treeParentColumn.javaField}) {
if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
return;
}
// 1. 不能设置自己为父${table.classComment}
if (Objects.equals(id, ${treeParentColumn.javaField})) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR);
}
// 2. 父${table.classComment}不存在
${simpleClassName}DO parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
if (parent${simpleClassName} == null) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS);
}
// 3. 递归校验父${table.classComment},如果父${table.classComment}是自己的子${table.classComment},则报错,避免形成环路
if (id == null) { // id 为空,说明新增,不需要考虑环路
return;
}
for (int i = 0; i < Short.MAX_VALUE; i++) {
// 3.1 校验环路
${treeParentColumn.javaField} = parent${simpleClassName}.get${TreeParentJavaField}();
if (Objects.equals(id, ${treeParentColumn.javaField})) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD);
}
// 3.2 继续递归下一级父${table.classComment}
if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
break;
}
parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
if (parent${simpleClassName} == null) {
break;
}
}
}
private void validate${simpleClassName}${TreeNameJavaField}Unique(Long id, Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) {
${simpleClassName}DO ${classNameVar} = ${classNameVar}Mapper.selectBy${TreeParentJavaField}And${TreeNameJavaField}(${treeParentColumn.javaField}, ${treeNameColumn.javaField});
if (${classNameVar} == null) {
return;
}
// 如果 id 为空,说明不用比较是否为相同 id 的${table.classComment}
if (id == null) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
}
if (!Objects.equals(${classNameVar}.getId(), id)) {
throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
}
}
#end
@Override
public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
return ${classNameVar}Mapper.selectById(id);
}
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
@Override
public PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) {
return ${classNameVar}Mapper.selectPage(pageReqVO);
}
#else
@Override
public List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) {
return ${classNameVar}Mapper.selectList(listReqVO);
}
#end
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subClassNameVar = $subClassNameVars.get($index))
// ==================== 子表($subTable.classComment ====================
## 情况一MASTER_ERP 时,需要分查询页子表
#if ( $table.templateType == 11 )
@Override
public PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return ${subClassNameVars.get($index)}Mapper.selectPage(pageReqVO, ${subJoinColumn.javaField});
}
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ( $subTable.subJoinMany )
@Override
public List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return ${subClassNameVars.get($index)}Mapper.selectListBy${SubJoinColumnName}(${subJoinColumn.javaField});
}
#else
@Override
public ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
return ${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subJoinColumn.javaField});
}
#end
#end
## 情况一MASTER_ERP 时,支持单个的新增、修改、删除操作
#if ( $table.templateType == 11 )
@Override
public ${subPrimaryColumn.javaType} create${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) {
## 特殊:一对一时,需要保证只有一条,不能重复插入
#if ( !$subTable.subJoinMany)
// 校验是否已经存在
if (${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subClassNameVar}.get${SubJoinColumnName}()) != null) {
throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS);
}
// 插入
#end
${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar});
return ${subClassNameVar}.getId();
}
@Override
public void update${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) {
// 校验存在
validate${subSimpleClassName}Exists(${subClassNameVar}.getId());
// 更新
${subClassNameVar}.clean(); // 解决更新情况下updateTime 不更新
${subClassNameVars.get($index)}Mapper.updateById(${subClassNameVar});
}
@Override
public void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id) {
// 删除
${subClassNameVars.get($index)}Mapper.deleteById(id);
}
#if ($deleteBatchEnable)
@Override
public void delete${subSimpleClassName}ListByIds(List<${subPrimaryColumn.javaType}> ids) {
// 删除
${subClassNameVars.get($index)}Mapper.deleteByIds(ids);
}
#end
@Override
public ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id) {
return ${subClassNameVars.get($index)}Mapper.selectById(id);
}
private void validate${subSimpleClassName}Exists(${subPrimaryColumn.javaType} id) {
if (${subClassNameVar}Mapper.selectById(id) == null) {
throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS);
}
}
## 情况二:非 MASTER_ERP 时,支持批量的新增、修改操作
#else
#if ( $subTable.subJoinMany)
private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) {
list.forEach(o -> o.set${SubJoinColumnName}(${subJoinColumn.javaField}).clean());
${subClassNameVars.get($index)}Mapper.insertBatch(list);
}
private void update${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) {
list.forEach(o -> o.set${SubJoinColumnName}(${subJoinColumn.javaField}).clean());
List<${subTable.className}DO> oldList = ${subClassNameVar}Mapper.selectListBy${SubJoinColumnName}(${subJoinColumn.javaField});
List<List<${subTable.className}DO>> diffList = diffList(oldList, list, (oldVal, newVal) -> {
boolean same = ObjectUtil.equal(oldVal.getId(), newVal.getId());
if (same) {
newVal.setId(oldVal.getId()).clean(); // 解决更新情况下updateTime 不更新
}
return same;
});
// 第二步,批量添加、修改、删除
if (CollUtil.isNotEmpty(diffList.get(0))) {
${subClassNameVar}Mapper.insertBatch(diffList.get(0));
}
if (CollUtil.isNotEmpty(diffList.get(1))) {
${subClassNameVar}Mapper.updateBatch(diffList.get(1));
}
if (CollUtil.isNotEmpty(diffList.get(2))) {
${subClassNameVar}Mapper.deleteByIds(convertList(diffList.get(2), ${subTable.className}DO::getId));
}
}
#else
private void create${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) {
if (${subClassNameVar} == null) {
return;
}
${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField});
${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar});
}
private void update${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) {
if (${subClassNameVar} == null) {
return;
}
${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField}).clean();// 解决更新情况下updateTime 不更新
${subClassNameVars.get($index)}Mapper.insertOrUpdate(${subClassNameVar});
}
#end
#end
private void delete${subSimpleClassName}By${SubJoinColumnName}(${primaryColumn.javaType} ${subJoinColumn.javaField}) {
${subClassNameVars.get($index)}Mapper.deleteBy${SubJoinColumnName}(${subJoinColumn.javaField});
}
#if ( $table.templateType != 2 && $deleteBatchEnable)
private void delete${subSimpleClassName}By${SubJoinColumnName}s(List<${primaryColumn.javaType}> ${subJoinColumn.javaField}s) {
${subClassNameVars.get($index)}Mapper.deleteBy${SubJoinColumnName}s(${subJoinColumn.javaField}s);
}
#end
#end
}

View File

@@ -0,0 +1,168 @@
package ${basePackage}.module.${table.moduleName}.service.${table.businessName};
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import ${jakartaPackage}.annotation.Resource;
import ${baseFrameworkPackage}.test.core.ut.BaseDbUnitTest;
import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
import ${basePackage}.module.${table.moduleName}.dal.dao.${table.businessName}.${table.className}Mapper;
import ${PageResultClassName};
import ${jakartaPackage}.annotation.Resource;
import org.springframework.context.annotation.Import;
import java.util.*;
import java.time.LocalDateTime;
import static cn.hutool.core.util.RandomUtil.*;
import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*;
import static ${baseFrameworkPackage}.test.core.util.AssertUtils.*;
import static ${baseFrameworkPackage}.test.core.util.RandomUtils.*;
import static ${LocalDateTimeUtilsClassName}.*;
import static ${ObjectUtilsClassName}.*;
import static ${DateUtilsClassName}.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
## 字段模板
#macro(getPageCondition $VO)
// mock 数据
${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class, o -> { // 等会查询到
#foreach ($column in $columns)
#if (${column.listOperation})
#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写
o.set$JavaField(null);
#end
#end
});
${classNameVar}Mapper.insert(db${simpleClassName});
#foreach ($column in $columns)
#if (${column.listOperation})
#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写
// 测试 ${column.javaField} 不匹配
${classNameVar}Mapper.insert(cloneIgnoreId(db${simpleClassName}, o -> o.set$JavaField(null)));
#end
#end
// 准备参数
${sceneEnum.prefixClass}${table.className}${VO} reqVO = new ${sceneEnum.prefixClass}${table.className}${VO}();
#foreach ($column in $columns)
#if (${column.listOperation})
#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写
#if (${column.listOperationCondition} == "BETWEEN")## BETWEEN 的情况
reqVO.set${JavaField}(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
#else
reqVO.set$JavaField(null);
#end
#end
#end
#end
/**
* {@link ${table.className}ServiceImpl} 的单元测试类
*
* @author ${table.author}
*/
@Import(${table.className}ServiceImpl.class)
public class ${table.className}ServiceImplTest extends BaseDbUnitTest {
@Resource
private ${table.className}ServiceImpl ${classNameVar}Service;
@Resource
private ${table.className}Mapper ${classNameVar}Mapper;
@Test
public void testCreate${simpleClassName}_success() {
// 准备参数
${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class).setId(null);
// 调用
${primaryColumn.javaType} ${classNameVar}Id = ${classNameVar}Service.create${simpleClassName}(createReqVO);
// 断言
assertNotNull(${classNameVar}Id);
// 校验记录的属性是否正确
${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(${classNameVar}Id);
assertPojoEquals(createReqVO, ${classNameVar}, "id");
}
@Test
public void testUpdate${simpleClassName}_success() {
// mock 数据
${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class);
${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据
// 准备参数
${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class, o -> {
o.setId(db${simpleClassName}.getId()); // 设置更新的 ID
});
// 调用
${classNameVar}Service.update${simpleClassName}(updateReqVO);
// 校验是否更新正确
${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(updateReqVO.getId()); // 获取最新的
assertPojoEquals(updateReqVO, ${classNameVar});
}
@Test
public void testUpdate${simpleClassName}_notExists() {
// 准备参数
${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> ${classNameVar}Service.update${simpleClassName}(updateReqVO), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
}
@Test
public void testDelete${simpleClassName}_success() {
// mock 数据
${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class);
${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据
// 准备参数
${primaryColumn.javaType} id = db${simpleClassName}.getId();
// 调用
${classNameVar}Service.delete${simpleClassName}(id);
// 校验数据不存在了
assertNull(${classNameVar}Mapper.selectById(id));
}
@Test
public void testDelete${simpleClassName}_notExists() {
// 准备参数
${primaryColumn.javaType} id = random${primaryColumn.javaType}Id();
// 调用, 并断言异常
assertServiceException(() -> ${classNameVar}Service.delete${simpleClassName}(id), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
}
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
@Test
@Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
public void testGet${simpleClassName}Page() {
#getPageCondition("PageReqVO")
// 调用
PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(db${simpleClassName}, pageResult.getList().get(0));
}
#else
@Test
@Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
public void testGet${simpleClassName}List() {
#getPageCondition("ListReqVO")
// 调用
List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(reqVO);
// 断言
assertEquals(1, list.size());
assertPojoEquals(db${simpleClassName}, list.get(0));
}
#end
}

View File

@@ -0,0 +1,37 @@
-- 将该建表 SQL 语句,添加到 cloud-module-${table.moduleName}-biz 模块的 test/resources/sql/create_tables.sql 文件里
CREATE TABLE IF NOT EXISTS "${table.tableName.toLowerCase()}" (
#foreach ($column in $columns)
#if (${column.javaType} == 'Long')
#set ($dataType='bigint')
#elseif (${column.javaType} == 'Integer')
#set ($dataType='int')
#elseif (${column.javaType} == 'Boolean')
#set ($dataType='bit')
#elseif (${column.javaType} == 'Date')
#set ($dataType='datetime')
#else
#set ($dataType='varchar')
#end
#if (${column.primaryKey})##处理主键
"${column.javaField}"#if (${column.javaType} == 'String') ${dataType} NOT NULL#else ${dataType} NOT NULL GENERATED BY DEFAULT AS IDENTITY#end,
#else
#if (${column.columnName} == 'create_time')
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
#elseif (${column.columnName} == 'update_time')
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
#elseif (${column.columnName} == 'creator' || ${column.columnName} == 'updater')
"${column.columnName}" ${dataType} DEFAULT '',
#elseif (${column.columnName} == 'deleted')
"deleted" bit NOT NULL DEFAULT FALSE,
#elseif (${column.columnName} == 'tenant_id')
"tenant_id" bigint NOT NULL DEFAULT 0,
#else
"${column.columnName.toLowerCase()}" ${dataType}#if (${column.nullable} == false) NOT NULL#end,
#end
#end
#end
PRIMARY KEY ("${primaryColumn.columnName.toLowerCase()}")
) COMMENT '${table.tableComment}';
-- 将该删表 SQL 语句,添加到 cloud-module-${table.moduleName}-biz 模块的 test/resources/sql/clean.sql 文件里
DELETE FROM "${table.tableName}";

View File

@@ -0,0 +1,29 @@
-- 菜单 SQL
INSERT INTO system_menu(
id, name, permission, type, sort, parent_id,
path, icon, component, status, component_name
)
VALUES (
'${table.id}', '${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
'${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
);
-- 按钮父菜单ID
-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
-- SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
#set ($functionNames = ['查询', '创建', '更新', '删除', '导出'])
#set ($functionOps = ['query', 'create', 'update', 'delete', 'export'])
#foreach ($functionName in $functionNames)
#set ($index = $foreach.count - 1)
INSERT INTO system_menu(
id, name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'${functionIds.get($index)}', '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, ${table.id},
'', '', '', 0
);
#end

View File

@@ -0,0 +1,141 @@
import request from '@/utils/request'
#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
// 创建${table.classComment}
export function create${simpleClassName}(data) {
return request({
url: '${baseURL}/create',
method: 'post',
data: data
})
}
// 更新${table.classComment}
export function update${simpleClassName}(data) {
return request({
url: '${baseURL}/update',
method: 'put',
data: data
})
}
// 删除${table.classComment}
export function delete${simpleClassName}(id) {
return request({
url: '${baseURL}/delete?id=' + id,
method: 'delete'
})
}
// 获得${table.classComment}
export function get${simpleClassName}(id) {
return request({
url: '${baseURL}/get?id=' + id,
method: 'get'
})
}
#if ( $table.templateType != 2 )
// 获得${table.classComment}分页
export function get${simpleClassName}Page(params) {
return request({
url: '${baseURL}/page',
method: 'get',
params
})
}
#else
// 获得${table.classComment}列表
export function get${simpleClassName}List(params) {
return request({
url: '${baseURL}/list',
method: 'get',
params
})
}
#end
// 导出${table.classComment} Excel
export function export${simpleClassName}Excel(params) {
return request({
url: '${baseURL}/export-excel',
method: 'get',
params,
responseType: 'blob'
})
}
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
#set ($subClassNameVar = $subClassNameVars.get($index))
// ==================== 子表($subTable.classComment ====================
## 情况一MASTER_ERP 时,需要分查询页子表
#if ($table.templateType == 11)
// 获得${subTable.classComment}分页
export function get${subSimpleClassName}Page(params) {
return request({
url: '${baseURL}/${subSimpleClassName_strikeCase}/page',
method: 'get',
params
})
}
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ($subTable.subJoinMany)
// 获得${subTable.classComment}列表
export function get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}) {
return request({
url: '${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=' + ${subJoinColumn.javaField},
method: 'get'
})
}
#else
// 获得${subTable.classComment}
export function get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}) {
return request({
url: '${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=' + ${subJoinColumn.javaField},
method: 'get'
})
}
#end
#end
## 特殊MASTER_ERP 时,支持单个的新增、修改、删除操作
#if ($table.templateType == 11)
// 新增${subTable.classComment}
export function create${subSimpleClassName}(data) {
return request({
url: '${baseURL}/${subSimpleClassName_strikeCase}/create',
method: 'post',
data
})
}
// 修改${subTable.classComment}
export function update${subSimpleClassName}(data) {
return request({
url: '${baseURL}/${subSimpleClassName_strikeCase}/update',
method: 'post',
data
})
}
// 删除${subTable.classComment}
export function delete${subSimpleClassName}(id) {
return request({
url: '${baseURL}/${subSimpleClassName_strikeCase}/delete?id=' + id,
method: 'delete'
})
}
// 获得${subTable.classComment}
export function get${subSimpleClassName}(id) {
return request({
url: '${baseURL}/${subSimpleClassName_strikeCase}/get?id=' + id,
method: 'get'
})
}
#end
#end

View File

@@ -0,0 +1,205 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
<template>
<div class="app-container">
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="45%" v-dialogDrag append-to-body>
<el-form ref="formRef" :model="formData" :rules="formRules" v-loading="formLoading" label-width="100px">
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")## 图片上传
#set ($hasImageUploadColumn = true)
<el-form-item label="${comment}" prop="${javaField}">
<ImageUpload v-model="formData.${javaField}"/>
</el-form-item>
#elseif($column.htmlType == "fileUpload")## 文件上传
#set ($hasFileUploadColumn = true)
<el-form-item label="${comment}" prop="${javaField}">
<FileUpload v-model="formData.${javaField}"/>
</el-form-item>
#elseif($column.htmlType == "editor")## 文本编辑器
#set ($hasEditorColumn = true)
<el-form-item label="${comment}" prop="${javaField}">
<editor v-model="formData.${javaField}" :min-height="192"/>
</el-form-item>
#elseif($column.htmlType == "select")## 下拉框
<el-form-item label="${comment}" prop="${javaField}">
<el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" :label="dict.label" #if ($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end />
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox")## 多选框
<el-form-item label="${comment}" prop="${javaField}">
<el-checkbox-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end>{{dict.label}}</el-checkbox>
#else##没数据字典
<el-checkbox>请选择字典生成</el-checkbox>
#end
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio")## 单选框
<el-form-item label="${comment}" prop="${javaField}">
<el-radio-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"
#else:label="dict.value"#end>{{dict.label}}</el-radio>
#else##没数据字典
<el-radio label="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "datetime")## 时间框
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker clearable v-model="formData.${javaField}" type="date" value-format="timestamp" placeholder="选择${comment}" />
</el-form-item>
#elseif($column.htmlType == "textarea")## 文本框
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入内容" />
</el-form-item>
#end
#end
#end
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm" :disabled="formLoading">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}';
#if ($hasImageUploadColumn)
import ImageUpload from '@/components/ImageUpload';
#end
#if ($hasFileUploadColumn)
import FileUpload from '@/components/FileUpload';
#end
#if ($hasEditorColumn)
import Editor from '@/components/Editor';
#end
export default {
name: "${subSimpleClassName}Form",
components: {
#if ($hasImageUploadColumn)
ImageUpload,
#end
#if ($hasFileUploadColumn)
FileUpload,
#end
#if ($hasEditorColumn)
Editor,
#end
},
data() {
return {
// 弹出层标题
dialogTitle: "",
// 是否显示弹出层
dialogVisible: false,
// 表单的加载中1修改时的数据加载2提交的按钮禁用
formLoading: false,
// 表单参数
formData: {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
},
// 表单校验
formRules: {
#foreach ($column in $subColumns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: "${comment}不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }],
#end
#end
},
};
},
methods: {
/** 打开弹窗 */
async open(id, ${subJoinColumn.javaField}) {
this.dialogVisible = true;
this.reset();
this.formData.${subJoinColumn.javaField} = ${subJoinColumn.javaField};
// 修改时,设置数据
if (id) {
this.formLoading = true;
try {
const res = await ${simpleClassName}Api.get${subSimpleClassName}(id);
this.formData = res.data;
this.dialogTitle = "修改${subTable.classComment}";
} finally {
this.formLoading = false;
}
}
this.dialogTitle = "新增${subTable.classComment}";
},
/** 提交按钮 */
async submitForm() {
await this.#[[$]]#refs["formRef"].validate();
this.formLoading = true;
try {
const data = this.formData;
// 修改的提交
if (data.${primaryColumn.javaField}) {
await ${simpleClassName}Api.update${subSimpleClassName}(data);
this.#[[$modal]]#.msgSuccess("修改成功");
this.dialogVisible = false;
this.#[[$]]#emit('success');
return;
}
// 添加的提交
await ${simpleClassName}Api.create${subSimpleClassName}(data);
this.#[[$modal]]#.msgSuccess("新增成功");
this.dialogVisible = false;
this.#[[$]]#emit('success');
}finally {
this.formLoading = false;
}
},
/** 表单重置 */
reset() {
this.formData = {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
};
this.resetForm("formRef");
},
}
};
</script>

View File

@@ -0,0 +1,2 @@
## 主表的 normal 和 inner 使用相同的 form 表单
#parse("codegen/vue/views/components/form_sub_normal.vue.vm")

View File

@@ -0,0 +1,347 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<template>
<div class="app-container">
#if ( $subTable.subJoinMany )## 情况一一对多table + form
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
v-loading="formLoading"
label-width="0px"
:inline-message="true"
>
<el-table :data="formData" class="-mt-10px">
<el-table-column label="序号" type="index" width="100" />
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<el-table-column label="${comment}" min-width="150">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-input v-model="row.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "imageUpload")## 图片上传
#set ($hasImageUploadColumn = true)
<el-table-column label="${comment}" min-width="200">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<ImageUpload v-model="row.${javaField}"/>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "fileUpload")## 文件上传
#set ($hasFileUploadColumn = true)
<el-table-column label="${comment}" min-width="200">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<FileUpload v-model="row.${javaField}"/>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "editor")## 文本编辑器
#set ($hasEditorColumn = true)
<el-table-column label="${comment}" min-width="400">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<Editor v-model="row.${javaField}" :min-height="192"/>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "select")## 下拉框
<el-table-column label="${comment}" min-width="150">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-select v-model="row.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" :label="dict.label" #if ($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end />
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "checkbox")## 多选框
<el-table-column label="${comment}" min-width="150">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-checkbox-group v-model="row.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end>{{dict.label}}</el-checkbox>
#else##没数据字典
<el-checkbox>请选择字典生成</el-checkbox>
#end
</el-checkbox-group>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "radio")## 单选框
<el-table-column label="${comment}" min-width="150">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-radio-group v-model="row.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"
#else:label="dict.value"#end>{{dict.label}}</el-radio>
#else##没数据字典
<el-radio label="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "datetime")## 时间框
<el-table-column label="${comment}" min-width="150">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-date-picker clearable v-model="row.${javaField}" type="date" value-format="timestamp" placeholder="选择${comment}" />
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "textarea")## 文本框
<el-table-column label="${comment}" min-width="200">
<template v-slot="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-input v-model="row.${javaField}" type="textarea" placeholder="请输入${comment}" />
</el-form-item>
</template>
</el-table-column>
#end
#end
#end
<el-table-column align="center" fixed="right" label="操作" width="60">
<template v-slot="{ $index }">
<el-link @click="handleDelete($index)">—</el-link>
</template>
</el-table-column>
</el-table>
</el-form>
<el-row justify="center" class="mt-3">
<el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button>
</el-row>
#else## 情况二一对一form
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")## 图片上传
#set ($hasImageUploadColumn = true)
<el-form-item label="${comment}">
<ImageUpload v-model="formData.${javaField}"/>
</el-form-item>
#elseif($column.htmlType == "fileUpload")## 文件上传
#set ($hasFileUploadColumn = true)
<el-form-item label="${comment}">
<FileUpload v-model="formData.${javaField}"/>
</el-form-item>
#elseif($column.htmlType == "editor")## 文本编辑器
#set ($hasEditorColumn = true)
<el-form-item label="${comment}">
<Editor v-model="formData.${javaField}" :min-height="192"/>
</el-form-item>
#elseif($column.htmlType == "select")## 下拉框
<el-form-item label="${comment}" prop="${javaField}">
<el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" :label="dict.label" #if ($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end />
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox")## 多选框
<el-form-item label="${comment}" prop="${javaField}">
<el-checkbox-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end>{{dict.label}}</el-checkbox>
#else##没数据字典
<el-checkbox>请选择字典生成</el-checkbox>
#end
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio")## 单选框
<el-form-item label="${comment}" prop="${javaField}">
<el-radio-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"
#else:label="dict.value"#end>{{dict.label}}</el-radio>
#else##没数据字典
<el-radio label="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "datetime")## 时间框
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker clearable v-model="formData.${javaField}" type="date" value-format="timestamp" placeholder="选择${comment}" />
</el-form-item>
#elseif($column.htmlType == "textarea")## 文本框
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
</el-form-item>
#end
#end
#end
</el-form>
#end
</div>
</template>
<script>
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}';
#if ($hasImageUploadColumn)
import ImageUpload from '@/components/ImageUpload';
#end
#if ($hasFileUploadColumn)
import FileUpload from '@/components/FileUpload';
#end
#if ($hasEditorColumn)
import Editor from '@/components/Editor';
#end
export default {
name: "${subSimpleClassName}Form",
components: {
#if ($hasImageUploadColumn)
ImageUpload,
#end
#if ($hasFileUploadColumn)
FileUpload,
#end
#if ($hasEditorColumn)
Editor,
#end
},
props:[
'${subJoinColumn.javaField}'
],// ${subJoinColumn.columnComment}(主表的关联字段)
data() {
return {
// 表单的加载中1修改时的数据加载2提交的按钮禁用
formLoading: false,
// 表单参数
formData: [],
// 表单校验
formRules: {
#foreach ($column in $subColumns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: "${comment}不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }],
#end
#end
},
};
},
watch:{/** 监听主表的关联字段的变化,加载对应的子表数据 */
${subJoinColumn.javaField}:{
handler(val) {
// 1. 重置表单
#if ( $subTable.subJoinMany )
this.formData = []
#else
this.formData = {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
}
#end
// 2. val 非空,则加载数据
if (!val) {
return;
}
try {
this.formLoading = true;
// 这里还是需要获取一下 this 的不然取不到 formData
const that = this;
#if ( $subTable.subJoinMany )
${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(val).then(function (res){
that.formData = res.data;
})
#else
${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(val).then(function (res){
const data = res.data;
if (!data) {
return
}
that.formData = data;
})
#end
} finally {
this.formLoading = false;
}
},
immediate: true
}
},
methods: {
#if ( $subTable.subJoinMany )
/** 新增按钮操作 */
handleAdd() {
const row = {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
}
row.${subJoinColumn.javaField} = this.${subJoinColumn.javaField};
this.formData.push(row);
},
/** 删除按钮操作 */
handleDelete(index) {
this.formData.splice(index, 1);
},
#end
/** 表单校验 */
validate(){
return this.#[[$]]#refs["formRef"].validate();
},
/** 表单值 */
getData(){
return this.formData;
}
}
};
</script>

View File

@@ -0,0 +1,165 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<template>
<div class="app-container">
#if ($table.templateType == 11)
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openForm(undefined)"
v-hasPermi="['${permissionPrefix}:create']">新增</el-button>
</el-col>
</el-row>
#end
## 列表
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
#foreach($column in $subColumns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.javaType == "LocalDateTime")## 时间类型
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.${javaField}) }}</span>
</template>
</el-table-column>
#elseif($column.dictType && "" != $column.dictType)## 数据字典
<el-table-column label="${comment}" align="center" prop="${javaField}">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
</template>
</el-table-column>
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
#end
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="openForm(scope.row.${primaryColumn.javaField})"
v-hasPermi="['${permissionPrefix}:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['${permissionPrefix}:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
#if ($table.templateType == 11)
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 对话框(添加 / 修改) -->
<${subSimpleClassName}Form ref="formRef" @success="getList" />
#end
</div>
</template>
<script>
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}';
#if ($table.templateType == 11)
import ${subSimpleClassName}Form from './${subSimpleClassName}Form.vue';
#end
export default {
name: "${subSimpleClassName}List",
#if ($table.templateType == 11)
components: {
${subSimpleClassName}Form
},
#end
props:[
'${subJoinColumn.javaField}'
],// ${subJoinColumn.columnComment}(主表的关联字段)
data() {
return {
// 遮罩层
loading: true,
// 列表的数据
list: [],
#if ($table.templateType == 11)
// 列表的总页数
total: 0,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
${subJoinColumn.javaField}: undefined
}
#end
};
},
#if ($table.templateType != 11)
created() {
this.getList();
},
#end
watch:{/** 监听主表的关联字段的变化,加载对应的子表数据 */
${subJoinColumn.javaField}:{
handler(val) {
this.queryParams.${subJoinColumn.javaField} = val;
if (val){
this.handleQuery();
}
},
immediate: true
}
},
methods: {
/** 查询列表 */
async getList() {
try {
this.loading = true;
#if ($table.templateType == 11)
const res = await ${simpleClassName}Api.get${subSimpleClassName}Page(this.queryParams);
this.list = res.data.list;
this.total = res.data.total;
#else
#if ( $subTable.subJoinMany )
const res = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(this.${subJoinColumn.javaField});
this.list = res.data;
#else
const res = await ${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(this.${subJoinColumn.javaField});
const data = res.data;
if (!data) {
return;
}
this.list.push(data);
#end
#end
} finally {
this.loading = false;
}
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
#if ($table.templateType == 11)
/** 添加/修改操作 */
openForm(id) {
if (!this.${subJoinColumn.javaField}) {
this.#[[$modal]]#.msgError('请选择一个${table.classComment}');
return;
}
this.#[[$]]#refs["formRef"].open(id, this.${subJoinColumn.javaField});
},
/** 删除按钮操作 */
async handleDelete(row) {
const ${primaryColumn.javaField} = row.${primaryColumn.javaField};
await this.#[[$modal]]#.confirm('是否确认删除${table.classComment}编号为"' + ${primaryColumn.javaField} + '"的数据项?');
try {
await ${simpleClassName}Api.delete${subSimpleClassName}(${primaryColumn.javaField});
await this.getList();
this.#[[$modal]]#.msgSuccess("删除成功");
} catch {}
},
#end
}
};
</script>

View File

@@ -0,0 +1,4 @@
## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
## 1inner 使用 list 不分页erp 使用 page 分页
## 2erp 支持单个子表的新增、修改、删除inner 不支持
#parse("codegen/vue/views/components/list_sub_erp.vue.vm")

View File

@@ -0,0 +1,320 @@
<template>
<div class="app-container">
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="45%" v-dialogDrag append-to-body>
<el-form ref="formRef" :model="formData" :rules="formRules" v-loading="formLoading" label-width="100px">
#foreach($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
<el-form-item label="${comment}" prop="${javaField}">
<TreeSelect
v-model="formData.${javaField}"
:options="${classNameVar}Tree"
:normalizer="normalizer"
placeholder="请选择${comment}"
/>
</el-form-item>
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")## 图片上传
#set ($hasImageUploadColumn = true)
<el-form-item label="${comment}">
<ImageUpload v-model="formData.${javaField}"/>
</el-form-item>
#elseif($column.htmlType == "fileUpload")## 文件上传
#set ($hasFileUploadColumn = true)
<el-form-item label="${comment}">
<FileUpload v-model="formData.${javaField}"/>
</el-form-item>
#elseif($column.htmlType == "editor")## 文本编辑器
#set ($hasEditorColumn = true)
<el-form-item label="${comment}">
<Editor v-model="formData.${javaField}" :min-height="192"/>
</el-form-item>
#elseif($column.htmlType == "select")## 下拉框
<el-form-item label="${comment}" prop="${javaField}">
<el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" :label="dict.label" #if ($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end />
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox")## 多选框
<el-form-item label="${comment}" prop="${javaField}">
<el-checkbox-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end>{{dict.label}}</el-checkbox>
#else##没数据字典
<el-checkbox>请选择字典生成</el-checkbox>
#end
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio")## 单选框
<el-form-item label="${comment}" prop="${javaField}">
<el-radio-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"
#else:label="dict.value"#end>{{dict.label}}</el-radio>
#else##没数据字典
<el-radio label="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "datetime")## 时间框
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker clearable v-model="formData.${javaField}" type="date" value-format="timestamp" placeholder="选择${comment}" />
</el-form-item>
#elseif($column.htmlType == "textarea")## 文本框
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入内容" />
</el-form-item>
#end
#end
#end
</el-form>
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
<!-- 子表的表单 -->
<el-tabs v-model="subTabsName">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
<${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData.id" />
</el-tab-pane>
#end
</el-tabs>
#end
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm" :disabled="formLoading">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}';
#if ($hasImageUploadColumn)
import ImageUpload from '@/components/ImageUpload';
#end
#if ($hasFileUploadColumn)
import FileUpload from '@/components/FileUpload';
#end
#if ($hasEditorColumn)
import Editor from '@/components/Editor';
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
import TreeSelect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue'
#end
#end
export default {
name: "${simpleClassName}Form",
components: {
#if ($hasImageUploadColumn)
ImageUpload,
#end
#if ($hasFileUploadColumn)
FileUpload,
#end
#if ($hasEditorColumn)
Editor,
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
TreeSelect,
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
${subSimpleClassName}Form,
#end
#end
},
data() {
return {
// 弹出层标题
dialogTitle: "",
// 是否显示弹出层
dialogVisible: false,
// 表单的加载中1修改时的数据加载2提交的按钮禁用
formLoading: false,
// 表单参数
formData: {
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
},
// 表单校验
formRules: {
#foreach ($column in $columns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end
#end
},
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
${classNameVar}Tree: [], // 树形结构
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
/** 子表的表单 */
subTabsName: '$subClassNameVars.get(0)'
#end
#end
};
},
methods: {
/** 打开弹窗 */
async open(id) {
this.dialogVisible = true;
this.reset();
// 修改时,设置数据
if (id) {
this.formLoading = true;
try {
const res = await ${simpleClassName}Api.get${simpleClassName}(id);
this.formData = res.data;
this.title = "修改${table.classComment}";
} finally {
this.formLoading = false;
}
}
this.title = "新增${table.classComment}";
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
await this.get${simpleClassName}Tree();
#end
},
/** 提交按钮 */
async submitForm() {
// 校验主表
await this.$refs["formRef"].validate();
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
// 校验子表
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
try {
## 代码生成后会替换为正确的 refs
await this.refs['${subClassNameVar}FormRef'].validate();
} catch (e) {
this.subTabsName = '${subClassNameVar}';
return;
}
#end
#end
#end
this.formLoading = true;
try {
const data = this.formData;
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
// 拼接子表的数据
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
data.${subClassNameVar}#if ( $subTable.subJoinMany)s#end = this.refs['${subClassNameVar}FormRef'].getData();
#end
#end
#end
// 修改的提交
if (data.${primaryColumn.javaField}) {
await ${simpleClassName}Api.update${simpleClassName}(data);
this.#[[$modal]]#.msgSuccess("修改成功");
this.dialogVisible = false;
this.#[[$]]#emit('success');
return;
}
// 添加的提交
await ${simpleClassName}Api.create${simpleClassName}(data);
this.#[[$modal]]#.msgSuccess("新增成功");
this.dialogVisible = false;
this.#[[$]]#emit('success');
} finally {
this.formLoading = false;
}
},
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
/** 获得${table.classComment}树 */
async get${simpleClassName}Tree() {
this.${classNameVar}Tree = [];
const res = await ${simpleClassName}Api.get${simpleClassName}List();
const root = { id: 0, name: '顶级${table.classComment}', children: [] };
root.children = this.handleTree(res.data, 'id', '${treeParentColumn.javaField}')
this.${classNameVar}Tree.push(root)
},
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
/** 转换${table.classComment}数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
#if ($treeNameColumn.javaField == "name")
return {
id: node.id,
label: node.name,
children: node.children
};
#else
return {
id: node.id,
label: node['$treeNameColumn.javaField'],
children: node.children
};
#end
},
#end
/** 表单重置 */
reset() {
this.formData = {
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
};
this.resetForm("formRef");
}
}
};
</script>

View File

@@ -0,0 +1,340 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns)
#if ($column.listOperation)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($column.htmlType == "input")
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="queryParams.${javaField}" placeholder="请输入${comment}" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
#elseif ($column.htmlType == "select" || $column.htmlType == "radio")
<el-form-item label="${comment}" prop="${javaField}">
<el-select v-model="queryParams.${javaField}" placeholder="请选择${comment}" clearable size="small">
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value" :label="dict.label" :value="dict.value"/>
#else## 未设置 dictType 数据字典的情况
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "datetime")
#if ($column.listOperationCondition != "BETWEEN")## 非范围
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker clearable v-model="queryParams.${javaField}" type="date" value-format="yyyy-MM-dd" placeholder="选择${comment}" />
</el-form-item>
#else## 范围
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker v-model="queryParams.${javaField}" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
#end
#end
#end
#end
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openForm(undefined)"
v-hasPermi="['${permissionPrefix}:create']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
v-hasPermi="['${permissionPrefix}:export']">导出</el-button>
</el-col>
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">
展开/折叠
</el-button>
</el-col>
#end
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:highlight-current-row="true"
:show-overflow-tooltip="true"
@current-change="handleCurrentChange"
>
## 特殊:树表专属逻辑
#elseif ( $table.templateType == 2 )
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
v-if="refreshTable"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
#else
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
<!-- 子表的列表 -->
<el-table-column type="expand">
<template #default="scope">
<el-tabs value="$subClassNameVars.get(0)">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
<${subSimpleClassName}List :${subJoinColumn_strikeCase}="scope.row.id" />
</el-tab-pane>
#end
</el-tabs>
</template>
</el-table-column>
#end
#foreach($column in $columns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.${javaField}) }}</span>
</template>
</el-table-column>
#elseif("" != $column.dictType)## 数据字典
<el-table-column label="${comment}" align="center" prop="${javaField}">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
</template>
</el-table-column>
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
#end
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="openForm(scope.row.${primaryColumn.javaField})"
v-hasPermi="['${permissionPrefix}:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['${permissionPrefix}:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
## 特殊:树表专属逻辑(树不需要分页)
#if ( $table.templateType != 2 )
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
#end
<!-- 对话框(添加 / 修改) -->
<${simpleClassName}Form ref="formRef" @success="getList" />
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
<!-- 子表的列表 -->
<el-tabs v-model="subTabsName">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
<${subSimpleClassName}List v-if="currentRow.id" :${subJoinColumn_strikeCase}="currentRow.id" />
</el-tab-pane>
#end
</el-tabs>
#end
</div>
</template>
<script>
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}';
import ${simpleClassName}Form from './${simpleClassName}Form.vue';
#if ($hasImageUploadColumn)
import ImageUpload from '@/components/ImageUpload';
#end
#if ($hasFileUploadColumn)
import FileUpload from '@/components/FileUpload';
#end
#if ($hasEditorColumn)
import Editor from '@/components/Editor';
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType != 10 )
#if ( $subTables && $subTables.size() > 0 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
import ${subSimpleClassName}List from './components/${subSimpleClassName}List.vue';
#end
#end
#end
export default {
name: "${simpleClassName}",
components: {
${simpleClassName}Form,
## 特殊:主子表专属逻辑
#if ( $table.templateType != 10 )
#if ( $subTables && $subTables.size() > 0 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
${subSimpleClassName}List,
#end
#end
#end
#if ($hasImageUploadColumn)
ImageUpload,
#end
#if ($hasFileUploadColumn)
FileUpload,
#end
#if ($hasEditorColumn)
Editor,
#end
},
data() {
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 显示搜索条件
showSearch: true,
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
// 总条数
total: 0,
#end
// ${table.classComment}列表
list: [],
// 是否展开,默认全部展开
isExpandAll: true,
// 重新渲染表格状态
refreshTable: true,
// 选中行
currentRow: {},
// 查询参数
queryParams: {
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
pageNo: 1,
pageSize: 10,
#end
#foreach ($column in $columns)
#if ($column.listOperation)
#if ($column.listOperationCondition != 'BETWEEN')
$column.javaField: null,
#end
#if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN")
$column.javaField: [],
#end
#end
#end
},
## 特殊:主子表专属逻辑-erp
#if ( $table.templateType == 11)
#if ( $subTables && $subTables.size() > 0 )
/** 子表的列表 */
subTabsName: '$subClassNameVars.get(0)'
#end
#end
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
async getList() {
try {
this.loading = true;
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType == 2 )
const res = await ${simpleClassName}Api.get${simpleClassName}List(this.queryParams);
this.list = this.handleTree(res.data, 'id', '${treeParentColumn.javaField}');
#else
const res = await ${simpleClassName}Api.get${simpleClassName}Page(this.queryParams);
this.list = res.data.list;
this.total = res.data.total;
#end
} finally {
this.loading = false;
}
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 添加/修改操作 */
openForm(id) {
this.#[[$]]#refs["formRef"].open(id);
},
/** 删除按钮操作 */
async handleDelete(row) {
const ${primaryColumn.javaField} = row.${primaryColumn.javaField};
await this.#[[$modal]]#.confirm('是否确认删除${table.classComment}编号为"' + ${primaryColumn.javaField} + '"的数据项?')
try {
await ${simpleClassName}Api.delete${simpleClassName}(${primaryColumn.javaField});
await this.getList();
this.#[[$modal]]#.msgSuccess("删除成功");
} catch {}
},
/** 导出按钮操作 */
async handleExport() {
await this.#[[$modal]]#.confirm('是否确认导出所有${table.classComment}数据项?');
try {
this.exportLoading = true;
const data = await ${simpleClassName}Api.export${simpleClassName}Excel(this.queryParams);
this.#[[$]]#download.excel(data, '${table.classComment}.xls');
} catch {
} finally {
this.exportLoading = false;
}
},
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 )
/** 选中行操作 */
handleCurrentChange(row) {
this.currentRow = row;
#if ( $subTables && $subTables.size() > 0 )
/** 子表的列表 */
this.subTabsName = '$subClassNameVars.get(0)';
#end
},
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false
this.isExpandAll = !this.isExpandAll
this.$nextTick(function () {
this.refreshTable = true
})
}
#end
}
};
</script>

View File

@@ -0,0 +1,141 @@
import request from '@/config/axios'
#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
// ${table.classComment} VO
export interface ${simpleClassName}VO {
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
${column.javaField}: number // ${column.columnComment}
#elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
${column.javaField}: Date // ${column.columnComment}
#else
${column.javaField}: ${column.javaType.toLowerCase()} // ${column.columnComment}
#end
#end
#end
}
## 主键类型动态生成,优先查找列名为 id 的类型,找不到则默认 string
#set($idType = "string")
#foreach($column in $columns)
#if($column.javaField == "id")
#if($column.javaType.toLowerCase() == "long" || $column.javaType.toLowerCase() == "integer" || $column.javaType.toLowerCase() == "short" || $column.javaType.toLowerCase() == "double" || $column.javaType.toLowerCase() == "bigdecimal")
#set($idType = "number")
#end
#end
#end
type IdType = $idType;
// ${table.classComment} API
export const ${simpleClassName}Api = {
#if ( $table.templateType != 2 )
// 查询${table.classComment}分页
get${simpleClassName}Page: async (params: any) => {
return await request.get({ url: `${baseURL}/page`, params })
},
#else
// 查询${table.classComment}列表
get${simpleClassName}List: async (params) => {
return await request.get({ url: `${baseURL}/list`, params })
},
#end
// 查询${table.classComment}详情
get${simpleClassName}: async (id: IdType) => {
return await request.get({ url: `${baseURL}/get?id=` + id })
},
// 新增${table.classComment}
create${simpleClassName}: async (data: ${simpleClassName}VO) => {
return await request.post({ url: `${baseURL}/create`, data })
},
// 修改${table.classComment}
update${simpleClassName}: async (data: ${simpleClassName}VO) => {
return await request.put({ url: `${baseURL}/update`, data })
},
// 删除${table.classComment}
delete${simpleClassName}: async (id: IdType) => {
return await request.delete({ url: `${baseURL}/delete?id=` + id })
},
// 批量删除${table.classComment}
delete${simpleClassName}List: async (ids: IdType[]) => {
return await request.delete({
url: `${baseURL}/delete-list`,
data: { ids }
})
},
// 导出${table.classComment} Excel
export${simpleClassName}: async (params) => {
return await request.download({ url: `${baseURL}/export-excel`, params })
},
#if($isFileUpload && $isFileUpload == true)
// 查询接口相关的文件上传元数据信息
getFileUploadInfo: async () => {
return await request.get({url: `${baseURL}/upload-info`})
},
#end
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
#set ($subClassNameVar = $subClassNameVars.get($index))
// ==================== 子表($subTable.classComment ====================
## 情况一MASTER_ERP 时,需要分查询页子表
#if ( $table.templateType == 11 )
// 获得${subTable.classComment}分页
get${subSimpleClassName}Page: async (params) => {
return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/page`, params })
},
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ( $subTable.subJoinMany )
// 获得${subTable.classComment}列表
get${subSimpleClassName}ListBy${SubJoinColumnName}: async (${subJoinColumn.javaField}) => {
return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} })
},
#else
// 获得${subTable.classComment}
get${subSimpleClassName}By${SubJoinColumnName}: async (${subJoinColumn.javaField}) => {
return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} })
},
#end
#end
## 特殊MASTER_ERP 时,支持单个的新增、修改、删除操作
#if ( $table.templateType == 11 )
// 新增${subTable.classComment}
create${subSimpleClassName}: async (data) => {
return await request.post({ url: `${baseURL}/${subSimpleClassName_strikeCase}/create`, data })
},
// 修改${subTable.classComment}
update${subSimpleClassName}: async (data) => {
return await request.put({ url: `${baseURL}/${subSimpleClassName_strikeCase}/update`, data })
},
// 删除${subTable.classComment}
delete${subSimpleClassName}: async (id: IdType) => {
return await request.delete({ url: `${baseURL}/${subSimpleClassName_strikeCase}/delete?id=` + id })
},
// 获得${subTable.classComment}
get${subSimpleClassName}: async (id: IdType) => {
return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get?id=` + id })
},
#end
#end
}

View File

@@ -0,0 +1,204 @@
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "getIntDictOptions")
#elseif ($javaType == "String")
#set ($dictMethod = "getStrDictOptions")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "getBoolDictOptions")
#end
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")## 图片上传
<el-form-item label="${comment}" prop="${javaField}">
<UploadImg v-model="formData.${javaField}" />
</el-form-item>
#elseif($column.htmlType == "fileUpload")## 文件上传
<el-form-item label="${comment}" prop="${javaField}">
<UploadFile v-model="formData.${javaField}" />
</el-form-item>
#elseif($column.htmlType == "editor")## 文本编辑器
<el-form-item label="${comment}" prop="${javaField}">
<Editor v-model="formData.${javaField}" height="150px" />
</el-form-item>
#elseif($column.htmlType == "select")## 下拉框
<el-form-item label="${comment}" prop="${javaField}">
<el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox")## 多选框
<el-form-item label="${comment}" prop="${javaField}">
<el-checkbox-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-checkbox label="请选择字典生成" />
#end
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio")## 单选框
<el-form-item label="${comment}" prop="${javaField}">
<el-radio-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
#else##没数据字典
<el-radio value="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "datetime")## 时间框
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker
v-model="formData.${javaField}"
type="date"
value-format="x"
placeholder="选择${comment}"
/>
</el-form-item>
#elseif($column.htmlType == "textarea")## 文本框
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
</el-form-item>
#end
#end
#end
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { ${simpleClassName}Api } from '@/api/${table.moduleName}/${table.businessName}'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
})
const formRules = reactive({
#foreach ($column in $subColumns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end
#end
})
const formRef = ref() // 表单 Ref
/** 打开弹窗 */
const open = async (type: string, id?: number, ${subJoinColumn.javaField}: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
formData.value.${subJoinColumn.javaField} = ${subJoinColumn.javaField}
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
formData.value = await ${simpleClassName}Api.get${subSimpleClassName}(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
// 校验表单
await formRef.value.validate()
// 提交请求
formLoading.value = true
try {
const data = formData.value
if (formType.value === 'create') {
await ${simpleClassName}Api.create${subSimpleClassName}(data)
message.success(t('common.createSuccess'))
} else {
await ${simpleClassName}Api.update${subSimpleClassName}(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
}
formRef.value?.resetFields()
}
</script>

View File

@@ -0,0 +1,2 @@
## 主表的 normal 和 inner 使用相同的 form 表单
#parse("codegen/vue3/views/components/form_sub_normal.vue.vm")

View File

@@ -0,0 +1,360 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<template>
#if ( $subTable.subJoinMany )## 情况一一对多table + form
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
v-loading="formLoading"
label-width="0px"
:inline-message="true"
>
<el-table :data="formData" class="-mt-10px">
<el-table-column label="序号" type="index" width="100" />
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "getIntDictOptions")
#elseif ($javaType == "String")
#set ($dictMethod = "getStrDictOptions")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "getBoolDictOptions")
#end
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<el-table-column label="${comment}" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-input v-model="row.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "imageUpload")## 图片上传
<el-table-column label="${comment}" min-width="200">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<UploadImg v-model="row.${javaField}" />
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "fileUpload")## 文件上传
<el-table-column label="${comment}" min-width="200">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<UploadFile v-model="row.${javaField}" />
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "editor")## 文本编辑器
<el-table-column label="${comment}" min-width="400">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<Editor v-model="row.${javaField}" height="150px" />
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "select")## 下拉框
<el-table-column label="${comment}" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-select v-model="row.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "checkbox")## 多选框
<el-table-column label="${comment}" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-checkbox-group v-model="row.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-checkbox label="请选择字典生成" />
#end
</el-checkbox-group>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "radio")## 单选框
<el-table-column label="${comment}" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-radio-group v-model="row.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
#else##没数据字典
<el-radio value="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "datetime")## 时间框
<el-table-column label="${comment}" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-date-picker
v-model="row.${javaField}"
type="date"
value-format="x"
placeholder="选择${comment}"
/>
</el-form-item>
</template>
</el-table-column>
#elseif($column.htmlType == "textarea")## 文本框
<el-table-column label="${comment}" min-width="200">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
<el-input v-model="row.${javaField}" type="textarea" placeholder="请输入${comment}" />
</el-form-item>
</template>
</el-table-column>
#end
#end
#end
<el-table-column align="center" fixed="right" label="操作" width="60">
<template #default="{ $index }">
<el-button @click="handleDelete($index)" link>—</el-button>
</template>
</el-table-column>
</el-table>
</el-form>
<el-row justify="center" class="mt-3">
<el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button>
</el-row>
#else## 情况二一对一form
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "getIntDictOptions")
#elseif ($javaType == "String")
#set ($dictMethod = "getStrDictOptions")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "getBoolDictOptions")
#end
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")## 图片上传
<el-form-item label="${comment}" prop="${javaField}">
<UploadImg v-model="formData.${javaField}" />
</el-form-item>
#elseif($column.htmlType == "fileUpload")## 文件上传
<el-form-item label="${comment}" prop="${javaField}">
<UploadFile v-model="formData.${javaField}" />
</el-form-item>
#elseif($column.htmlType == "editor")## 文本编辑器
<el-form-item label="${comment}" prop="${javaField}">
<Editor v-model="formData.${javaField}" height="150px" />
</el-form-item>
#elseif($column.htmlType == "select")## 下拉框
<el-form-item label="${comment}" prop="${javaField}">
<el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox")## 多选框
<el-form-item label="${comment}" prop="${javaField}">
<el-checkbox-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-checkbox label="请选择字典生成" />
#end
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio")## 单选框
<el-form-item label="${comment}" prop="${javaField}">
<el-radio-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
#else##没数据字典
<el-radio value="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "datetime")## 时间框
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker
v-model="formData.${javaField}"
type="date"
value-format="x"
placeholder="选择${comment}"
/>
</el-form-item>
#elseif($column.htmlType == "textarea")## 文本框
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
</el-form-item>
#end
#end
#end
</el-form>
#end
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { ${simpleClassName}Api } from '@/api/${table.moduleName}/${table.businessName}'
const props = defineProps<{
${subJoinColumn.javaField}: undefined // ${subJoinColumn.columnComment}(主表的关联字段)
}>()
const formLoading = ref(false) // 表单的加载中
const formData = ref([])
const formRules = reactive({
#foreach ($column in $subColumns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end
#end
})
const formRef = ref() // 表单 Ref
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
async (val) => {
// 1. 重置表单
#if ( $subTable.subJoinMany )
formData.value = []
#else
formData.value = {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
}
#end
// 2. val 非空,则加载数据
if (!val) {
return;
}
try {
formLoading.value = true
#if ( $subTable.subJoinMany )
formData.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(val)
#else
const data = await ${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(val)
if (!data) {
return
}
formData.value = data
#end
} finally {
formLoading.value = false
}
},
{ immediate: true }
)
#if ( $subTable.subJoinMany )
/** 新增按钮操作 */
const handleAdd = () => {
const row = {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
}
row.${subJoinColumn.javaField} = props.${subJoinColumn.javaField}
formData.value.push(row)
}
/** 删除按钮操作 */
const handleDelete = (index) => {
formData.value.splice(index, 1)
}
#end
/** 表单校验 */
const validate = () => {
return formRef.value.validate()
}
/** 表单值 */
const getData = () => {
return formData.value
}
defineExpose({ validate, getData })
</script>

View File

@@ -0,0 +1,184 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<template>
<!-- 列表 -->
<ContentWrap>
#if ($table.templateType == 11)
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['${permissionPrefix}:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
#end
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
#foreach($column in $subColumns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.javaType == "LocalDateTime")## 时间类型
<el-table-column
label="${comment}"
align="center"
prop="${javaField}"
:formatter="dateFormatter"
width="180px"
/>
#elseif($column.dictType && "" != $column.dictType)## 数据字典
<el-table-column label="${comment}" align="center" prop="${javaField}">
<template #default="scope">
<dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
</template>
</el-table-column>
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
#end
#if ($table.templateType == 11)
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['${permissionPrefix}:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['${permissionPrefix}:delete']"
>
删除
</el-button>
</template>
</el-table-column>
#end
</el-table>
#if ($table.templateType == 11)
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
#end
</ContentWrap>
#if ($table.templateType == 11)
<!-- 表单弹窗:添加/修改 -->
<${subSimpleClassName}Form ref="formRef" @success="getList" />
#end
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import { ${simpleClassName}Api } from '@/api/${table.moduleName}/${table.businessName}'
#if ($table.templateType == 11)
import ${subSimpleClassName}Form from './${subSimpleClassName}Form.vue'
#end
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const props = defineProps<{
${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
}>()
const loading = ref(false) // 列表的加载中
const list = ref([]) // 列表的数据
#if ($table.templateType == 11)
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
${subJoinColumn.javaField}: undefined as unknown
})
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
(val: number) => {
if (!val) {
return
}
queryParams.${subJoinColumn.javaField} = val
handleQuery()
},
{ immediate: true, deep: true }
)
#end
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
#if ($table.templateType == 11)
const data = await ${simpleClassName}Api.get${subSimpleClassName}Page(queryParams)
list.value = data.list
total.value = data.total
#else
#if ( $subTable.subJoinMany )
list.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField})
#else
const data = await ${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField})
if (!data) {
return
}
list.value.push(data)
#end
#end
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
#if ($table.templateType == 11)
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
if (!props.${subJoinColumn.javaField}) {
message.error('请选择一个${table.classComment}')
return
}
formRef.value.open(type, id, props.${subJoinColumn.javaField})
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await ${simpleClassName}Api.delete${subSimpleClassName}(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch {}
}
#end
#if ($table.templateType != 11)
/** 初始化 **/
onMounted(() => {
getList()
})
#end
</script>

View File

@@ -0,0 +1,4 @@
## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
## 1inner 使用 list 不分页erp 使用 page 分页
## 2erp 支持单个子表的新增、修改、删除inner 不支持
#parse("codegen/vue3/views/components/list_sub_erp.vue.vm")

View File

@@ -0,0 +1,244 @@
<template>
<FormDialog
ref="formDialogRef"
:form-data="formData"
:form-rules="formRules"
:create-api="${simpleClassName}Api.create${simpleClassName}"
:update-api="${simpleClassName}Api.update${simpleClassName}"
:get-api="${simpleClassName}Api.get${simpleClassName}"
create-title="新增${table.classComment}"
update-title="修改${table.classComment}"
@success="handleSuccess"
>
<template #form-items="{ formData }">
#foreach($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "getIntDictOptions")
#elseif ($javaType == "String")
#set ($dictMethod = "getStrDictOptions")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "getBoolDictOptions")
#end
#if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
<el-form-item label="${comment}" prop="${javaField}">
<el-tree-select
v-model="formData.${javaField}"
:data="${classNameVar}Tree"
#if ($treeNameColumn.javaField == "name")
:props="defaultProps"
#else
:props="{...defaultProps, label: '$treeNameColumn.javaField'}"
#end
check-strictly
default-expand-all
placeholder="请选择${comment}"
/>
</el-form-item>
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")## 图片上传
<el-form-item label="${comment}" prop="${javaField}">
<UploadImg v-model="formData.${javaField}" />
</el-form-item>
#elseif($column.htmlType == "fileUpload")## 文件上传
<el-form-item label="${comment}" prop="${javaField}">
<UploadFile v-model="formData.${javaField}" />
</el-form-item>
</el-form-item>
#elseif($column.htmlType == "editor")## 文本编辑器
<el-form-item label="${comment}" prop="${javaField}">
<Editor v-model="formData.${javaField}" height="150px" />
</el-form-item>
#elseif($column.htmlType == "select")## 下拉框
<el-form-item label="${comment}" prop="${javaField}">
<el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<el-option
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox")## 多选框
<el-form-item label="${comment}" prop="${javaField}">
<el-checkbox-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-checkbox
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else##没数据字典
<el-checkbox label="请选择字典生成" />
#end
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio")## 单选框
<el-form-item label="${comment}" prop="${javaField}">
<el-radio-group v-model="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<el-radio
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
#else##没数据字典
<el-radio value="1">请选择字典生成</el-radio>
#end
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "datetime")## 时间框
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker
v-model="formData.${javaField}"
type="date"
value-format="x"
placeholder="选择${comment}"
/>
</el-form-item>
#elseif($column.htmlType == "textarea")## 文本框
<el-form-item label="${comment}" prop="${javaField}">
<el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
</el-form-item>
#end
#end
#end
#if($isFileUpload && $isFileUpload == true)
<el-form-item label="附件" prop="files">
<UploadFile v-model="formData.files" />
</el-form-item>
#end
</template>
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
<!-- 子表的表单 -->
<template #footer="{ submit, cancel, loading }">
<el-tabs v-model="subTabsName" style="margin-bottom: 20px;">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
<${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData.id" />
</el-tab-pane>
#end
</el-tabs>
<el-button @click="submit" type="primary" :disabled="loading">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</template>
#end
</FormDialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { ${simpleClassName}Api, ${simpleClassName}VO } from '@/api/${table.moduleName}/${table.businessName}'
import FormDialog from '@/components/FormDialog/index.vue'
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
import { defaultProps, handleTree } from '@/utils/tree'
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue'
#end
#end
/** ${table.classComment} 表单 */
defineOptions({ name: '${simpleClassName}Form' })
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
/** 成功事件 */
const emit = defineEmits(['success'])
/** 组件引用 */
const formDialogRef = ref()
/** 表单数据 */
const formData = ref({
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
#if($isFileUpload && $isFileUpload == true)
files: undefined
#end
})
/** 表单验证规则 */
const formRules = reactive({
#foreach ($column in $columns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end
#end
})
const formRef = ref() // 表单 Ref
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
const ${classNameVar}Tree = ref() // 树形结构
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
/** 子表的表单 */
const subTabsName = ref('$subClassNameVars.get(0)')
#foreach ($subClassNameVar in $subClassNameVars)
const ${subClassNameVar}FormRef = ref()
#end
#end
#end
/** 处理成功事件 */
const handleSuccess = () => {
emit('success')
}
/** 暴露组件方法 */
defineExpose({
open: (type: string, id?: number) => {
formDialogRef.value?.open(type, id)
}
})
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
/** 获得${table.classComment}树 */
const get${simpleClassName}Tree = async () => {
${classNameVar}Tree.value = []
const data = await ${simpleClassName}Api.get${simpleClassName}List()
const root: Tree = { id: 0, name: '顶级${table.classComment}', children: [] }
root.children = handleTree(data, 'id', '${treeParentColumn.javaField}')
${classNameVar}Tree.value.push(root)
}
#end
</script>

View File

@@ -0,0 +1,596 @@
<template>
<!-- 搜索区域 -->
<SearchForm
v-model="queryParams"
@search="handleQuery"
@reset="resetQuery"
>
<template #search-items="{ form }">
#foreach($column in $columns)
#if ($column.listOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "getIntDictOptions")
#elseif ($javaType == "String")
#set ($dictMethod = "getStrDictOptions")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "getBoolDictOptions")
#end
#if ($column.htmlType == "input")
<el-form-item label="${comment}" prop="${javaField}">
<el-input
v-model="form.${javaField}"
placeholder="请输入${comment}"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
#elseif ($column.htmlType == "select" || $column.htmlType == "radio")
<el-form-item label="${comment}" prop="${javaField}">
<el-select
v-model="form.${javaField}"
placeholder="请选择${comment}"
clearable
class="!w-240px"
>
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
<el-option
v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
#else## 未设置 dictType 数据字典的情况
<el-option label="请选择字典生成" value="" />
#end
</el-select>
</el-form-item>
#elseif($column.htmlType == "datetime")
#if ($column.listOperationCondition != "BETWEEN")## 非范围
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker
v-model="form.${javaField}"
value-format="YYYY-MM-DD"
type="date"
placeholder="选择${comment}"
clearable
class="!w-240px"
/>
</el-form-item>
#else## 范围
<el-form-item label="${comment}" prop="${javaField}">
<el-date-picker
v-model="form.${javaField}"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item>
#end
#end
#end
#end
</template>
<template #action-buttons>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['${permissionPrefix}:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['${permissionPrefix}:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
#if ( $table.templateType != 12 && $table.templateType != 11 && $table.templateType != 2 )
<el-button
type="danger"
plain
@click="handleBatchDelete"
:disabled="selectRecords.length === 0"
v-hasPermi="['${permissionPrefix}:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> 批量删除({{ selectRecords.length }})
</el-button>
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
<el-button type="danger" plain @click="toggleExpandAll">
<Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
</el-button>
#end
</template>
</SearchForm>
<!-- 列表区域 -->
#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
<!-- 特殊:主子表使用传统表格 -->
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
highlight-current-row
@current-change="handleCurrentChange"
>
#elseif ( $table.templateType == 2 )
<!-- 特殊:树表使用传统表格 -->
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
:default-expand-all="isExpandAll"
v-if="refreshTable"
>
#elseif ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
<!-- 特殊:主子表展开使用传统表格 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
#else
<!-- 普通表格使用 DataTable 组件 -->
<DataTable
:data="list"
:total="total"
:loading="loading"
:current-page="queryParams.pageNo"
:page-size="queryParams.pageSize"
:columns="tableColumns"
@pagination="handlePagination"
@selection-change="onSelectionChange"
>
<template #action="{ row }">
<el-button
link
type="primary"
@click="openForm('update', row.id)"
v-hasPermi="['${permissionPrefix}:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(row.id)"
v-hasPermi="['${permissionPrefix}:delete']"
>
删除
</el-button>
#if($isFileUpload && $isFileUpload == true)
<el-button link @click="openBusinessFile(row.id)">附件</el-button>
#end
</template>
</DataTable>
#end
## 特殊表格依然使用 element table
#if ( $table.templateType == 12 || $table.templateType == 11 || $table.templateType == 2 )
## 特殊:主子表专属逻辑
#if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
<!-- 子表的列表 -->
<el-table-column type="expand">
<template #default="scope">
<el-tabs model-value="$subClassNameVars.get(0)">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
<${subSimpleClassName}List :${subJoinColumn_strikeCase}="scope.row.id" />
</el-tab-pane>
#end
</el-tabs>
</template>
</el-table-column>
#end
#foreach($column in $columns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
<el-table-column
label="${comment}"
align="center"
prop="${javaField}"
:formatter="dateFormatter"
width="180px"
/>
#elseif($column.dictType && "" != $column.dictType)## 数据字典
<el-table-column label="${comment}" align="center" prop="${javaField}">
<template #default="scope">
<dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
</template>
</el-table-column>
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
#end
<el-table-column label="操作" align="center" min-width="200px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['${permissionPrefix}:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['${permissionPrefix}:delete']"
>
删除
</el-button>
#if($isFileUpload && $isFileUpload == true)
<el-button link @click="openBusinessFile(scope.row.id)">附件</el-button>
#end
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
:page-sizes="[10, 20, 50, 100, 200, 500, 700,5000, 10000]"
/>
</ContentWrap>
#end
<!-- 表单弹窗:添加/修改 -->
<${simpleClassName}Form ref="formRef" @success="getList" />
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
<!-- 子表的列表 -->
<ContentWrap>
<el-tabs model-value="$subClassNameVars.get(0)">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
<${subSimpleClassName}List :${subJoinColumn_strikeCase}="currentRow.id" />
</el-tab-pane>
#end
</el-tabs>
</ContentWrap>
#end
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
import { handleTree } from '@/utils/tree'
#end
#if ( $table.templateType != 12 && $table.templateType != 11 && $table.templateType != 2 )
import { useVxeGrid } from '@/hooks/web/useVxeGrid'
#end
import download from '@/utils/download'
import { ${simpleClassName}Api, ${simpleClassName}VO } from '@/api/${table.moduleName}/${table.businessName}'
import ${simpleClassName}Form from './${simpleClassName}Form.vue'
import SearchForm from '@/components/SearchForm/index.vue'
#if ( $table.templateType != 12 && $table.templateType != 11 && $table.templateType != 2 )
import DataTable from '@/components/DataTable/index.vue'
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType != 10 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
import ${subSimpleClassName}List from './components/${subSimpleClassName}List.vue'
#end
#end
#if($isFileUpload && $isFileUpload == true)
import {useDialogStore} from '@/store/modules/dialog'
import {FileUploadInfoVO} from '@/api/infra/file'
const dialogStore = useDialogStore()
const openBusinessFile = async (id: string) => {
let fileUploadInfoVO : FileUploadInfoVO = await ${simpleClassName}Api.getFileUploadInfo();
fileUploadInfoVO.businessId = id
dialogStore.openBusinessFileDialog(fileUploadInfoVO)
}
#end
/** ${table.classComment} 列表 */
defineOptions({ name: '${table.className}' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中
const list = ref<${simpleClassName}VO[]>([]) // 列表的数据
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
const total = ref(0) // 列表的总页数
#end
#if ( $table.templateType == 12 || $table.templateType == 11 || $table.templateType == 2 )
const gridRef = ref() // vxe-grid 的引用
#end
const selectRecords = ref<${simpleClassName}VO[]>([]) // 选中的记录
const queryParams = reactive({
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
pageNo: 1,
pageSize: 10,
#end
#foreach ($column in $columns)
#if ($column.listOperation)
#if ($column.listOperationCondition != 'BETWEEN')
$column.javaField: undefined,
#end
#if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
$column.javaField: [],
#end
#end
#end
})
const exportLoading = ref(false) // 导出的加载中
#if ( $table.templateType != 12 && $table.templateType != 11 && $table.templateType != 2 )
// 表格列配置
const tableColumns = [
#foreach($column in $columns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
{
field: '${javaField}',
title: '${comment}',
width: 180,
align: 'center',
formatter: ({ row, column, cellValue }) => cellValue ? dateFormatter(row, column, cellValue) : ''
},
#elseif($column.dictType && "" != $column.dictType)## 数据字典
{
field: '${javaField}',
title: '${comment}',
width: 120,
align: 'center',
formatter: ({ cellValue }) => {
const dict = getStrDictOptions(DICT_TYPE.${dictType.toUpperCase()}).find(item => item.value === cellValue)
return dict ? dict.label : cellValue
}
},
#else
{
field: '${javaField}',
title: '${comment}',
minWidth: 120,
align: 'center'
},
#end
#end
#end
{
title: '操作',
width: 200,
align: 'center',
fixed: 'right', // 固定在右侧
slots: { default: 'action' }
}
]
/** DataTable 选择变化事件 */
const onSelectionChange = (records: ${simpleClassName}VO[]) => {
selectRecords.value = records
}
/** 分页处理 */
const handlePagination = ({ page, limit }: { page: number; limit: number }) => {
queryParams.pageNo = page
queryParams.pageSize = limit
getList()
}
#else
/** vxe-grid 复选框事件 */
const onCheckboxChange = ({ records }) => {
selectRecords.value = records
}
// vxe-grid 配置 (兼容 VxeTable 4.6.25)
const { gridOptions } = useVxeGrid({
loading,
data: list,
columns: [
{
type: 'checkbox',
width: 50,
align: 'center',
fixed: 'left' // 固定在左侧
},
#foreach($column in $columns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
{
field: '${javaField}',
title: '${comment}',
width: 180,
align: 'center',
formatter: ({ cellValue }) => dateFormatter(null,null,cellValue)
},
#elseif($column.dictType && "" != $column.dictType)## 数据字典
{
field: '${javaField}',
title: '${comment}',
width: 120,
align: 'center',
formatter: ({ cellValue }) => {
const dict = getStrDictOptions(DICT_TYPE.${dictType.toUpperCase()}).find(item => item.value === cellValue)
return dict ? dict.label : cellValue
}
},
#else
{
field: '${javaField}',
title: '${comment}',
minWidth: 120,
align: 'center'
},
#end
#end
#end
{
title: '操作',
width: 200,
align: 'center',
fixed: 'right', // 固定在右侧
slots: { default: 'action' }
}
]
})
#end
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType == 2 )
const data = await ${simpleClassName}Api.get${simpleClassName}List(queryParams)
list.value = handleTree(data, 'id', '${treeParentColumn.javaField}')
#else
const data = await ${simpleClassName}Api.get${simpleClassName}Page(queryParams)
list.value = data.list
total.value = data.total
#end
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
#if ( $table.templateType != 2 )
queryParams.pageNo = 1
#end
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
#if ( $table.templateType != 2 )
queryParams.pageNo = 1
#end
getList()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await ${simpleClassName}Api.delete${simpleClassName}(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch {}
}
/** 批量删除按钮操作 */
const handleBatchDelete = async () => {
try {
if (selectRecords.value.length === 0) {
message.warning('请至少选择一条记录')
return
}
// 删除的二次确认
await message.delConfirm(`确定要删除选中的 ${selectRecords.value.length} 条记录吗?`)
// 批量删除
const ids = selectRecords.value.map((record) => record.id)
await ${simpleClassName}Api.delete${simpleClassName}List(ids)
message.success(t('common.delSuccess'))
// 清空选中状态
#if ( $table.templateType != 12 && $table.templateType != 11 && $table.templateType != 2 )
// DataTable 组件会自动处理选中状态
#else
gridRef.value?.clearCheckboxRow()
#end
selectRecords.value = []
// 刷新列表
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const data = await ${simpleClassName}Api.export${simpleClassName}(queryParams)
download.excel(data, '${table.classComment}.xls')
} catch {
} finally {
exportLoading.value = false
}
}
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 )
/** 选中行操作 */
const currentRow = ref({}) // 选中行
const handleCurrentChange = (row) => {
currentRow.value = row
}
#end
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
/** 展开/折叠操作 */
const isExpandAll = ref(true) // 是否展开,默认全部展开
const refreshTable = ref(true) // 重新渲染表格状态
const toggleExpandAll = async () => {
refreshTable.value = false
isExpandAll.value = !isExpandAll.value
await nextTick()
refreshTable.value = true
}
#end
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@@ -0,0 +1,32 @@
import { defHttp } from '@/utils/http/axios'
#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
// 查询${table.classComment}列表
export function get${simpleClassName}Page(params) {
return defHttp.get({ url: '${baseURL}/page', params })
}
// 查询${table.classComment}详情
export function get${simpleClassName}(id: number) {
return defHttp.get({ url: `${baseURL}/get?id=${id}` })
}
// 新增${table.classComment}
export function create${simpleClassName}(data) {
return defHttp.post({ url: '${baseURL}/create', data })
}
// 修改${table.classComment}
export function update${simpleClassName}(data) {
return defHttp.put({ url: '${baseURL}/update', data })
}
// 删除${table.classComment}
export function delete${simpleClassName}(id: number) {
return defHttp.delete({ url: `${baseURL}/delete?id=${id}` })
}
// 导出${table.classComment} Excel
export function export${simpleClassName}(params) {
return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls')
}

View File

@@ -0,0 +1,260 @@
import type {BasicColumn, FormSchema} from '@/components/Table'
import {useRender} from '@/components/Table'
import {DICT_TYPE, getDictOptions} from '@/utils/dict'
export const columns: BasicColumn[] = [
#foreach($column in $columns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
{
title: '${comment}',
dataIndex: '${javaField}',
width: 180,
customRender: ({ text }) => {
return useRender.renderDate(text)
},
},
#elseif("" != $column.dictType)## 数据字典
{
title: '${comment}',
dataIndex: '${javaField}',
width: 180,
customRender: ({ text }) => {
return useRender.renderDict(text, DICT_TYPE.$dictType.toUpperCase())
},
},
#else
{
title: '${comment}',
dataIndex: '${javaField}',
width: 160,
},
#end
#end
#end
]
export const searchFormSchema: FormSchema[] = [
#foreach($column in $columns)
#if ($column.listOperation)
#set ($dictType=$column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
{
label: '${comment}',
field: '${javaField}',
#if ($column.htmlType == "input")
component: 'Input',
#elseif ($column.htmlType == "select")
component: 'Select',
componentProps: {
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else## 未设置 dictType 数据字典的情况
options: [],
#end
},
#elseif ($column.htmlType == "radio")
component: 'RadioButtonGroup',
componentProps: {
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else## 未设置 dictType 数据字典的情况
options: [],
#end
},
#elseif($column.htmlType == "datetime")
component: 'RangePicker',
#end
colProps: { span: 8 },
},
#end
#end
]
export const createFormSchema: FormSchema[] = [
{
label: '编号',
field: 'id',
show: false,
component: 'Input',
},
#foreach($column in $columns)
#if ($column.createOperation)
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if (!$column.primaryKey)## 忽略主键,不用在表单里
{
label: '${comment}',
field: '${javaField}',
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
required: true,
#end
#if ($column.htmlType == "input")
component: 'Input',
#elseif($column.htmlType == "imageUpload")## 图片上传
component: 'FileUpload',
componentProps: {
fileType: 'image',
maxCount: 1,
},
#elseif($column.htmlType == "fileUpload")## 文件上传
component: 'FileUpload',
componentProps: {
fileType: 'file',
maxCount: 1,
},
#elseif($column.htmlType == "editor")## 文本编辑器
component: 'Editor',
#elseif($column.htmlType == "select")## 下拉框
component: 'Select',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options:[],
#end
},
#elseif($column.htmlType == "checkbox")## 多选框
component: 'Checkbox',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options:[],
#end
},
#elseif($column.htmlType == "radio")## 单选框
component: 'RadioButtonGroup',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options:[],
#end
},
#elseif($column.htmlType == "datetime")## 时间框
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
},
#elseif($column.htmlType == "textarea")## 文本域
component: 'InputTextArea',
#end
},
#end
#end
#end
]
export const updateFormSchema: FormSchema[] = [
{
label: '编号',
field: 'id',
show: false,
component: 'Input',
},
#foreach($column in $columns)
#if ($column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if (!$column.primaryKey)## 忽略主键,不用在表单里
{
label: '${comment}',
field: '${javaField}',
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
required: true,
#end
#if ($column.htmlType == "input")
component: 'Input',
#elseif($column.htmlType == "imageUpload")## 图片上传
component: 'FileUpload',
componentProps: {
fileType: 'image',
maxCount: 1,
},
#elseif($column.htmlType == "fileUpload")## 文件上传
component: 'FileUpload',
componentProps: {
fileType: 'file',
maxCount: 1,
},
#elseif($column.htmlType == "editor")## 文本编辑器
component: 'Editor',
#elseif($column.htmlType == "select")## 下拉框
component: 'Select',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options:[],
#end
},
#elseif($column.htmlType == "checkbox")## 多选框
component: 'Checkbox',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options:[],
#end
},
#elseif($column.htmlType == "radio")## 单选框
component: 'RadioButtonGroup',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options:[],
#end
},
#elseif($column.htmlType == "datetime")## 时间框
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
},
#elseif($column.htmlType == "textarea")## 文本域
component: 'InputTextArea',
#end
},
#end
#end
#end
]

View File

@@ -0,0 +1,58 @@
<script lang="ts" setup>
import { ref, unref } from 'vue'
import { createFormSchema, updateFormSchema } from './${classNameVar}.data'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { BasicForm, useForm } from '@/components/Form'
import { BasicModal, useModalInner } from '@/components/Modal'
import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
defineOptions({ name: '${table.className}Modal' })
const emit = defineEmits(['success', 'register'])
const { t } = useI18n()
const { createMessage } = useMessage()
const isUpdate = ref(true)
const [registerForm, { setFieldsValue, resetFields, resetSchema, validate }] = useForm({
labelWidth: 120,
baseColProps: { span: 24 },
schemas: createFormSchema,
showActionButtonGroup: false,
actionColOptions: { span: 23 },
})
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields()
setModalProps({ confirmLoading: false })
isUpdate.value = !!data?.isUpdate
if (unref(isUpdate)) {
resetSchema(updateFormSchema)
const res = await get${simpleClassName}(data.record.id)
setFieldsValue({ ...res })
}
})
async function handleSubmit() {
try {
const values = await validate()
setModalProps({ confirmLoading: true })
if (unref(isUpdate))
await update${simpleClassName}(values)
else
await create${simpleClassName}(values)
closeModal()
emit('success')
createMessage.success(t('common.saveSuccessText'))
} finally {
setModalProps({ confirmLoading: false })
}
}
</script>
<template>
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>

View File

@@ -0,0 +1,92 @@
<script lang="ts" setup>
import ${simpleClassName}Modal from './${simpleClassName}Modal.vue'
import { columns, searchFormSchema } from './${classNameVar}.data'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { useModal } from '@/components/Modal'
import { IconEnum } from '@/enums/appEnum'
import { BasicTable, TableAction, useTable } from '@/components/Table'
import { delete${simpleClassName}, export${simpleClassName}, get${simpleClassName}Page } from '@/api/${table.moduleName}/${table.businessName}'
defineOptions({ name: '${table.className}' })
const { t } = useI18n()
const { createConfirm, createMessage } = useMessage()
const [registerModal, { openModal }] = useModal()
const [registerTable, { getForm, reload }] = useTable({
title: '${table.classComment}列表',
api: get${simpleClassName}Page,
columns,
formConfig: { labelWidth: 120, schemas: searchFormSchema },
useSearchForm: true,
showTableSetting: true,
actionColumn: {
width: 140,
title: t('common.action'),
dataIndex: 'action',
fixed: 'right',
},
})
function handleCreate() {
openModal(true, { isUpdate: false })
}
function handleEdit(record: Recordable) {
openModal(true, { record, isUpdate: true })
}
async function handleExport() {
createConfirm({
title: t('common.exportTitle'),
iconType: 'warning',
content: t('common.exportMessage'),
async onOk() {
await export${simpleClassName}(getForm().getFieldsValue())
createMessage.success(t('common.exportSuccessText'))
},
})
}
async function handleDelete(record: Recordable) {
await delete${simpleClassName}(record.id)
createMessage.success(t('common.delSuccessText'))
reload()
}
</script>
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" v-auth="['${permissionPrefix}:create']" :preIcon="IconEnum.ADD" @click="handleCreate">
{{ t('action.create') }}
</a-button>
<a-button v-auth="['${permissionPrefix}:export']" :preIcon="IconEnum.EXPORT" @click="handleExport">
{{ t('action.export') }}
</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{ icon: IconEnum.EDIT, label: t('action.edit'), auth: '${permissionPrefix}:update', onClick: handleEdit.bind(null, record) },
{
icon: IconEnum.DELETE,
danger: true,
label: t('action.delete'),
auth: '${permissionPrefix}:delete',
popConfirm: {
title: t('common.delMessage'),
placement: 'left',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</template>
</BasicTable>
<${simpleClassName}Modal @register="registerModal" @success="reload()" />
</div>
</template>

View File

@@ -0,0 +1,168 @@
import type { PageParam, PageResult } from '@vben/request';
import type { Dayjs } from 'dayjs';
import { requestClient } from '#/api/request';
#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
export namespace ${simpleClassName}Api {
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subColumns = $subColumnsList.get($index))##当前字段数组
/** ${subTable.classComment}信息 */
export interface ${subSimpleClassName} {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
#elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
#else
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
#end
#end
#end
}
#end
/** ${table.classComment}信息 */
export interface ${simpleClassName} {
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
#elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
#else
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
#end
#end
#end
#if ( $table.templateType == 2 )
children?: ${simpleClassName}[];
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#if ( $subTable.subJoinMany )
${subSimpleClassName.toLowerCase()}s?: ${subSimpleClassName}[]
#else
${subSimpleClassName.toLowerCase()}?: ${subSimpleClassName}
#end
#end
#end
}
}
#if ( $table.templateType != 2 )
/** 查询${table.classComment}分页 */
export function get${simpleClassName}Page(params: PageParam) {
return requestClient.get<PageResult<${simpleClassName}Api.${simpleClassName}>>('${baseURL}/page', { params });
}
#else
/** 查询${table.classComment}列表 */
export function get${simpleClassName}List(params: any) {
return requestClient.get<${simpleClassName}Api.${simpleClassName}[]>('${baseURL}/list', { params });
}
#end
/** 查询${table.classComment}详情 */
export function get${simpleClassName}(id: number) {
return requestClient.get<${simpleClassName}Api.${simpleClassName}>(`${baseURL}/get?id=${id}`);
}
/** 新增${table.classComment} */
export function create${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
return requestClient.post('${baseURL}/create', data);
}
/** 修改${table.classComment} */
export function update${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
return requestClient.put('${baseURL}/update', data);
}
/** 删除${table.classComment} */
export function delete${simpleClassName}(id: number) {
return requestClient.delete(`${baseURL}/delete?id=${id}`);
}
#if ( $table.templateType != 2 && $deleteBatchEnable)
/** 批量删除${table.classComment} */
export function delete${simpleClassName}ListByIds(ids: number[]) {
return requestClient.delete(`${baseURL}/delete-list?ids=${ids.join(',')}`)
}
#end
/** 导出${table.classComment} */
export function export${simpleClassName}(params: any) {
return requestClient.download('${baseURL}/export-excel', params);
}
## 特殊:主子表专属逻辑
## TODO @puhui999下面这块缩进调整了会乱掉么
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
#set ($subClassNameVar = $subClassNameVars.get($index))
// ==================== 子表($subTable.classComment ====================
## 情况一MASTER_ERP 时,需要分查询页子表
#if ( $table.templateType == 11 )
/** 获得${subTable.classComment}分页 */
export function get${subSimpleClassName}Page(params: PageParam) {
return requestClient.get<PageResult<${simpleClassName}Api.${subSimpleClassName}>>(`${baseURL}/${subSimpleClassName_strikeCase}/page`, { params });
}
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ( $subTable.subJoinMany )
/** 获得${subTable.classComment}列表 */
export function get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
return requestClient.get<${simpleClassName}Api.${subSimpleClassName}[]>(`${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
}
#else
/** 获得${subTable.classComment} */
export function get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
}
#end
#end
## 特殊MASTER_ERP 时,支持单个的新增、修改、删除操作
#if ( $table.templateType == 11 )
/** 新增${subTable.classComment} */
export function create${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
return requestClient.post(`${baseURL}/${subSimpleClassName_strikeCase}/create`, data);
}
/** 修改${subTable.classComment} */
export function update${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
return requestClient.put(`${baseURL}/${subSimpleClassName_strikeCase}/update`, data);
}
/** 删除${subTable.classComment} */
export function delete${subSimpleClassName}(id: number) {
return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete?id=${id}`);
}
#if ($deleteBatchEnable)
/** 批量删除${subTable.classComment} */
export function delete${subSimpleClassName}ListByIds(ids: number[]) {
return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete-list?ids=${ids.join(',')}`)
}
#end
/** 获得${subTable.classComment} */
export function get${subSimpleClassName}(id: number) {
return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get?id=${id}`);
}
#end
#end

View File

@@ -0,0 +1,324 @@
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
import type { Rule } from 'ant-design-vue/es/form';
import { useVbenModal } from '@vben/common-ui';
import { Tinymce as RichTextarea } from '#/components/tinymce';
import { ImageUpload, FileUpload } from "#/components/upload";
import { message, Tabs, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'ant-design-vue';
import { DICT_TYPE, getDictOptions } from '#/utils';
#if($table.templateType == 2)## 树表需要导入这些
import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}';
import { handleTree } from '@vben/utils'
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
#end
#end
import { computed, ref } from 'vue';
import { $t } from '#/locales';
import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
const emit = defineEmits(['success']);
const formRef = ref();
const formData = ref<Partial<${simpleClassName}Api.${simpleClassName}>>({
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
});
const rules: Record<string, Rule[]> = {
#foreach ($column in $columns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end
#end
};
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
const ${classNameVar}Tree = ref<any[]>([]) // 树形结构
#end
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['${table.classComment}'])
: $t('ui.actionTitle.create', ['${table.classComment}']);
});
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
/** 子表的表单 */
const subTabsName = ref('$subClassNameVars.get(0)')
#foreach ($subClassNameVar in $subClassNameVars)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
const ${subClassNameVar}FormRef = ref<InstanceType<typeof ${subSimpleClassName}Form>>()
#end
#end
#end
/** 重置表单 */
const resetForm = () => {
formData.value = {
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
};
formRef.value?.resetFields();
}
## 特殊:树表专属逻辑
#if ( $table.templateType == 2 )
/** 获得${table.classComment}树 */
const get${simpleClassName}Tree = async () => {
${classNameVar}Tree.value = []
const data = await get${simpleClassName}List({});
data.unshift({
id: 0,
name: '顶级${table.classComment}',
});
${classNameVar}Tree.value = handleTree(data);
}
#end
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
await formRef.value?.validate();
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
// 校验子表单
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#if ($subTable.subJoinMany) ## 一对多
## TODO 列表值校验?
#else
try {
await ${subClassNameVar}FormRef.value?.validate()
} catch (e) {
subTabsName.value = '${subClassNameVar}'
return
}
#end
#end
#end
#end
modalApi.lock();
// 提交表单
const data = formData.value as ${simpleClassName}Api.${simpleClassName};
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
// 拼接子表的数据
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#if ($subTable.subJoinMany)
data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
#else
data.${subClassNameVar} = ${subClassNameVar}FormRef.value?.getValues();
#end
#end
#end
#end
try {
await (formData.value?.id ? update${simpleClassName}(data) : create${simpleClassName}(data));
// 关闭并提示
await modalApi.close();
emit('success');
message.success({
content: $t('ui.actionMessage.operationSuccess'),
key: 'action_process_msg',
});
} finally {
modalApi.unlock();
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
resetForm()
return;
}
// 加载数据
let data = modalApi.getData<${simpleClassName}Api.${simpleClassName}>();
if (!data) {
return;
}
if (data.id) {
modalApi.lock();
try {
data = await get${simpleClassName}(data.id);
} finally {
modalApi.unlock();
}
}
formData.value = data;
#if ( $table.templateType == 2 )
// 加载树数据
await get${simpleClassName}Tree()
#end
},
});
</script>
<template>
<Modal :title="getTitle">
<Form
ref="formRef"
:model="formData"
:rules="rules"
:label-col="{ span: 5 }"
:wrapper-col="{ span: 18 }"
>
#foreach($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
<Form.Item label="${comment}" name="${javaField}">
<TreeSelect
v-model:value="formData.${javaField}"
:treeData="${classNameVar}Tree"
#if ($treeNameColumn.javaField == "name")
:fieldNames="{
label: 'name',
value: 'id',
children: 'children',
}"
#else
:fieldNames="{
label: '$treeNameColumn.javaField',
value: 'id',
children: 'children',
}"
#end
checkable
treeDefaultExpandAll
placeholder="请选择${comment}"
/>
</Form.Item>
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<Form.Item label="${comment}" name="${javaField}">
<Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
</Form.Item>
#elseif($column.htmlType == "imageUpload")## 图片上传
<Form.Item label="${comment}" name="${javaField}">
<ImageUpload v-model:value="formData.${javaField}" />
</Form.Item>
#elseif($column.htmlType == "fileUpload")## 文件上传
<Form.Item label="${comment}" name="${javaField}">
<FileUpload v-model:value="formData.${javaField}" />
</Form.Item>
#elseif($column.htmlType == "editor")## 文本编辑器
<Form.Item label="${comment}" name="${javaField}">
<RichTextarea v-model="formData.${javaField}" height="500px" />
</Form.Item>
#elseif($column.htmlType == "select")## 下拉框
<Form.Item label="${comment}" name="${javaField}">
<Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<Select.Option
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Select.Option>
#else##没数据字典
<Select.Option label="请选择字典生成" value="" />
#end
</Select>
</Form.Item>
#elseif($column.htmlType == "checkbox")## 多选框
<Form.Item label="${comment}" name="${javaField}">
<CheckboxGroup v-model:value="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<Checkbox
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Checkbox>
#else##没数据字典
<Checkbox label="请选择字典生成" />
#end
</CheckboxGroup>
</Form.Item>
#elseif($column.htmlType == "radio")## 单选框
<Form.Item label="${comment}" name="${javaField}">
<RadioGroup v-model:value="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<Radio
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Radio>
#else##没数据字典
<Radio value="1">请选择字典生成</Radio>
#end
</RadioGroup>
</Form.Item>
#elseif($column.htmlType == "datetime")## 时间框
<Form.Item label="${comment}" name="${javaField}">
<DatePicker
v-model:value="formData.${javaField}"
valueFormat="x"
placeholder="选择${comment}"
/>
</Form.Item>
#elseif($column.htmlType == "textarea")## 文本框
<Form.Item label="${comment}" name="${javaField}">
<Textarea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
</Form.Item>
#end
#end
#end
</Form>
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
<!-- 子表的表单 -->
<Tabs v-model:active-key="subTabsName">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
<${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" />
</Tabs.TabPane>
#end
</Tabs>
#end
</Modal>
</template>

View File

@@ -0,0 +1,489 @@
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
import type { VxeTableInstance } from '#/adapter/vxe-table';
import { Page, useVbenModal } from '@vben/common-ui';
import { cloneDeep, formatDateTime } from '@vben/utils';
import { Button, message,Tabs,Pagination,Form,RangePicker,DatePicker,Select,Input } from 'ant-design-vue';
import { DictTag } from '#/components/dict-tag';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import ${simpleClassName}Form from './modules/form.vue';
import { Download, Plus, RefreshCw, Search, Trash2 } from '@vben/icons';
import { ContentWrap } from '#/components/content-wrap';
import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
import { TableToolbar } from '#/components/table-toolbar';
import { useTableToolbar } from '#/hooks';
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
import ${subSimpleClassName}List from './modules/${subSimpleClassName_strikeCase}-list.vue'
#end
#end
import { ref, h, reactive,onMounted,nextTick } from 'vue';
import { $t } from '#/locales';
#if (${table.templateType} == 2)## 树表接口
import { handleTree,isEmpty } from '@vben/utils'
import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
#else## 标准表接口
import { isEmpty } from '@vben/utils';
import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}ListByIds,#end export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
#end
import { downloadFileFromBlobPart } from '@vben/utils';
#if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况
/** 子表的列表 */
const subTabsName = ref('$subClassNameVars.get(0)')
#if ($table.templateType == 11)
const select${simpleClassName} = ref<${simpleClassName}Api.${simpleClassName}>();
async function onCellClick({ row }: { row: ${simpleClassName}Api.${simpleClassName} }) {
select${simpleClassName}.value = row
}
#end
#end
const loading = ref(true) // 列表的加载中
#if ( $table.templateType == 2 )
const list = ref<any[]>([]) // 树列表的数据
#else
const list = ref<${simpleClassName}Api.${simpleClassName}[]>([]) // 列表的数据
#end
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
const total = ref(0) // 列表的总页数
#end
const queryParams = reactive({
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 )
pageNo: 1,
pageSize: 10,
#end
#foreach ($column in $columns)
#if ($column.listOperation)
#if ($column.listOperationCondition != 'BETWEEN')
$column.javaField: undefined,
#end
#if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
$column.javaField: undefined,
#end
#end
#end
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const params = cloneDeep(queryParams) as any;
#foreach ($column in $columns)
#if ($column.listOperation)
#if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
}
#end
#end
#end
## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType == 2 )
list.value = await get${simpleClassName}List(params);
#else
const data = await get${simpleClassName}Page(params)
list.value = data.list
total.value = data.total
#end
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
#if ( $table.templateType != 2 )
queryParams.pageNo = 1
#end
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: ${simpleClassName}Form,
destroyOnClose: true,
});
/** 创建${table.classComment} */
function onCreate() {
formModalApi.setData({}).open();
}
/** 编辑${table.classComment} */
function onEdit(row: ${simpleClassName}Api.${simpleClassName}) {
formModalApi.setData(row).open();
}
#if (${table.templateType} == 2)## 树表特有:新增下级
/** 新增下级${table.classComment} */
function onAppend(row: ${simpleClassName}Api.${simpleClassName}) {
formModalApi.setData({ ${treeParentColumn.javaField}: row.id }).open();
}
#end
/** 删除${table.classComment} */
async function onDelete(row: ${simpleClassName}Api.${simpleClassName}) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.id]),
duration: 0,
key: 'action_process_msg',
});
try {
await delete${simpleClassName}(row.id as number);
message.success({
content: $t('ui.actionMessage.deleteSuccess', [row.id]),
key: 'action_process_msg',
});
await getList();
} finally {
hideLoading();
}
}
#if ($table.templateType != 2 && $deleteBatchEnable)
/** 批量删除${table.classComment} */
async function onDeleteBatch() {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting'),
duration: 0,
key: 'action_process_msg',
});
try {
await delete${simpleClassName}ListByIds(deleteIds.value);
message.success( $t('ui.actionMessage.deleteSuccess') );
await getList();
} finally {
hideLoading();
}
}
const deleteIds = ref<number[]>([]) // 待删除${table.classComment} ID
function setDeleteIds({
records,
}: {
records: ${simpleClassName}Api.${simpleClassName}[];
}) {
deleteIds.value = records.map((item) => item.id);
}
#end
/** 导出表格 */
async function onExport() {
try {
exportLoading.value = true;
const data = await export${simpleClassName}(queryParams);
downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data });
}finally {
exportLoading.value = false;
}
}
#if (${table.templateType} == 2)
/** 切换树形展开/收缩状态 */
const isExpanded = ref(true);
function toggleExpand() {
isExpanded.value = !isExpanded.value;
tableRef.value?.setAllTreeExpand(isExpanded.value);
}
#end
/** 初始化 */
const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
onMounted(() => {
getList();
});
</script>
<template>
<Page auto-content-height>
<FormModal @success="getList" />
<ContentWrap v-if="!hiddenSearchBar">
<!-- 搜索工作栏 -->
<Form
:model="queryParams"
ref="queryFormRef"
layout="inline"
>
#foreach($column in $columns)
#if ($column.listOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ($column.htmlType == "input")
<Form.Item label="${comment}" name="${javaField}">
<Input
v-model:value="queryParams.${javaField}"
placeholder="请输入${comment}"
allowClear
@pressEnter="handleQuery"
class="w-full"
/>
</Form.Item>
#elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
<Form.Item label="${comment}" name="${javaField}">
<Select
v-model:value="queryParams.${javaField}"
placeholder="请选择${comment}"
allowClear
class="w-full"
>
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
<Select.Option
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Select.Option>
#else## 未设置 dictType 数据字典的情况
<Select.Option label="请选择字典生成" value="" />
#end
</Select>
</Form.Item>
#elseif($column.htmlType == "datetime")
#if ($column.listOperationCondition != "BETWEEN")## 非范围
<Form.Item label="${comment}" name="${javaField}">
<DatePicker
v-model:value="queryParams.${javaField}"
valueFormat="YYYY-MM-DD"
placeholder="选择${comment}"
allowClear
class="w-full"
/>
</Form.Item>
#else## 范围
<Form.Item label="${comment}" name="${javaField}">
<RangePicker
v-model:value="queryParams.${javaField}"
v-bind="getRangePickerDefaultProps()"
class="w-full"
/>
</Form.Item>
#end
#end
#end
#end
<Form.Item>
<Button class="ml-2" @click="resetQuery"> 重置 </Button>
<Button class="ml-2" @click="handleQuery" type="primary">
搜索
</Button>
</Form.Item>
</Form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap title="${table.classComment}">
<template #extra>
<TableToolbar
ref="tableToolbarRef"
v-model:hidden-search="hiddenSearchBar"
>
#if (${table.templateType} == 2)
<Button @click="toggleExpand" class="mr-2">
{{ isExpanded ? '收缩' : '展开' }}
</Button>
#end
<Button
class="ml-2"
:icon="h(Plus)"
type="primary"
@click="onCreate"
v-access:code="['${permissionPrefix}:create']"
>
{{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
</Button>
<Button
:icon="h(Download)"
type="primary"
class="ml-2"
:loading="exportLoading"
@click="onExport"
v-access:code="['${permissionPrefix}:export']"
>
{{ $t('ui.actionTitle.export') }}
</Button>
#if ($table.templateType != 2 && $deleteBatchEnable)
<Button
:icon="h(Trash2)"
type="primary"
danger
class="ml-2"
:disabled="isEmpty(deleteIds)"
@click="onDeleteBatch"
v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']"
>
批量删除
</Button>
#end
</TableToolbar>
</template>
<vxe-table
ref="tableRef"
:data="list"
#if ( $table.templateType == 2 )
:tree-config="{
parentField: '${treeParentColumn.javaField}',
rowField: 'id',
transform: true,
expandAll: true,
reserve: true,
}"
#end
#if ($table.templateType == 11) ## erp情况
@cell-click="onCellClick"
:row-config="{
keyField: 'id',
isHover: true,
isCurrent: true,
}"
#end
show-overflow
:loading="loading"
#if ($table.templateType != 2 && $deleteBatchEnable)
@checkboxAll="setDeleteIds"
@checkboxChange="setDeleteIds"
#end
>
#if ($table.templateType != 2 && $deleteBatchEnable)
<vxe-column type="checkbox" width="40"></vxe-column>
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
<!-- 子表的列表 -->
<vxe-column type="expand" width="60">
<template #content="{ row }">
<!-- 子表的表单 -->
<Tabs v-model:active-key="subTabsName" class="mx-8">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
<${subSimpleClassName}List :${subJoinColumn_strikeCase}="row?.id" />
</Tabs.TabPane>
#end
</Tabs>
</template>
</vxe-column>
#end
#foreach($column in $columns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
{{formatDateTime(row.${javaField})}}
</template>
</vxe-column>
#elseif($column.dictType && "" != $column.dictType)## 数据字典
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
</template>
</vxe-column>
#elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
<vxe-column field="${javaField}" title="${comment}" align="center" tree-node/>
#else
<vxe-column field="${javaField}" title="${comment}" align="center" />
#end
#end
#end
<vxe-column field="operation" title="操作" align="center">
<template #default="{row}">
#if ( $table.templateType == 2 )
<Button
size="small"
type="link"
@click="onAppend(row as any)"
v-access:code="['${permissionPrefix}:create']"
>
新增下级
</Button>
#end
<Button
size="small"
type="link"
@click="onEdit(row as any)"
v-access:code="['${permissionPrefix}:update']"
>
{{ $t('ui.actionTitle.edit') }}
</Button>
<Button
size="small"
type="link"
danger
class="ml-2"
#if ( $table.templateType == 2 )
:disabled="!isEmpty(row?.children)"
#end
@click="onDelete(row as any)"
v-access:code="['${permissionPrefix}:delete']"
>
{{ $t('ui.actionTitle.delete') }}
</Button>
</template>
</vxe-column>
</vxe-table>
#if ( $table.templateType != 2 )
<!-- 分页 -->
<div class="mt-2 flex justify-end">
<Pagination
:total="total"
v-model:current="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
show-size-changer
@change="getList"
/>
</div>
#end
</ContentWrap>
#if ($table.templateType == 11) ## erp情况
<ContentWrap>
<!-- 子表的表单 -->
<Tabs v-model:active-key="subTabsName">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
<${subSimpleClassName}List :${subJoinColumn_strikeCase}="select${simpleClassName}?.id" />
</Tabs.TabPane>
#end
</Tabs>
</ContentWrap>
#end
</Page>
</template>

View File

@@ -0,0 +1,212 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
import type { Rule } from 'ant-design-vue/es/form';
import { useVbenModal } from '@vben/common-ui';
import { Tinymce as RichTextarea } from '#/components/tinymce';
import { ImageUpload, FileUpload } from "#/components/upload";
import { message, Tabs, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'ant-design-vue';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { computed, ref } from 'vue';
import { $t } from '#/locales';
import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
const emit = defineEmits(['success']);
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['${subTable.classComment}'])
: $t('ui.actionTitle.create', ['${subTable.classComment}']);
});
const formRef = ref();
const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
});
const rules: Record<string, Rule[]> = {
#foreach ($column in $subColumns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end
#end
};
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
await formRef.value?.validate();
modalApi.lock();
// 提交表单
const data = formData.value as ${simpleClassName}Api.${subSimpleClassName};
try {
await (formData.value?.id ? update${subSimpleClassName}(data) : create${subSimpleClassName}(data));
// 关闭并提示
await modalApi.close();
emit('success');
message.success({
content: $t('ui.actionMessage.operationSuccess'),
key: 'action_process_msg',
});
} finally {
modalApi.unlock();
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
resetForm()
return;
}
// 加载数据
let data = modalApi.getData<${simpleClassName}Api.${subSimpleClassName}>();
if (!data) {
return;
}
if (data.id) {
modalApi.lock();
try {
data = await get${subSimpleClassName}(data.id);
} finally {
modalApi.unlock();
}
}
// 设置到 values
formData.value = data;
},
});
/** 重置表单 */
const resetForm = () => {
formData.value = {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
};
formRef.value?.resetFields();
}
</script>
<template>
<Modal :title="getTitle">
<Form
ref="formRef"
:model="formData"
:rules="rules"
:label-col="{ span: 5 }"
:wrapper-col="{ span: 18 }"
>
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<Form.Item label="${comment}" name="${javaField}">
<Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
</Form.Item>
#elseif($column.htmlType == "imageUpload")## 图片上传
<Form.Item label="${comment}" name="${javaField}">
<ImageUpload v-model:value="formData.${javaField}" />
</Form.Item>
#elseif($column.htmlType == "fileUpload")## 文件上传
<Form.Item label="${comment}" name="${javaField}">
<FileUpload v-model:value="formData.${javaField}" />
</Form.Item>
#elseif($column.htmlType == "editor")## 文本编辑器
<Form.Item label="${comment}" name="${javaField}">
<RichTextarea v-model="formData.${javaField}" height="500px" />
</Form.Item>
#elseif($column.htmlType == "select")## 下拉框
<Form.Item label="${comment}" name="${javaField}">
<Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<Select.Option
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Select.Option>
#else##没数据字典
<Select.Option label="请选择字典生成" value="" />
#end
</Select>
</Form.Item>
#elseif($column.htmlType == "checkbox")## 多选框
<Form.Item label="${comment}" name="${javaField}">
<CheckboxGroup v-model:value="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<Checkbox
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Checkbox>
#else##没数据字典
<Checkbox label="请选择字典生成" />
#end
</CheckboxGroup>
</Form.Item>
#elseif($column.htmlType == "radio")## 单选框
<Form.Item label="${comment}" name="${javaField}">
<RadioGroup v-model:value="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<Radio
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Radio>
#else##没数据字典
<Radio value="1">请选择字典生成</Radio>
#end
</RadioGroup>
</Form.Item>
#elseif($column.htmlType == "datetime")## 时间框
<Form.Item label="${comment}" name="${javaField}">
<DatePicker
v-model:value="formData.${javaField}"
valueFormat="x"
placeholder="选择${comment}"
/>
</Form.Item>
#elseif($column.htmlType == "textarea")## 文本框
<Form.Item label="${comment}" name="${javaField}">
<Textarea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
</Form.Item>
#end
#end
#end
</Form>
</Modal>
</template>

View File

@@ -0,0 +1,2 @@
## 主表的 normal 和 inner 使用相同的 form 表单
#parse("codegen/vue3_vben5_antd/general/views/modules/form_sub_normal.vue.vm")

View File

@@ -0,0 +1,338 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subClassNameVar = $subClassNameVars.get($subIndex))
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
import { message, Tabs, Form, Input, Textarea,Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'ant-design-vue';
import { computed, ref, h, onMounted,watch,nextTick } from 'vue';
import { $t } from '#/locales';
import { DICT_TYPE, getDictOptions } from '#/utils';
#if ($subTable.subJoinMany) ## 一对多
import type { VxeTableInstance } from '#/adapter/vxe-table';
import { Plus } from "@vben/icons";
import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
#else
import type { Rule } from 'ant-design-vue/es/form';
import { Tinymce as RichTextarea } from '#/components/tinymce';
import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
#end
const props = defineProps<{
${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
}>()
#if ($subTable.subJoinMany) ## 一对多
const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 列表的数据
const tableRef = ref<VxeTableInstance>();
/** 添加${subTable.classComment} */
const onAdd = async () => {
await tableRef.value?.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1);
}
/** 删除${subTable.classComment} */
const onDelete = async (row: ${simpleClassName}Api.${subSimpleClassName}) => {
await tableRef.value?.remove(row);
}
/** 提供获取表格数据的方法供父组件调用 */
defineExpose({
getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => {
const data = list.value as ${simpleClassName}Api.${subSimpleClassName}[];
const removeRecords = tableRef.value?.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
const insertRecords = tableRef.value?.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
return data
.filter((row) => !removeRecords.some((removed) => removed.id === row.id))
?.concat(insertRecords.map((row: any) => ({ ...row, id: undefined })));
},
});
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
async (val) => {
if (!val) {
return;
}
list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
},
{ immediate: true },
);
#else
const formRef = ref();
const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox")
$column.javaField: [],
#else
$column.javaField: undefined,
#end
#end
#end
});
const rules: Record<string, Rule[]> = {
#foreach ($column in $subColumns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end
#end
};
/** 暴露出表单校验方法和表单值获取方法 */
defineExpose({
validate: async () => await formRef.value?.validate(),
getValues: ()=> formData.value,
});
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
async (val) => {
if (!val) {
return;
}
await nextTick();
formData.value = await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
},
{ immediate: true },
);
#end
</script>
<template>
#if ($subTable.subJoinMany) ## 一对多
<vxe-table ref="tableRef" :data="list" show-overflow class="mx-4">
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($comment = $column.columnComment)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<Input v-model:value="row.${javaField}" />
</template>
</vxe-column>
#elseif($column.htmlType == "imageUpload")## 图片上传
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<ImageUpload v-model:value="row.${javaField}" />
</template>
</vxe-column>
#elseif($column.htmlType == "fileUpload")## 文件上传
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<FileUpload v-model:value="row.${javaField}" />
</template>
</vxe-column>
#elseif($column.htmlType == "select")## 下拉框
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<Select v-model:value="row.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<Select.Option
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Select.Option>
#else##没数据字典
<Select.Option label="请选择字典生成" value="" />
#end
</Select>
</template>
</vxe-column>
#elseif($column.htmlType == "checkbox")## 多选框
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<CheckboxGroup v-model:value="row.${javaField}">
#if ("" != $dictType)## 有数据字典
<Checkbox
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Checkbox>
#else##没数据字典
<Checkbox label="请选择字典生成" />
#end
</CheckboxGroup>
</template>
</vxe-column>
#elseif($column.htmlType == "radio")## 单选框
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<RadioGroup v-model:value="row.${javaField}">
#if ("" != $dictType)## 有数据字典
<Radio
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Radio>
#else##没数据字典
<Radio value="1">请选择字典生成</Radio>
#end
</RadioGroup>
</template>
</vxe-column>
#elseif($column.htmlType == "datetime")## 时间框
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<DatePicker
v-model:value="row.${javaField}"
:showTime="true"
format="YYYY-MM-DD HH:mm:ss"
valueFormat='x'
/>
</template>
</vxe-column>
#elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<Textarea v-model:value="row.${javaField}" />
</template>
</vxe-column>
#end
#end
#end
<vxe-column field="operation" title="操作" align="center">
<template #default="{row}">
<Button
size="small"
type="link"
danger
@click="onDelete(row as any)"
v-access:code="['${permissionPrefix}:delete']"
>
{{ $t('ui.actionTitle.delete') }}
</Button>
</template>
</vxe-column>
</vxe-table>
<div class="flex justify-center mt-4">
<Button :icon="h(Plus)" type="primary" ghost @click="onAdd" v-access:code="['${permissionPrefix}:create']">
{{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
</Button>
</div>
#else
<Form
ref="formRef"
class="mx-4"
:model="formData"
:rules="rules"
:label-col="{ span: 5 }"
:wrapper-col="{ span: 18 }"
>
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<Form.Item label="${comment}" name="${javaField}">
<Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
</Form.Item>
#elseif($column.htmlType == "imageUpload")## 图片上传
<Form.Item label="${comment}" name="${javaField}">
<ImageUpload v-model:value="formData.${javaField}" />
</Form.Item>
#elseif($column.htmlType == "fileUpload")## 文件上传
<Form.Item label="${comment}" name="${javaField}">
<FileUpload v-model:value="formData.${javaField}" />
</Form.Item>
#elseif($column.htmlType == "editor")## 文本编辑器
<Form.Item label="${comment}" name="${javaField}">
<RichTextarea v-model="formData.${javaField}" height="500px" />
</Form.Item>
#elseif($column.htmlType == "select")## 下拉框
<Form.Item label="${comment}" name="${javaField}">
<Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
#if ("" != $dictType)## 有数据字典
<Select.Option
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Select.Option>
#else##没数据字典
<Select.Option label="请选择字典生成" value="" />
#end
</Select>
</Form.Item>
#elseif($column.htmlType == "checkbox")## 多选框
<Form.Item label="${comment}" name="${javaField}">
<CheckboxGroup v-model:value="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<Checkbox
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Checkbox>
#else##没数据字典
<Checkbox label="请选择字典生成" />
#end
</CheckboxGroup>
</Form.Item>
#elseif($column.htmlType == "radio")## 单选框
<Form.Item label="${comment}" name="${javaField}">
<RadioGroup v-model:value="formData.${javaField}">
#if ("" != $dictType)## 有数据字典
<Radio
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Radio>
#else##没数据字典
<Radio value="1">请选择字典生成</Radio>
#end
</RadioGroup>
</Form.Item>
#elseif($column.htmlType == "datetime")## 时间框
<Form.Item label="${comment}" name="${javaField}">
<DatePicker
v-model:value="formData.${javaField}"
valueFormat="x"
placeholder="选择${comment}"
/>
</Form.Item>
#elseif($column.htmlType == "textarea")## 文本框
<Form.Item label="${comment}" name="${javaField}">
<Textarea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
</Form.Item>
#end
#end
#end
</Form>
#end
</template>

View File

@@ -0,0 +1,426 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex))
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
import type { VxeTableInstance } from '#/adapter/vxe-table';
import { DictTag } from '#/components/dict-tag';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
import { reactive,ref, h, nextTick,watch,onMounted } from 'vue';
import { cloneDeep, formatDateTime } from '@vben/utils';
import { ContentWrap } from '#/components/content-wrap';
#if ($table.templateType == 11) ## erp
import { useVbenModal } from '@vben/common-ui';
import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
import { Tinymce as RichTextarea } from '#/components/tinymce';
import { ImageUpload, FileUpload } from "#/components/upload";
import { message,Button, Tabs,Pagination, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox,RangePicker, DatePicker, TreeSelect } from 'ant-design-vue';
import { Plus, Trash2 } from '@vben/icons';
import { $t } from '#/locales';
import { TableToolbar } from '#/components/table-toolbar';
import { useTableToolbar } from '#/hooks';
#end
#if ($table.templateType == 11) ## erp
import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}ListByIds,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${table.businessName}';
import { isEmpty } from '@vben/utils';
#else
#if ($subTable.subJoinMany) ## 一对多
import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
#else
import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
#end
#end
const props = defineProps<{
${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
}>()
#if ($table.templateType == 11) ## erp
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: ${subSimpleClassName}Form,
destroyOnClose: true,
});
/** 创建${subTable.classComment} */
function onCreate() {
if (!props.${subJoinColumn.javaField}){
message.warning("请先选择一个${table.classComment}!")
return
}
formModalApi.setData({${subJoinColumn.javaField}: props.${subJoinColumn.javaField}}).open();
}
/** 编辑${subTable.classComment} */
function onEdit(row: ${simpleClassName}Api.${subSimpleClassName}) {
formModalApi.setData(row).open();
}
/** 删除${subTable.classComment} */
async function onDelete(row: ${simpleClassName}Api.${subSimpleClassName}) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.id]),
duration: 0,
key: 'action_process_msg',
});
try {
await delete${subSimpleClassName}(row.id as number);
message.success({
content: $t('ui.actionMessage.deleteSuccess', [row.id]),
key: 'action_process_msg',
});
await getList();
} finally {
hideLoading();
}
}
#if ($deleteBatchEnable)
/** 批量删除${subTable.classComment} */
async function onDeleteBatch() {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting'),
duration: 0,
key: 'action_process_msg',
});
try {
await delete${subSimpleClassName}ListByIds(deleteIds.value);
message.success( $t('ui.actionMessage.deleteSuccess') );
await getList();
} finally {
hideLoading();
}
}
const deleteIds = ref<number[]>([]) // 待删除${subTable.classComment} ID
function setDeleteIds({
records,
}: {
records: ${simpleClassName}Api.${subSimpleClassName}[];
}) {
deleteIds.value = records.map((item) => item.id);
}
#end
#end
const loading = ref(true) // 列表的加载中
const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 列表的数据
#if ($table.templateType == 11) ## erp
const total = ref(0) // 列表的总页数
#end
#if ($table.templateType == 11) ## erp
const queryFormRef = ref() // 搜索的表单
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
#foreach ($column in $subColumns)
#if ($column.listOperation)
#if ($column.listOperationCondition != 'BETWEEN')
$column.javaField: undefined,
#end
#if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
$column.javaField: undefined,
#end
#end
#end
})
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
#end
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
if (!props.${subJoinColumn.javaField}){
return []
}
## 特殊:树表专属逻辑(树不需要分页接口)
#if ($table.templateType == 11) ## erp
const params = cloneDeep(queryParams) as any;
#foreach ($column in $columns)
#if ($column.listOperation)
#if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
}
#end
#end
#end
params.${subJoinColumn.javaField} = props.${subJoinColumn.javaField};
const data = await get${subSimpleClassName}Page(params)
list.value = data.list
total.value = data.total
#else
#if ($subTable.subJoinMany) ## 一对多
list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
#else
list.value = [await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)];
#end
#end
} finally {
loading.value = false
}
}
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
async (val) => {
if (!val) {
return;
}
await nextTick();
await getList()
},
{ immediate: true },
);
#if ($table.templateType == 11) ## erp
/** 初始化 */
const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
onMounted(() => {
getList();
});
#end
</script>
<template>
#if ($table.templateType == 11) ## erp
<FormModal @success="getList" />
<div class="h-[600px]">
<ContentWrap v-if="!hiddenSearchBar">
<!-- 搜索工作栏 -->
<Form
:model="queryParams"
ref="queryFormRef"
layout="inline"
>
#foreach($column in $subColumns)
#if ($column.listOperation)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($javaType = $column.javaType)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ($column.htmlType == "input")
<Form.Item label="${comment}" name="${javaField}">
<Input
v-model:value="queryParams.${javaField}"
placeholder="请输入${comment}"
allowClear
@pressEnter="handleQuery"
class="w-full"
/>
</Form.Item>
#elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
<Form.Item label="${comment}" name="${javaField}">
<Select
v-model:value="queryParams.${javaField}"
placeholder="请选择${comment}"
allowClear
class="w-full"
>
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
<Select.Option
v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</Select.Option>
#else## 未设置 dictType 数据字典的情况
<Select.Option label="请选择字典生成" value="" />
#end
</Select>
</Form.Item>
#elseif($column.htmlType == "datetime")
#if ($column.listOperationCondition != "BETWEEN")## 非范围
<Form.Item label="${comment}" name="${javaField}">
<DatePicker
v-model:value="queryParams.${javaField}"
valueFormat="YYYY-MM-DD"
placeholder="选择${comment}"
allowClear
class="w-full"
/>
</Form.Item>
#else## 范围
<Form.Item label="${comment}" name="${javaField}">
<RangePicker
v-model:value="queryParams.${javaField}"
v-bind="getRangePickerDefaultProps()"
class="w-full"
/>
</Form.Item>
#end
#end
#end
#end
<Form.Item>
<Button class="ml-2" @click="resetQuery"> 重置 </Button>
<Button class="ml-2" @click="handleQuery" type="primary">
搜索
</Button>
</Form.Item>
</Form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap title="${table.classComment}">
<template #extra>
<TableToolbar
ref="tableToolbarRef"
v-model:hidden-search="hiddenSearchBar"
>
<Button
class="ml-2"
:icon="h(Plus)"
type="primary"
@click="onCreate"
v-access:code="['${permissionPrefix}:create']"
>
{{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
</Button>
#if ($deleteBatchEnable)
<Button
:icon="h(Trash2)"
type="primary"
danger
class="ml-2"
:disabled="isEmpty(deleteIds)"
@click="onDeleteBatch"
v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']"
>
批量删除
</Button>
#end
</TableToolbar>
</template>
<vxe-table
ref="tableRef"
:data="list"
show-overflow
:loading="loading"
#if ($deleteBatchEnable)
@checkboxAll="setDeleteIds"
@checkboxChange="setDeleteIds"
#end
>
#if ($deleteBatchEnable)
<vxe-column type="checkbox" width="40"></vxe-column>
#end
#foreach($column in $subColumns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
{{formatDateTime(row.${javaField})}}
</template>
</vxe-column>
#elseif($column.dictType && "" != $column.dictType)## 数据字典
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
</template>
</vxe-column>
#elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
<vxe-column field="${javaField}" title="${comment}" align="center" tree-node/>
#else
<vxe-column field="${javaField}" title="${comment}" align="center" />
#end
#end
#end
<vxe-column field="operation" title="操作" align="center">
<template #default="{row}">
<Button
size="small"
type="link"
@click="onEdit(row as any)"
v-access:code="['${permissionPrefix}:update']"
>
{{ $t('ui.actionTitle.edit') }}
</Button>
<Button
size="small"
type="link"
danger
class="ml-2"
@click="onDelete(row as any)"
v-access:code="['${permissionPrefix}:delete']"
>
{{ $t('ui.actionTitle.delete') }}
</Button>
</template>
</vxe-column>
</vxe-table>
<!-- 分页 -->
<div class="mt-2 flex justify-end">
<Pagination
:total="total"
v-model:current="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
show-size-changer
@change="getList"
/>
</div>
</ContentWrap>
</div>
#else
<ContentWrap title="${subTable.classComment}列表">
<vxe-table
:data="list"
show-overflow
:loading="loading"
>
#foreach($column in $subColumns)
#if ($column.listOperationResult)
#set ($dictType=$column.dictType)
#set ($javaField = $column.javaField)
#set ($comment=$column.columnComment)
#if ($column.javaType == "LocalDateTime")## 时间类型
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
{{formatDateTime(row.${javaField})}}
</template>
</vxe-column>
#elseif($column.dictType && "" != $column.dictType)## 数据字典
<vxe-column field="${javaField}" title="${comment}" align="center">
<template #default="{row}">
<dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
</template>
</vxe-column>
#else
<vxe-column field="${javaField}" title="${comment}" align="center" />
#end
#end
#end
</vxe-table>
</ContentWrap>
#end
</template>

View File

@@ -0,0 +1,4 @@
## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
## 1inner 使用 list 不分页erp 使用 page 分页
## 2erp 支持单个子表的新增、修改、删除inner 不支持
#parse("codegen/vue3_vben5_antd/general/views/modules/list_sub_erp.vue.vm")

View File

@@ -0,0 +1,167 @@
import type { PageParam, PageResult } from '@vben/request';
import type { Dayjs } from 'dayjs';
import { requestClient } from '#/api/request';
#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
export namespace ${simpleClassName}Api {
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subColumns = $subColumnsList.get($index))##当前字段数组
/** ${subTable.classComment}信息 */
export interface ${subSimpleClassName} {
#foreach ($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
#elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
#else
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
#end
#end
#end
}
#end
/** ${table.classComment}信息 */
export interface ${simpleClassName} {
#foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
#elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
#else
${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
#end
#end
#end
#if ( $table.templateType == 2 )
children?: ${simpleClassName}[];
#end
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#if ( $subTable.subJoinMany )
${subSimpleClassName.toLowerCase()}s?: ${subSimpleClassName}[]
#else
${subSimpleClassName.toLowerCase()}?: ${subSimpleClassName}
#end
#end
#end
}
}
#if ( $table.templateType != 2 )
/** 查询${table.classComment}分页 */
export function get${simpleClassName}Page(params: PageParam) {
return requestClient.get<PageResult<${simpleClassName}Api.${simpleClassName}>>('${baseURL}/page', { params });
}
#else
/** 查询${table.classComment}列表 */
export function get${simpleClassName}List(params: any) {
return requestClient.get<${simpleClassName}Api.${simpleClassName}[]>('${baseURL}/list', { params });
}
#end
/** 查询${table.classComment}详情 */
export function get${simpleClassName}(id: number) {
return requestClient.get<${simpleClassName}Api.${simpleClassName}>(`${baseURL}/get?id=${id}`);
}
/** 新增${table.classComment} */
export function create${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
return requestClient.post('${baseURL}/create', data);
}
/** 修改${table.classComment} */
export function update${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
return requestClient.put('${baseURL}/update', data);
}
/** 删除${table.classComment} */
export function delete${simpleClassName}(id: number) {
return requestClient.delete(`${baseURL}/delete?id=${id}`);
}
#if ( $table.templateType != 2 && $deleteBatchEnable)
/** 批量删除${table.classComment} */
export function delete${simpleClassName}ListByIds(ids: number[]) {
return requestClient.delete(`${baseURL}/delete-list?ids=${ids.join(',')}`)
}
#end
/** 导出${table.classComment} */
export function export${simpleClassName}(params: any) {
return requestClient.download('${baseURL}/export-excel', params);
}
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
#set ($subClassNameVar = $subClassNameVars.get($index))
// ==================== 子表($subTable.classComment ====================
## 情况一MASTER_ERP 时,需要分查询页子表
#if ( $table.templateType == 11 )
/** 获得${subTable.classComment}分页 */
export function get${subSimpleClassName}Page(params: PageParam) {
return requestClient.get<PageResult<${simpleClassName}Api.${subSimpleClassName}>>(`${baseURL}/${subSimpleClassName_strikeCase}/page`, { params });
}
## 情况二:非 MASTER_ERP 时,需要列表查询子表
#else
#if ( $subTable.subJoinMany )
/** 获得${subTable.classComment}列表 */
export function get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
return requestClient.get<${simpleClassName}Api.${subSimpleClassName}[]>(`${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
}
#else
/** 获得${subTable.classComment} */
export function get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
}
#end
#end
## 特殊MASTER_ERP 时,支持单个的新增、修改、删除操作
#if ( $table.templateType == 11 )
/** 新增${subTable.classComment} */
export function create${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
return requestClient.post(`${baseURL}/${subSimpleClassName_strikeCase}/create`, data);
}
/** 修改${subTable.classComment} */
export function update${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
return requestClient.put(`${baseURL}/${subSimpleClassName_strikeCase}/update`, data);
}
/** 删除${subTable.classComment} */
export function delete${subSimpleClassName}(id: number) {
return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete?id=${id}`);
}
#if ($deleteBatchEnable)
/** 批量删除${subTable.classComment} */
export function delete${subSimpleClassName}ListByIds(ids: number[]) {
return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete-list?ids=${ids.join(',')}`)
}
#end
/** 获得${subTable.classComment} */
export function get${subSimpleClassName}(id: number) {
return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get?id=${id}`);
}
#end
#end

View File

@@ -0,0 +1,607 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
import { z } from '#/adapter/form';
import {
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
#if(${table.templateType} == 2)## 树表需要导入这些
import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}';
import { handleTree } from '@vben/utils';
#end
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'id',
component: 'Input',
dependencies: {
triggerFields: [''],
show: () => false,
},
},
#if(${table.templateType} == 2)## 树表特有字段:上级
{
fieldName: '${treeParentColumn.javaField}',
label: '上级${table.classComment}',
component: 'ApiTreeSelect',
componentProps: {
allowClear: true,
api: async () => {
const data = await get${simpleClassName}List({});
data.unshift({
id: 0,
${treeNameColumn.javaField}: '顶级${table.classComment}',
});
return handleTree(data);
},
labelField: '${treeNameColumn.javaField}',
valueField: 'id',
childrenField: 'children',
placeholder: '请选择上级${table.classComment}',
treeDefaultExpandAll: true,
},
rules: 'selectRequired',
},
#end
#foreach($column in $columns)
#if ($column.createOperation || $column.updateOperation)
#if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 树表中已经添加了父ID字段这里排除
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
{
fieldName: '${javaField}',
label: '${comment}',
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
rules: 'required',
#end
#if ($column.htmlType == "input")
component: 'Input',
componentProps: {
placeholder: '请输入${comment}',
},
#elseif($column.htmlType == "imageUpload")## 图片上传
component: 'ImageUpload',
#elseif($column.htmlType == "fileUpload")## 文件上传
component: 'FileUpload',
#elseif($column.htmlType == "editor")## 文本编辑器
component: 'RichTextarea',
#elseif($column.htmlType == "select")## 下拉框
component: 'Select',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
placeholder: '请选择${comment}',
},
#elseif($column.htmlType == "checkbox")## 多选框
component: 'Checkbox',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
},
#elseif($column.htmlType == "radio")## 单选框
component: 'RadioGroup',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
buttonStyle: 'solid',
optionType: 'button',
},
#elseif($column.htmlType == "datetime")## 时间框
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
},
#elseif($column.htmlType == "textarea")## 文本域
component: 'Textarea',
componentProps: {
placeholder: '请输入${comment}',
},
#elseif($column.htmlType == "inputNumber")## 数字输入框
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
},
#end
},
#end
#end
#end
];
}
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
return [
#foreach($column in $columns)
#if ($column.listOperation)
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
{
fieldName: '${javaField}',
label: '${comment}',
#if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
component: 'Input',
componentProps: {
allowClear: true,
placeholder: '请输入${comment}',
},
#elseif ($column.htmlType == "select" || $column.htmlType == "radio")
component: 'Select',
componentProps: {
allowClear: true,
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else## 未设置 dictType 数据字典的情况
options: [],
#end
placeholder: '请选择${comment}',
},
#elseif($column.htmlType == "datetime")
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
#end
},
#end
#end
];
}
/** 列表的字段 */
export function useGridColumns(): VxeTableGridOptions<${simpleClassName}Api.${simpleClassName}>['columns'] {
return [
#if ($table.templateType != 2 && $deleteBatchEnable)
{ type: 'checkbox', width: 40 },
#end
#if ($table.templateType == 12) ## 内嵌情况
{ type: 'expand', width: 80, slots: { content: 'expand_content' } },
#end
#foreach($column in $columns)
#if ($column.listOperationResult)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
{
field: '${javaField}',
title: '${comment}',
minWidth: 120,
#if ($column.javaType == "LocalDateTime")## 时间类型
formatter: 'formatDateTime',
#elseif("" != $dictType)## 数据字典
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.$dictType.toUpperCase() },
},
#end
#if (${table.templateType} == 2 && $column.id == $treeNameColumn.id)## 树表特有:标记树节点列
treeNode: true,
#end
},
#end
#end
{
title: '操作',
width: 200,
fixed: 'right',
slots: { default: 'actions' },
},
];
}
## 标准模式和内嵌模式时主子关系一对一则生成表单schema,一对多则生成列表schema内嵌模式时表单schema也要生成。erp 模式时都生成
## 特殊:主子表专属逻辑
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subColumns = $subColumnsList.get($index))##当前字段数组
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
// ==================== 子表($subTable.classComment ====================
#if ($table.templateType == 11) ## erp 情况
/** 新增/修改的表单 */
export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'id',
component: 'Input',
dependencies: {
triggerFields: [''],
show: () => false,
},
},
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 树表中已经添加了父ID字段这里排除
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#else
{
fieldName: '${javaField}',
label: '${comment}',
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
rules: 'required',
#end
#if ($column.htmlType == "input")
component: 'Input',
componentProps: {
placeholder: '请输入${comment}',
},
#elseif($column.htmlType == "imageUpload")## 图片上传
component: 'ImageUpload',
#elseif($column.htmlType == "fileUpload")## 文件上传
component: 'FileUpload',
#elseif($column.htmlType == "editor")## 文本编辑器
component: 'RichTextarea',
#elseif($column.htmlType == "select")## 下拉框
component: 'Select',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
placeholder: '请选择${comment}',
},
#elseif($column.htmlType == "checkbox")## 多选框
component: 'Checkbox',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
},
#elseif($column.htmlType == "radio")## 单选框
component: 'RadioGroup',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
buttonStyle: 'solid',
optionType: 'button',
},
#elseif($column.htmlType == "datetime")## 时间框
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
},
#elseif($column.htmlType == "textarea")## 文本域
component: 'Textarea',
componentProps: {
placeholder: '请输入${comment}',
},
#elseif($column.htmlType == "inputNumber")## 数字输入框
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
},
#end
},
#end
#end
#end
#end
];
}
/** 列表的搜索表单 */
export function use${subSimpleClassName}GridFormSchema(): VbenFormSchema[] {
return [
#foreach($column in $subColumns)
#if ($column.listOperation)
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
{
fieldName: '${javaField}',
label: '${comment}',
#if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
component: 'Input',
componentProps: {
allowClear: true,
placeholder: '请输入${comment}',
},
#elseif ($column.htmlType == "select" || $column.htmlType == "radio")
component: 'Select',
componentProps: {
allowClear: true,
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else## 未设置 dictType 数据字典的情况
options: [],
#end
placeholder: '请选择${comment}',
},
#elseif($column.htmlType == "datetime")
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
#end
},
#end
#end
];
}
/** 列表的字段 */
export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
return [
#if ($table.templateType != 2 && $deleteBatchEnable)
{ type: 'checkbox', width: 40 },
#end
#foreach($column in $subColumns)
#if ($column.listOperationResult)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
{
field: '${javaField}',
title: '${comment}',
minWidth: 120,
#if ($column.javaType == "LocalDateTime")## 时间类型
formatter: 'formatDateTime',
#elseif("" != $dictType)## 数据字典
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.$dictType.toUpperCase() },
},
#end
},
#end
#end
{
title: '操作',
width: 200,
fixed: 'right',
slots: { default: 'actions' },
},
];
}
#else
#if ($subTable.subJoinMany) ## 一对多
/** 新增/修改列表的字段 */
export function use${subSimpleClassName}GridEditColumns(
onActionClick?: OnActionClickFn<${simpleClassName}Api.${subSimpleClassName}>,
): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
return [
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if (!$column.primaryKey && $column.listOperationResult && $column.id != $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
{
field: '${javaField}',
title: '${comment}',
minWidth: 120,
slots: { default: '${javaField}' },
#if ($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio")
#if ("" != $dictType)## 有数据字典
params: {
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
},
#else
params: {
options: [],
},
#end
#end
},
#end
#end
#end
{
title: '操作',
width: 200,
fixed: 'right',
slots: { default: 'actions' },
},
];
}
#else
/** 新增/修改的表单 */
export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'id',
component: 'Input',
dependencies: {
triggerFields: [''],
show: () => false,
},
},
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 树表中已经添加了父ID字段这里排除
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
#if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
#set ($dictMethod = "number")
#elseif ($javaType == "String")
#set ($dictMethod = "string")
#elseif ($javaType == "Boolean")
#set ($dictMethod = "boolean")
#end
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#else
{
fieldName: '${javaField}',
label: '${comment}',
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
rules: 'required',
#end
#if ($column.htmlType == "input")
component: 'Input',
componentProps: {
placeholder: '请输入${comment}',
},
#elseif($column.htmlType == "imageUpload")## 图片上传
component: 'ImageUpload',
#elseif($column.htmlType == "fileUpload")## 文件上传
component: 'FileUpload',
#elseif($column.htmlType == "editor")## 文本编辑器
component: 'RichTextarea',
#elseif($column.htmlType == "select")## 下拉框
component: 'Select',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
placeholder: '请选择${comment}',
},
#elseif($column.htmlType == "checkbox")## 多选框
component: 'Checkbox',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
},
#elseif($column.htmlType == "radio")## 单选框
component: 'RadioGroup',
componentProps: {
#if ("" != $dictType)## 有数据字典
options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
#else##没数据字典
options: [],
#end
buttonStyle: 'solid',
optionType: 'button',
},
#elseif($column.htmlType == "datetime")## 时间框
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
},
#elseif($column.htmlType == "textarea")## 文本域
component: 'Textarea',
componentProps: {
placeholder: '请输入${comment}',
},
#elseif($column.htmlType == "inputNumber")## 数字输入框
component: 'InputNumber',
componentProps: {
min: 0,
controlsPosition: 'right',
placeholder: '请输入${comment}',
},
#end
},
#end
#end
#end
#end
];
}
#end
#if ($table.templateType == 12) ## 内嵌情况
/** 列表的字段 */
export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
return [
#foreach($column in $subColumns)
#if ($column.listOperationResult)
#set ($dictType = $column.dictType)
#set ($javaField = $column.javaField)
#set ($comment = $column.columnComment)
{
field: '${javaField}',
title: '${comment}',
minWidth: 120,
#if ($column.javaType == "LocalDateTime")## 时间类型
formatter: 'formatDateTime',
#elseif("" != $dictType)## 数据字典
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.$dictType.toUpperCase() },
},
#end
},
#end
#end
];
}
#end
#end
#end

View File

@@ -0,0 +1,154 @@
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
import { useVbenModal } from '@vben/common-ui';
import { message, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue';
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
#end
#end
import { computed, ref } from 'vue';
import { $t } from '#/locales';
import { useVbenForm } from '#/adapter/form';
import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
import { useFormSchema } from '../data';
const emit = defineEmits(['success']);
const formData = ref<${simpleClassName}Api.${simpleClassName}>();
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['${table.classComment}'])
: $t('ui.actionTitle.create', ['${table.classComment}']);
});
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
/** 子表的表单 */
const subTabsName = ref('$subClassNameVars.get(0)')
#foreach ($subClassNameVar in $subClassNameVars)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
const ${subClassNameVar}FormRef = ref<InstanceType<typeof ${subSimpleClassName}Form>>()
#end
#end
#end
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 80,
},
layout: 'horizontal',
schema: useFormSchema(),
showDefaultActions: false
});
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) {
return;
}
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
// 校验子表单
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#if ($subTable.subJoinMany) ## 一对多
## TODO 列表值校验?
#else
const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate();
if (!${subClassNameVar}Valid) {
subTabsName.value = '${subClassNameVar}';
return;
}
#end
#end
#end
#end
modalApi.lock();
// 提交表单
const data = (await formApi.getValues()) as ${simpleClassName}Api.${simpleClassName};
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 )
// 拼接子表的数据
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#if ($subTable.subJoinMany)
data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
#else
data.${subClassNameVar} = await ${subClassNameVar}FormRef.value?.getValues();
#end
#end
#end
#end
try {
await (formData.value?.id ? update${simpleClassName}(data) : create${simpleClassName}(data));
// 关闭并提示
await modalApi.close();
emit('success');
message.success( $t('ui.actionMessage.operationSuccess') );
} finally {
modalApi.unlock();
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = undefined;
return;
}
// 加载数据
let data = modalApi.getData<${simpleClassName}Api.${simpleClassName}>();
if (!data) {
return;
}
if (data.id) {
modalApi.lock();
try {
data = await get${simpleClassName}(data.id);
} finally {
modalApi.unlock();
}
}
// 设置到 values
formData.value = data;
await formApi.setValues(formData.value);
},
});
</script>
<template>
<Modal :title="getTitle">
<Form class="mx-4" />
## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 )
<!-- 子表的表单 -->
<Tabs v-model:active-key="subTabsName">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
<${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" />
</Tabs.TabPane>
#end
</Tabs>
#end
</Modal>
</template>

View File

@@ -0,0 +1,316 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
import { Page, useVbenModal } from '@vben/common-ui';
import { message,Tabs } from 'ant-design-vue';
import Form from './modules/form.vue';
## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames)
#set ($index = $foreach.count - 1)
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
import ${subSimpleClassName}List from './modules/${subSimpleClassName_strikeCase}-list.vue'
#end
#end
import { ref, computed } from 'vue';
import { $t } from '#/locales';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
#if (${table.templateType} == 2)## 树表接口
import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
#else## 标准表接口
import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}ListByIds,#end export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
#end
import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
import { useGridColumns, useGridFormSchema } from './data';
#if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况
/** 子表的列表 */
const subTabsName = ref('$subClassNameVars.get(0)')
#if ($table.templateType == 11)
const select${simpleClassName} = ref<${simpleClassName}Api.${simpleClassName}>();
#end
#end
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
destroyOnClose: true,
});
#if (${table.templateType} == 2)## 树表特有:控制表格展开收缩
/** 切换树形展开/收缩状态 */
const isExpanded = ref(true);
function toggleExpand() {
isExpanded.value = !isExpanded.value;
gridApi.grid.setAllTreeExpand(isExpanded.value);
}
#end
/** 刷新表格 */
function onRefresh() {
#if ($table.templateType == 12) ## 内嵌情况
gridApi.reload();
#else
gridApi.query();
#end
}
/** 创建${table.classComment} */
function handleCreate() {
formModalApi.setData({}).open();
}
/** 编辑${table.classComment} */
function handleEdit(row: ${simpleClassName}Api.${simpleClassName}) {
formModalApi.setData(row).open();
}
#if (${table.templateType} == 2)## 树表特有:新增下级
/** 新增下级${table.classComment} */
function handleAppend(row: ${simpleClassName}Api.${simpleClassName}) {
formModalApi.setData({ ${treeParentColumn.javaField}: row.id }).open();
}
#end
/** 删除${table.classComment} */
async function handleDelete(row: ${simpleClassName}Api.${simpleClassName}) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.id]),
key: 'action_key_msg',
});
try {
await delete${simpleClassName}(row.id as number);
message.success({
content: $t('ui.actionMessage.deleteSuccess', [row.id]),
key: 'action_key_msg',
});
onRefresh();
} finally {
hideLoading();
}
}
#if ($table.templateType != 2 && $deleteBatchEnable)
/** 批量删除${table.classComment} */
async function handleDeleteBatch() {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting'),
key: 'action_key_msg',
});
try {
await delete${simpleClassName}ListByIds(deleteIds.value);
message.success({
content: $t('ui.actionMessage.deleteSuccess'),
key: 'action_key_msg',
});
onRefresh();
} finally {
hideLoading();
}
}
const deleteIds = ref<number[]>([]) // 待删除${table.classComment} ID
function setDeleteIds({
records,
}: {
records: ${simpleClassName}Api.${simpleClassName}[];
}) {
deleteIds.value = records.map((item) => item.id);
}
#end
/** 导出表格 */
async function handleExport() {
const data = await export${simpleClassName}(await gridApi.formApi.getValues());
downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data });
}
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
},
gridOptions: {
columns: useGridColumns(),
#if (${table.templateType} == 11)
height: '600px',
#else
height: 'auto',
#end
#if (${table.templateType} == 2)## 树表设置
treeConfig: {
parentField: '${treeParentColumn.javaField}',
rowField: 'id',
transform: true,
expandAll: true,
reserve: true,
},
pagerConfig: {
enabled: false,
},
#else## 标准表设置
pagerConfig: {
enabled: true,
},
#end
proxyConfig: {
ajax: {
#if (${table.templateType} == 2)## 树表数据加载
query: async (_, formValues) => {
return await get${simpleClassName}List(formValues);
},
#else## 标准表数据加载
query: async ({ page }, formValues) => {
return await get${simpleClassName}Page({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
#end
},
},
rowConfig: {
keyField: 'id',
isHover: true,
#if (${table.templateType} == 11)
isCurrent: true,
#end
},
toolbarConfig: {
refresh: { code: 'query' },
search: true,
},
} as VxeTableGridOptions<${simpleClassName}Api.${simpleClassName}>,
#if (${table.templateType} == 11 || $deleteBatchEnable)
gridEvents:{
#if(${table.templateType} == 11)
cellClick: ({ row }: { row: ${simpleClassName}Api.${simpleClassName}}) => {
select${simpleClassName}.value = row;
},
#end
#if($deleteBatchEnable)
checkboxAll: setDeleteIds,
checkboxChange: setDeleteIds,
#end
}
#end
});
</script>
<template>
<Page auto-content-height>
<FormModal @success="onRefresh" />
#if ($table.templateType == 11) ## erp情况
<div>
#end
<Grid table-title="${table.classComment}列表">
#if ($table.templateType == 12) ## 内嵌情况
<template #expand_content="{ row }">
<!-- 子表的表单 -->
<Tabs v-model:active-key="subTabsName" class="mx-8">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
<${subSimpleClassName}List :${subJoinColumn_strikeCase}="row?.id" />
</Tabs.TabPane>
#end
</Tabs>
</template>
#end
<template #toolbar-tools>
<TableAction
:actions="[
#if (${table.templateType} == 2)## 树表特有:展开/收缩按钮
{
label: isExpanded ? '收缩' : '展开',
type: 'primary',
onClick: toggleExpand,
},
#end
{
label: $t('ui.actionTitle.create', ['${table.classComment}']),
type: 'primary',
icon: ACTION_ICON.ADD,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
onClick: handleCreate,
},
{
label: $t('ui.actionTitle.export'),
type: 'primary',
icon: ACTION_ICON.DOWNLOAD,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:export'],
onClick: handleExport,
},
#if ($table.templateType != 2 && $deleteBatchEnable)
{
label: $t('ui.actionTitle.deleteBatch'),
type: 'primary',
danger: true,
icon: ACTION_ICON.DELETE,
disabled: isEmpty(deleteIds),
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
onClick: handleDeleteBatch,
},
#end
]"
/>
</template>
<template #actions="{ row }">
<TableAction
:actions="[
#if (${table.templateType} == 2)## 树表特有:新增下级
{
label: '新增下级',
type: 'link',
icon: ACTION_ICON.ADD,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
onClick: handleAppend.bind(null, row),
},
#end
{
label: $t('common.edit'),
type: 'link',
icon: ACTION_ICON.EDIT,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:update'],
onClick: handleEdit.bind(null, row),
},
{
label: $t('common.delete'),
type: 'link',
danger: true,
icon: ACTION_ICON.DELETE,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
popConfirm: {
title: $t('ui.actionMessage.deleteConfirm', [row.id]),
confirm: handleDelete.bind(null, row),
},
},
]"
/>
</template>
</Grid>
#if ($table.templateType == 11) ## erp情况
<!-- 子表的表单 -->
<Tabs v-model:active-key="subTabsName" class="mt-2">
#foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index))
#set ($subSimpleClassName = $subSimpleClassNames.get($index))
#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
<Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
<${subSimpleClassName}List :${subJoinColumn_strikeCase}="select${simpleClassName}?.id" />
</Tabs.TabPane>
#end
</Tabs>
</div>
#end
</Page>
</template>

View File

@@ -0,0 +1,90 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { computed, ref } from 'vue';
import { $t } from '#/locales';
import { useVbenForm } from '#/adapter/form';
import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
import { use${subSimpleClassName}FormSchema } from '../data';
const emit = defineEmits(['success']);
const formData = ref<${simpleClassName}Api.${subSimpleClassName}>();
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['${subTable.classComment}'])
: $t('ui.actionTitle.create', ['${subTable.classComment}']);
});
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 80,
},
layout: 'horizontal',
schema: use${subSimpleClassName}FormSchema(),
showDefaultActions: false
});
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) {
return;
}
modalApi.lock();
// 提交表单
const data = (await formApi.getValues()) as ${simpleClassName}Api.${subSimpleClassName};
data.${subJoinColumn.javaField} = formData.value?.${subJoinColumn.javaField};
try {
await (formData.value?.id ? update${subSimpleClassName}(data) : create${subSimpleClassName}(data));
// 关闭并提示
await modalApi.close();
emit('success');
message.success( $t('ui.actionMessage.operationSuccess') );
} finally {
modalApi.unlock();
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = undefined;
return;
}
// 加载数据
let data = modalApi.getData<${simpleClassName}Api.${subSimpleClassName}>();
if (!data) {
return;
}
if (data.id) {
modalApi.lock();
try {
data = await get${subSimpleClassName}(data.id);
} finally {
modalApi.unlock();
}
}
// 设置到 values
formData.value = data;
await formApi.setValues(formData.value);
},
});
</script>
<template>
<Modal :title="getTitle">
<Form class="mx-4" />
</Modal>
</template>

View File

@@ -0,0 +1,2 @@
## 主表的 normal 和 inner 使用相同的 form 表单
#parse("codegen/vue3_vben5_antd/schema/views/modules/form_sub_normal.vue.vm")

View File

@@ -0,0 +1,196 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subClassNameVar = $subClassNameVars.get($subIndex))
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<script lang="ts" setup>
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
import { computed, ref, h, onMounted,watch,nextTick } from 'vue';
import { $t } from '#/locales';
#if ($subTable.subJoinMany) ## 一对多
import { Plus } from "@vben/icons";
import { Button, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue';
import { ImageUpload, FileUpload } from "#/components/upload";
import type { OnActionClickParams } from '#/adapter/vxe-table';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { use${subSimpleClassName}GridEditColumns } from '../data';
import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
#else
import { useVbenForm } from '#/adapter/form';
import { use${subSimpleClassName}FormSchema } from '../data';
import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
#end
const props = defineProps<{
${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
}>()
#if ($subTable.subJoinMany) ## 一对多
/** 表格操作按钮的回调函数 */
function onActionClick({
code,
row,
}: OnActionClickParams<${simpleClassName}Api.${subSimpleClassName}>) {
switch (code) {
case 'delete': {
onDelete(row);
break;
}
}
}
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: use${subSimpleClassName}GridEditColumns(onActionClick),
border: true,
showOverflow: true,
autoResize: true,
keepSource: true,
rowConfig: {
keyField: 'id',
},
pagerConfig: {
enabled: false,
},
toolbarConfig: {
enabled: false,
},
},
});
/** 添加${subTable.classComment} */
const onAdd = async () => {
await gridApi.grid.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1);
}
/** 删除${subTable.classComment} */
const onDelete = async (row: ${simpleClassName}Api.${subSimpleClassName}) => {
await gridApi.grid.remove(row);
}
/** 提供获取表格数据的方法供父组件调用 */
defineExpose({
getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => {
const data = gridApi.grid.getData() as ${simpleClassName}Api.${subSimpleClassName}[];
const removeRecords = gridApi.grid.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
const insertRecords = gridApi.grid.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
return data
.filter((row) => !removeRecords.some((removed) => removed.id === row.id))
.concat(insertRecords.map((row: any) => ({ ...row, id: undefined })));
},
});
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
async (val) => {
if (!val) {
return;
}
await nextTick();
await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
},
{ immediate: true },
);
#else
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 80,
},
layout: 'horizontal',
schema: use${subSimpleClassName}FormSchema(),
showDefaultActions: false
});
/** 暴露出表单校验方法和表单值获取方法 */
defineExpose({
validate: async () => {
const { valid } = await formApi.validate();
return valid;
},
getValues: formApi.getValues,
});
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
async (val) => {
if (!val) {
return;
}
await nextTick();
await formApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
},
{ immediate: true },
);
#end
</script>
<template>
#if ($subTable.subJoinMany) ## 一对多
<Grid class="mx-4">
#foreach($column in $subColumns)
#if ($column.createOperation || $column.updateOperation)
#set ($javaField = $column.javaField)
#if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
#elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
<template #${javaField}="{ row }">
<Input v-model:value="row.${javaField}" />
</template>
#elseif($column.htmlType == "imageUpload")## 图片上传
<template #${javaField}="{ row }">
<ImageUpload v-model:value="row.${javaField}" />
</template>
#elseif($column.htmlType == "fileUpload")## 文件上传
<template #${javaField}="{ row }">
<FileUpload v-model:value="row.${javaField}" />
</template>
#elseif($column.htmlType == "select")## 下拉框
<template #${javaField}="{ row, column }">
<Select v-model:value="row.${javaField}" class="w-full">
<Select.Option v-for="option in column.params.options" :key="option.value" :value="option.value">
{{ option.label }}
</Select.Option>
</Select>
</template>
#elseif($column.htmlType == "checkbox")## 多选框
<template #${javaField}="{ row, column }">
<CheckboxGroup v-model:value="row.${javaField}" :options="column.params.options" />
</template>
#elseif($column.htmlType == "radio")## 单选框
<template #${javaField}="{ row, column }">
<RadioGroup v-model:value="row.${javaField}" :options="column.params.options" />
</template>
#elseif($column.htmlType == "datetime")## 时间框
<template #${javaField}="{ row }">
<DatePicker
v-model:value="row.${javaField}"
:showTime="true"
format="YYYY-MM-DD HH:mm:ss"
valueFormat='x'
/>
</template>
#elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框
<template #${javaField}="{ row }">
<Textarea v-model:value="row.${javaField}" />
</template>
#end
#end
#end
</Grid>
<div class="flex justify-center -mt-4">
<Button :icon="h(Plus)" type="primary" ghost @click="onAdd" v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:create']">
{{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
</Button>
</div>
#else
<Form class="mx-4" />
#end
</template>

View File

@@ -0,0 +1,243 @@
#set ($subTable = $subTables.get($subIndex))##当前表
#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex))
#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
#if ($table.templateType == 11) ## erp
import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
#end
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { ref, computed, nextTick,watch } from 'vue';
import { $t } from '#/locales';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
#if ($table.templateType == 11) ## erp
import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}ListByIds,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${table.businessName}';
import { use${subSimpleClassName}GridFormSchema, use${subSimpleClassName}GridColumns } from '../data';
import { isEmpty } from '@vben/utils';
#else
#if ($subTable.subJoinMany) ## 一对多
import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
#else
import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
#end
import { use${subSimpleClassName}GridColumns } from '../data';
#end
const props = defineProps<{
${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
}>()
#if ($table.templateType == 11) ## erp
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: ${subSimpleClassName}Form,
destroyOnClose: true,
});
/** 创建${subTable.classComment} */
function handleCreate() {
if (!props.${subJoinColumn.javaField}){
message.warning("请先选择一个${table.classComment}!")
return
}
formModalApi.setData({${subJoinColumn.javaField}: props.${subJoinColumn.javaField}}).open();
}
/** 编辑${subTable.classComment} */
function handleEdit(row: ${simpleClassName}Api.${subSimpleClassName}) {
formModalApi.setData(row).open();
}
/** 删除${subTable.classComment} */
async function handleDelete(row: ${simpleClassName}Api.${subSimpleClassName}) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.id]),
key: 'action_process_msg',
});
try {
await delete${subSimpleClassName}(row.id as number);
message.success({
content: $t('ui.actionMessage.deleteSuccess', [row.id]),
key: 'action_key_msg',
});
onRefresh();
} finally {
hideLoading();
}
}
#if ($deleteBatchEnable)
/** 批量删除${subTable.classComment} */
async function handleDeleteBatch() {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting'),
key: 'action_key_msg',
});
try {
await delete${subSimpleClassName}ListByIds(deleteIds.value);
message.success({
content: $t('ui.actionMessage.deleteSuccess', [row.id]),
key: 'action_key_msg',
});
onRefresh();
} finally {
hideLoading();
}
}
const deleteIds = ref<number[]>([]) // 待删除${subTable.classComment} ID
function setDeleteIds({
records,
}: {
records: ${simpleClassName}Api.${subSimpleClassName}[];
}) {
deleteIds.value = records.map((item) => item.id);
}
#end
#end
const [Grid, gridApi] = useVbenVxeGrid({
#if ($table.templateType == 11)
formOptions: {
schema: use${subSimpleClassName}GridFormSchema(),
},
#end
gridOptions: {
#if ($table.templateType == 11)
columns: use${subSimpleClassName}GridColumns(),
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
if (!props.${subJoinColumn.javaField}){
return []
}
return await get${subSimpleClassName}Page({
pageNo: page.currentPage,
pageSize: page.pageSize,
${subJoinColumn.javaField}: props.${subJoinColumn.javaField},
...formValues,
});
},
},
},
pagerConfig: {
enabled: true,
},
toolbarConfig: {
refresh: { code: 'query' },
search: true,
},
#else
columns: use${subSimpleClassName}GridColumns(),
pagerConfig: {
nabled: false,
},
toolbarConfig: {
enabled: false,
},
#end
height: '600px',
rowConfig: {
keyField: 'id',
isHover: true,
},
} as VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>,
#if (${table.templateType} == 11 && $deleteBatchEnable)
gridEvents:{
checkboxAll: setDeleteIds,
checkboxChange: setDeleteIds,
}
#end
});
/** 刷新表格 */
async function onRefresh() {
#if ($table.templateType == 11) ## erp
await gridApi.query();
#else
#if ($subTable.subJoinMany) ## 一对多
await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
#else
await gridApi.grid.loadData([await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)]);
#end
#end
}
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.${subJoinColumn.javaField},
async (val) => {
if (!val) {
return;
}
await nextTick();
await onRefresh()
},
{ immediate: true },
);
</script>
<template>
#if ($table.templateType == 11) ## erp
<FormModal @success="onRefresh" />
<Grid table-title="${subTable.classComment}列表">
<template #toolbar-tools>
<TableAction
:actions="[
{
label: $t('ui.actionTitle.create', ['${table.classComment}']),
type: 'primary',
icon: ACTION_ICON.ADD,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
onClick: handleCreate,
},
#if ($table.templateType == 11 && $deleteBatchEnable)
{
label: $t('ui.actionTitle.deleteBatch'),
type: 'primary',
danger: true,
icon: ACTION_ICON.DELETE,
disabled: isEmpty(deleteIds),
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
onClick: handleDeleteBatch,
},
#end
]"
/>
</template>
<template #actions="{ row }">
<TableAction
:actions="[
{
label: $t('common.edit'),
type: 'link',
icon: ACTION_ICON.EDIT,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:update'],
onClick: handleEdit.bind(null, row),
},
{
label: $t('common.delete'),
type: 'link',
danger: true,
icon: ACTION_ICON.DELETE,
auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
popConfirm: {
title: $t('ui.actionMessage.deleteConfirm', [row.id]),
confirm: handleDelete.bind(null, row),
},
},
]"
/>
</template>
</Grid>
#else
<Grid table-title="${subTable.classComment}列表" />
#end
</template>

View File

@@ -0,0 +1,4 @@
## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
## 1inner 使用 list 不分页erp 使用 page 分页
## 2erp 支持单个子表的新增、修改、删除inner 不支持
#parse("codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm")

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,76 @@
<configuration>
<!-- 引用 Spring Boot 的 logback 基础配置 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<!-- 变量 cloud.info.base-package基础业务包 -->
<springProperty scope="context" name="cloud.info.base-package" source="cloud.info.base-package"/>
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level级别从左显示 5 个字符宽度,%msg日志消息%n是换行符 -->
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!-- 控制台 Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">     
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${PATTERN_DEFAULT}</pattern>
</layout>
</encoder>
</appender>
<!-- 文件 Appender -->
<!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${PATTERN_DEFAULT}</pattern>
</layout>
</encoder>
<!-- 日志文件名 -->
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 滚动后的日志文件名 -->
<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
<!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
<!-- 日志文件,到达多少容量,进行滚动 -->
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
<!-- 日志文件的总大小0 表示不限制 -->
<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
<!-- 日志文件的保留天数 -->
<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
</rollingPolicy>
</appender>
<!-- 异步写入日志,提升性能 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
<queueSize>256</queueSize>
<appender-ref ref="FILE"/>
</appender>
<!-- SkyWalking GRPC 日志收集实现日志中心。注意SkyWalking 8.4.0 版本开始支持 -->
<appender name="GRPC" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${PATTERN_DEFAULT}</pattern>
</layout>
</encoder>
</appender>
<!-- 本地环境 -->
<springProfile name="local">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
</root>
</springProfile>
<!-- 其它环境 -->
<springProfile name="dev,test,stage,prod,default">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNC"/>
<appender-ref ref="GRPC"/>
</root>
</springProfile>
</configuration>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zt.plat.module.infra.dal.mysql.businessfile.BusinessFileMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zt.plat.module.infra.dal.mysql.standardname.StandardNameMapper">
</mapper>