Compare commits

..

36 Commits

Author SHA1 Message Date
6495150a80 添加菜单加getClientType条件 2026-03-13 10:14:22 +08:00
9d4e3081b9 优化 2026-01-28 20:49:45 +08:00
06b7a095ad 添加菜单下载 2026-01-23 15:51:39 +08:00
9e723b3d8a 优化,添加页面路径 2026-01-22 14:44:27 +08:00
ac1512088f 添加字段 2026-01-22 11:06:37 +08:00
84ebce764b 优化初始化数据 2026-01-21 13:53:48 +08:00
96ac78f856 操作编码允许小驼峰 2026-01-21 09:56:41 +08:00
c8e168e4c4 功能管理,完成 2026-01-20 15:33:13 +08:00
bd2b0e7f3d 初始化数据xml代码生成 2026-01-20 14:40:32 +08:00
f6a76efe1d 代码生成 2026-01-20 09:12:56 +08:00
06979818be 代码生成 2026-01-19 21:30:09 +08:00
b3def6eb10 添加详情接口 2026-01-16 15:09:23 +08:00
9ae7b537cc 模版响应参数说明 2026-01-15 15:09:56 +08:00
34c9c9766d Merge remote-tracking branch 'origin/master' 2026-01-15 15:09:34 +08:00
f588e522f2 角色权限表加客户端类型 2026-01-15 14:41:58 +08:00
8d4bca005e 模版参数 2026-01-15 14:34:24 +08:00
0e8dedc64b 删除菜单权限,菜单列表加已有的功能 2026-01-15 14:20:45 +08:00
a7e8259fb2 删除菜单权限,菜单列表加已有的功能 2026-01-15 09:38:16 +08:00
c62225c34a 获取菜单列表返回已有的权限ID 2026-01-14 17:54:31 +08:00
b3a0e377e5 模板管理 2026-01-14 17:47:36 +08:00
fb6ea0bfd2 菜单获取操作列表 2026-01-14 14:42:53 +08:00
d45edc85ba 获取角色功能权限配置 2026-01-14 11:44:59 +08:00
81cd6b4951 usableConfig升序 2026-01-14 10:52:49 +08:00
ba21dbe551 角色管理 2026-01-14 09:43:11 +08:00
ab425b4f3b 操作增加参数 2026-01-14 09:21:43 +08:00
cbc0c8f4dd 功能增加参数 2026-01-13 18:00:39 +08:00
924db70d84 模块增加参数 2026-01-13 17:48:00 +08:00
9c184c750e 过滤无关文件 2026-01-13 17:39:33 +08:00
f9d41a3404 校验编码 2026-01-13 17:38:38 +08:00
37f961b27f 优化接口 2026-01-13 16:43:08 +08:00
1516caa21a 菜单管理 2026-01-13 14:06:36 +08:00
aaa2d25367 排序降序,包名称限制小写字母和. 2026-01-13 11:32:09 +08:00
b0d3f9c60a 不需要 0: 无需处理 2026-01-13 10:57:16 +08:00
6156e12d93 config 2026-01-13 10:48:31 +08:00
4383a7c547 Merge remote-tracking branch 'origin/master' 2026-01-12 09:27:56 +08:00
2c2ac6d032 添加 模版生成相关依赖 2026-01-12 09:17:24 +08:00
126 changed files with 6510 additions and 71 deletions

1
.gitignore vendored
View File

@@ -40,3 +40,4 @@ build/
/.idea/misc.xml
/.idea/vcs.xml
/.idea/**
/.xcodemap/config

450
doc/sql.md Normal file
View File

@@ -0,0 +1,450 @@
```sql
/* ---------------------------------------------------- */
/* Generated by Enterprise Architect Version 10.10 */
/* Created On : 22-1月-2026 10:57:00 */
/* DBMS : PostgreSQL */
/* ---------------------------------------------------- */
/* Drop Sequences for Autonumber Columns */
DROP SEQUENCE IF EXISTS cg_template_id_seq
;
/* Drop Tables */
DROP TABLE IF EXISTS cg_fun_item CASCADE
;
DROP TABLE IF EXISTS cg_fun_module CASCADE
;
DROP TABLE IF EXISTS cg_fun_operation CASCADE
;
DROP TABLE IF EXISTS cg_menu CASCADE
;
DROP TABLE IF EXISTS cg_role CASCADE
;
DROP TABLE IF EXISTS cg_role_fun CASCADE
;
DROP TABLE IF EXISTS cg_template CASCADE
;
/* Create Tables */
CREATE TABLE cg_fun_item
(
id bigint NOT NULL, -- id
module_id bigint NOT NULL, -- 模块ID
item_id bigint NOT NULL, -- 功能ID
item_name varchar(50) NOT NULL, -- 功能名称
item_code varchar(64) NOT NULL, -- 功能编码
is_tenant boolean NOT NULL DEFAULT true, -- 是否租户
describe varchar(250) NULL, -- 说明
sort_order smallint NOT NULL DEFAULT 0 -- 排序
)
;
CREATE TABLE cg_fun_module
(
id bigint NOT NULL, -- id
module_code varchar(16) NOT NULL, -- 模块编码
module_name varchar(8) NOT NULL, -- 模块名称
package_name varchar(250) NOT NULL, -- 包名称
api_package_name varchar(250) NOT NULL, -- 参数包名
sort_order smallint NOT NULL DEFAULT 0, -- 排序
describe varchar(250) NULL -- 描述
)
;
CREATE TABLE cg_fun_operation
(
id bigint NOT NULL, -- id
module_id bigint NOT NULL, -- 模块ID
item_id bigint NOT NULL, -- 功能ID(表主键ID)
is_green_light boolean NOT NULL DEFAULT false, -- 直接放行
operation_id bigint NOT NULL, -- 操作ID
operation_code varchar(32) NULL, -- 操作编码
fun_name varchar(16) NOT NULL, -- 操作名称
fun_type smallint NOT NULL, -- 操作类型>>查>>改>>删>>增
request_type smallint NOT NULL, -- 请求类型
is_req_params boolean NOT NULL DEFAULT true, -- 是否需要请求参数
is_res_params boolean NOT NULL DEFAULT true, -- 是否需要响应参数
is_page boolean NOT NULL DEFAULT true, -- 是否分页
path_params varchar(16) NULL, -- 路径参数与请求参数true互斥
usable_config json NOT NULL DEFAULT '[]', -- 可配置数据类型json[]
field_config json NOT NULL DEFAULT '[]', -- 可配置字段
sort_order smallint NOT NULL DEFAULT 0, -- 排序
describe varchar(250) NULL -- 说明说明
)
;
CREATE TABLE cg_menu
(
id bigint NOT NULL, -- 主键ID
client_type smallint NOT NULL, -- 客户端类型0 PC端1 小程序端2 H5端
menu_name varchar(32) NOT NULL, -- 菜单名称
parent_id bigint NOT NULL DEFAULT 0, -- 父菜单ID
fun_id bigint NULL, -- 操作ID/来自操作表
menu_type smallint NOT NULL DEFAULT 0, -- 0菜单1按钮
path varchar(64) NULL, -- 路由路径
page_path varchar(64) NULL,
icon varchar(64) NULL, -- 菜单图标
is_tenant boolean NOT NULL DEFAULT true, -- 是否租户
is_hide boolean NOT NULL DEFAULT false, -- 是否隐藏
sort_order smallint NOT NULL DEFAULT 0 -- 排序
)
;
CREATE TABLE cg_role
(
id bigint NOT NULL, -- 主键ID
role_name varchar(32) NOT NULL, -- 角色名称
role_type smallint NOT NULL -- 角色类型 0平台 1套餐
)
;
CREATE TABLE cg_role_fun
(
id bigint NOT NULL, -- 主键ID
role_id bigint NOT NULL, -- 角色ID
fun_id bigint NOT NULL, -- 操作ID
data_scope smallint NOT NULL DEFAULT 0, -- 数据权限默认:0无
assign_data_scope json NOT NULL DEFAULT '[]', -- 指定的数据权限范围
exclude_field json NOT NULL DEFAULT '[]', -- 排除的字段
client_type smallserial NOT NULL -- 客户端类型0 PC端1 小程序端2 H5端
)
;
CREATE TABLE cg_template
(
id bigint NOT NULL DEFAULT NEXTVAL(('"cg_template_id_seq"'::text)::regclass), -- 主键ID
is_use boolean NOT NULL DEFAULT false, -- 是否使用
template_name varchar(32) NOT NULL, -- 模板名称
template_type smallint NOT NULL, -- 模板类型
content text NOT NULL -- 正文
)
;
/* Create Primary Keys, Indexes, Uniques, Checks */
ALTER TABLE cg_fun_item ADD CONSTRAINT "PK_cg_fun_item"
PRIMARY KEY (id)
;
ALTER TABLE cg_fun_item
ADD CONSTRAINT u_module_item_code UNIQUE (module_id,item_id,item_code)
;
ALTER TABLE cg_fun_item
ADD CONSTRAINT u_module_item_id UNIQUE (module_id,item_id)
;
ALTER TABLE cg_fun_module ADD CONSTRAINT "PK_cg_fun_module"
PRIMARY KEY (id)
;
ALTER TABLE cg_fun_operation ADD CONSTRAINT "PK_cg_fun_operation"
PRIMARY KEY (id)
;
ALTER TABLE cg_fun_operation
ADD CONSTRAINT u_module_item_opration UNIQUE (module_id,item_id,operation_code)
;
ALTER TABLE cg_fun_operation
ADD CONSTRAINT u_module_item_operation_id UNIQUE (module_id,item_id,operation_id)
;
ALTER TABLE cg_menu ADD CONSTRAINT "PK_cg_menu"
PRIMARY KEY (id)
;
ALTER TABLE cg_role ADD CONSTRAINT "PK_cg_role"
PRIMARY KEY (id)
;
ALTER TABLE cg_role_fun ADD CONSTRAINT "PK_cg_role_fun"
PRIMARY KEY (id)
;
ALTER TABLE cg_template ADD CONSTRAINT "PK_cg_template"
PRIMARY KEY (id)
;
/* Create Table Comments, Sequences for Autonumber Columns */
COMMENT ON TABLE cg_fun_item
IS '功能项配置'
;
COMMENT ON COLUMN cg_fun_item.id
IS 'id'
;
COMMENT ON COLUMN cg_fun_item.module_id
IS '模块ID'
;
COMMENT ON COLUMN cg_fun_item.item_id
IS '功能ID'
;
COMMENT ON COLUMN cg_fun_item.item_name
IS '功能名称'
;
COMMENT ON COLUMN cg_fun_item.item_code
IS '功能编码'
;
COMMENT ON COLUMN cg_fun_item.is_tenant
IS '是否租户'
;
COMMENT ON COLUMN cg_fun_item.describe
IS '说明'
;
COMMENT ON COLUMN cg_fun_item.sort_order
IS '排序'
;
COMMENT ON TABLE cg_fun_module
IS '模块配置'
;
COMMENT ON COLUMN cg_fun_module.id
IS 'id'
;
COMMENT ON COLUMN cg_fun_module.module_code
IS '模块编码'
;
COMMENT ON COLUMN cg_fun_module.module_name
IS '模块名称'
;
COMMENT ON COLUMN cg_fun_module.package_name
IS '包名称'
;
COMMENT ON COLUMN cg_fun_module.api_package_name
IS '参数包名'
;
COMMENT ON COLUMN cg_fun_module.sort_order
IS '排序'
;
COMMENT ON COLUMN cg_fun_module.describe
IS '描述'
;
COMMENT ON TABLE cg_fun_operation
IS '操作配置'
;
COMMENT ON COLUMN cg_fun_operation.id
IS 'id'
;
COMMENT ON COLUMN cg_fun_operation.module_id
IS '模块ID'
;
COMMENT ON COLUMN cg_fun_operation.item_id
IS '功能ID(表主键ID)'
;
COMMENT ON COLUMN cg_fun_operation.is_green_light
IS '直接放行'
;
COMMENT ON COLUMN cg_fun_operation.operation_id
IS '操作ID'
;
COMMENT ON COLUMN cg_fun_operation.operation_code
IS '操作编码'
;
COMMENT ON COLUMN cg_fun_operation.fun_name
IS '操作名称'
;
COMMENT ON COLUMN cg_fun_operation.fun_type
IS '操作类型>>查>>改>>删>>增'
;
COMMENT ON COLUMN cg_fun_operation.request_type
IS '请求类型'
;
COMMENT ON COLUMN cg_fun_operation.is_req_params
IS '是否需要请求参数'
;
COMMENT ON COLUMN cg_fun_operation.is_res_params
IS '是否需要响应参数'
;
COMMENT ON COLUMN cg_fun_operation.is_page
IS '是否分页'
;
COMMENT ON COLUMN cg_fun_operation.path_params
IS '路径参数与请求参数true互斥'
;
COMMENT ON COLUMN cg_fun_operation.usable_config
IS '可配置数据类型json[]'
;
COMMENT ON COLUMN cg_fun_operation.field_config
IS '可配置字段'
;
COMMENT ON COLUMN cg_fun_operation.sort_order
IS '排序'
;
COMMENT ON COLUMN cg_fun_operation.describe
IS '说明说明'
;
COMMENT ON TABLE cg_menu
IS '菜单'
;
COMMENT ON COLUMN cg_menu.id
IS '主键ID'
;
COMMENT ON COLUMN cg_menu.client_type
IS '客户端类型0 PC端1 小程序端2 H5端'
;
COMMENT ON COLUMN cg_menu.menu_name
IS '菜单名称'
;
COMMENT ON COLUMN cg_menu.parent_id
IS '父菜单ID'
;
COMMENT ON COLUMN cg_menu.fun_id
IS '操作ID/来自操作表'
;
COMMENT ON COLUMN cg_menu.menu_type
IS '0菜单1按钮'
;
COMMENT ON COLUMN cg_menu.path
IS '路由路径'
;
COMMENT ON COLUMN cg_menu.icon
IS '菜单图标'
;
COMMENT ON COLUMN cg_menu.is_tenant
IS '是否租户'
;
COMMENT ON COLUMN cg_menu.is_hide
IS '是否隐藏'
;
COMMENT ON COLUMN cg_menu.sort_order
IS '排序'
;
COMMENT ON TABLE cg_role
IS '角色表'
;
COMMENT ON COLUMN cg_role.id
IS '主键ID'
;
COMMENT ON COLUMN cg_role.role_name
IS '角色名称'
;
COMMENT ON COLUMN cg_role.role_type
IS '角色类型 0平台 1套餐'
;
COMMENT ON TABLE cg_role_fun
IS '角色权限表'
;
COMMENT ON COLUMN cg_role_fun.id
IS '主键ID'
;
COMMENT ON COLUMN cg_role_fun.role_id
IS '角色ID'
;
COMMENT ON COLUMN cg_role_fun.fun_id
IS '操作ID'
;
COMMENT ON COLUMN cg_role_fun.data_scope
IS '数据权限默认:0无'
;
COMMENT ON COLUMN cg_role_fun.assign_data_scope
IS '指定的数据权限范围'
;
COMMENT ON COLUMN cg_role_fun.exclude_field
IS '排除的字段'
;
COMMENT ON COLUMN cg_role_fun.client_type
IS '客户端类型0 PC端1 小程序端2 H5端'
;
COMMENT ON COLUMN cg_template.id
IS '主键ID'
;
COMMENT ON COLUMN cg_template.is_use
IS '是否使用'
;
COMMENT ON COLUMN cg_template.template_name
IS '模板名称'
;
COMMENT ON COLUMN cg_template.template_type
IS '模板类型'
;
COMMENT ON COLUMN cg_template.content
IS '正文'
;
CREATE SEQUENCE cg_template_id_seq INCREMENT 1 START 1
;
```

480
doc/模版.md Normal file
View File

@@ -0,0 +1,480 @@
# stringtemplate4
设置 $
```
STGroup group = new STGroupString("db_template",template, '$', '$');
```
## 模版的定义
基础
```
classTemplate(item, module, operationList, className) ::= <<
>>
```
> 注意 <<内容>> 定义的方法
>
> classTemplate 为 group.getInstanceOf("classTemplate"); 定义
例子:
```java
classTemplate(item, module, operationList, className) ::= <<
package $module.packageName$;
/**
* @author xia
* @date 2026/1/10
* @version 0.0.1
*/
public class $className$ {
}
>>
```
映射字典
```ts
// 定义一个映射字典
requestAnnotations ::= [
"POST": "@PostMapping",
"GET": "@GetMapping",
"PUT": "@PutMapping",
"DELETE": "@DeleteMapping",
default: "@RequestMapping"
]
```
## Controller
```java
requestAnnotations ::= [
"POST": "@PostMapping",
"GET": "@GetMapping",
"PUT": "@PutMapping",
"DELETE": "@DeleteMapping",
default: "@RequestMapping"
]
classTemplate(module,item,operationList,basics) ::= <<
package $module.packageName$.controller;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* $item.itemName$ 控制器
* @author xia
*/
@Tag(name = "$item.itemName$")
@RequiredArgsConstructor
@RestController
@RequestMapping("/$item.itemCode$")
public class $basics.itemCodeUp$Controller {
private final $basics.itemCodeUp$Service $item.itemCode$Service;
$operationList:{op |
@OperLog
@SecureAudit(id = $op.id$,$if(op.isGreenLight)$isGreenLight = true,$endif$ $if(!item.isTenant)$isTenant = false,$endif$
funType = FunTypeEnum.$op.funType$, funName = "$op.funName$", funCode = "$module.moduleCode$:$item.itemCode$:$op.operationCode$")
@Operation(summary = "$op.funName$", description = "$op.describe$")
$requestAnnotations.(op.requestType)$("$op.url$$op.pathParamsUrl$")
public XResult<$if(op.isPage)$Page<$basics.itemCodeUp$$op.methodNamePascalCase$Res>$else$$if(op.isResParams)$$basics.itemCodeUp$$op.methodNamePascalCase$Res$else$Void$endif$$endif$> $op.methodName$($if(op.isReqParams)$@RequestBody @Valid $basics.itemCodeUp$$op.methodNamePascalCase$Req req$endif$$op.pathParamsLong$) {
return $item.itemCode$Service.$op.methodName$($if(op.isPathParams)$$op.pathParams$$endif$$if(op.isReqParams)$req$endif$);
\}
}$
}
>>
```
## 请求参数
```java
classTemplate(module,item,operationList,basics) ::= <<
package $module.apiPackageName$.request.$item.itemCode$;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* $item.itemName$
* $basics.oper.funName$ 请求参数
* @author xia
*/
@Getter
@Setter
@Schema(description = "$basics.oper.funName$ 参数")
public class $basics.itemCodeUp$Req $if(basics.oper.isPage)$extends XhPage$endif$ implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
}
>>
```
## 响应参数
```java
classTemplate(module,item,operationList,basics) ::= <<
package $module.apiPackageName$.response.$item.itemCode$;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* $item.itemName$
* $basics.oper.funName$ 响应
* @author xia
*/
@Getter
@Setter
@Schema(description = "$basics.oper.funName$ 响应")
public class $basics.itemCodeUp$Res implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
}
>>
```
## 服务接口
```java
classTemplate(module,item,operationList,basics) ::= <<
package $module.packageName$.service;
/**
* $item.itemName$ 服务层接口
* @author xia
*/
public interface $basics.itemCodeUp$Service {
$operationList:{op |
/**
* $op.funName$
* $op.describe$
*/
XResult<$if(op.isPage)$Page<$basics.itemCodeUp$$op.methodNamePascalCase$Res>$else$$if(op.isResParams)$$basics.itemCodeUp$$op.methodNamePascalCase$Res$else$Void$endif$$endif$> $op.methodName$($if(op.isReqParams)$$basics.itemCodeUp$$op.methodNamePascalCase$Req req$endif$$if(op.isPathParams)$$op.pathParamsLongReq$$endif$);
}$
}
>>
```
## 服务接口实现
```java
classTemplate(module,item,operationList,basics) ::= <<
package $module.packageName$.service.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import $module.packageName$.service.$basics.itemCodeUp$Service;
/**
* $item.itemName$ 服务层接口
* @author xia
*/
@Service
@RequiredArgsConstructor
public class $basics.itemCodeUp$ServiceImpl implements $basics.itemCodeUp$Service{
$operationList:{op |
/**
* $op.funName$
* $op.describe$
*/
@Override
public XResult<$if(op.isPage)$Page<$basics.itemCodeUp$$op.methodNamePascalCase$Res>$else$$if(op.isResParams)$$basics.itemCodeUp$$op.methodNamePascalCase$Res$else$Void$endif$$endif$> $op.methodName$($if(op.isReqParams)$$basics.itemCodeUp$$op.methodNamePascalCase$Req req$endif$$if(op.isPathParams)$$op.pathParamsLongReq$$endif$){
// TODO $op.funName$ 实现
return null;
\}
}$
}
>>
```
## 模块数据
```xml
group dbXml;
moduleTemplate(module) ::= <<
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
<changeSet id="insert-ms-fun-module-data" author="xinghe">
<comment>初始化模块数据</comment>
$module:{op |
<insert tableName="ms_fun_module">
<column name="id" value="$op.id$"/>
<column name="module_code" value="$op.moduleCode$"/>
<column name="module_name" value="$op.moduleName$"/>
<column name="remark" value="$op.describe$"/>
</insert>
}$
</changeSet>
</databaseChangeLog>
>>
itemTemplate(item) ::= <<
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
<changeSet id="insert-ms-fun-item-data" author="xinghe">
<comment>初始化功能数据</comment>
$item:{op |
<insert tableName="ms_fun_item">
<column name="id" value="$op.id$"/>
<column name="module_id" value="$op.moduleId$"/>
<column name="item_code" value="$op.itemCode$"/>
<column name="item_name" value="$op.itemName$"/>
<column name="is_tenant" value="$op.isTenant$"/>
<column name="remark" value="$op.describe$"/>
</insert>
}$
</changeSet>
</databaseChangeLog>
>>
funTypeAnnotations ::= [
"ADD": "0",
"DELETE": "1",
"EDIT": "2",
"QUERY": "3",
"UPLOAD": "4",
"DOWNLOAD": "5",
"IMPORT": "6",
"EXPORT": "7",
"PRINT": "8",
"REGISTER": "9",
"LOGIN": "10",
"LOGOUT": "11",
"SMS": "12",
"EMAIL": "13",
"WECHAT": "14",
"OTHER": "99"
default: "-1"
]
operationTemplate(operation) ::= <<
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
<changeSet id="insert-ms-fun-operation-data" author="xinghe">
<comment>初始化操作数据</comment>
$operation:{op |
<insert tableName="ms_fun_operation">
<column name="id" value="$op.id$"/>
<column name="module_id" value="$op.moduleId$"/>
<column name="item_id" value="$op.itemId$"/>
<column name="is_green_light" value="$op.isGreenLight$"/>
<column name="fun_code" value="$op.moduleCode$:$op.itemCode$:$op.operationCode$"/>
<column name="fun_name" value="$op.funName$"/>
<column name="fun_type" value="$funTypeAnnotations.(op.funType)$"/>
<column name="usable_config" value="$op.usableConfigJson$"/>
<column name="field_config" value="$op.fieldConfigJson$"/>
<column name="sort_order" value="$op.sortOrder$"/>
<column name="remark" value="$op.describe$"/>
</insert>
}$
</changeSet>
</databaseChangeLog>
>>
```
## 角色套餐
初始化数据
```xml
group dbXml;
roleBindFunTemplate(operations,clientTypeCode,clientTypeDesc) ::= <<
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
<changeSet id="insert-ms-user-role-fun-data" author="xinghe">
<comment>初始化平台角色权限数据($clientTypeDesc$)</comment>
$operations:{op |
<!-- $op.funName$ -->
<insert tableName="ms_user_role_fun">
<column name="id" value="$op.id$$clientTypeCode$100"/>
<column name="role_id" value="100"/>
<column name="fun_id" value="$op.id$"/>
<column name="client_type" value="$clientTypeCode$"/>
<column name="data_scope" value="0"/>
<column name="assign_data_scope" value="[]"/>
<column name="exclude_field" value="[]"/>
<column name="update_by_id" value="10086"/>
<column name="update_time" value="2025-01-01 00:00:00"/>
</insert>
}$
</changeSet>
</databaseChangeLog>
>>
mealBindFunTemplate(meals,clientTypeCode,clientTypeDesc) ::= <<
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
<changeSet id="insert-ms-tenant-meal-bind-fun-data" author="xinghe">
<comment>初始化模块数据($clientTypeDesc$)</comment>
$meals:{op |
<!-- $op.funName$ -->
<insert tableName="ms_tenant_meal_bind_fun">
<column name="id" value="$op.id$$clientTypeCode$200"/>
<column name="meal_id" value="200"/>
<column name="fun_id" value="$op.id$"/>
<column name="client_type" value="$clientTypeCode$"/>
</insert>
}$
</changeSet>
</databaseChangeLog>
>>
```
## 菜单数据
菜单数据生成
```xml
menuTypeAnnotations ::= [
"MENU_ID": "0",
"BUTTON_ID": "1"
]
clientTypeAnnotations ::= [
"PC": "0",
"MINI_PROGRAM": "1",
"H5": "2"
]
menuTemplate(menus) ::= <<
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
<changeSet id="insert-ms-menu-data" author="xinghe">
<comment>初始化菜单数据</comment>
$menus:{op |
<insert tableName="ms_menu">
<column name="id" value="$op.id$"/>
<column name="parent_id" value="$op.parentId$"/>
<column name="fun_id" value="$if(op.funId)$$op.funId$$else$null$endif$"/>
<column name="menu_name" value="$op.menuName$"/>
<column name="menu_type" value="$menuTypeAnnotations.(op.menuType)$"/>
<column name="client_type" value="$clientTypeAnnotations.(op.clientType)$"/>
<column name="route_path" value="$op.path$"/>
<column name="page_path" value="$op.pagePath$"/>
<column name="icon" value="$op.icon$"/>
<column name="is_tenant" value="$op.isTenant$"/>
<column name="is_hide" value="$op.isHide$"/>
<column name="sort_order" value="$op.sortOrder$"/>
</insert>
}$
</changeSet>
</databaseChangeLog>
>>
```

64
pom.xml
View File

@@ -22,6 +22,8 @@
<knife4j.version>4.4.0</knife4j.version>
<hibernate-validator.version>9.1.0.Final</hibernate-validator.version>
<springdoc-openapi-starter-webmvc-ui.version>2.8.15</springdoc-openapi-starter-webmvc-ui.version>
<ST4.version>4.3.4</ST4.version>
<liteflow.version>2.15.2</liteflow.version>
</properties>
<dependencies>
@@ -73,18 +75,7 @@
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
@@ -96,6 +87,28 @@
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<!-- stringtemplate ST4-->
<dependency>
<groupId>org.antlr</groupId>
<artifactId>ST4</artifactId>
<version>${ST4.version}</version>
<scope>compile</scope>
</dependency>
<!-- liteflow -->
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>${liteflow.version}</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -126,4 +139,31 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</profile>
<profile>
<id>prod</id>
</profile>
</profiles>
</project>

View File

@@ -3,6 +3,7 @@ package com.cczsa.xinghe.codegen;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CodegenApplication {

View File

@@ -0,0 +1,26 @@
package com.cczsa.xinghe.codegen.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author xia
* &#064;date 2026/1/20
* @version 0.0.1
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 将所有非 API 的路径转发到 index.html
// 注意:这里假设你的 API 请求都有 /api 前缀
registry.addViewController("/{path:[^\\.]*}")
.setViewName("forward:/index.html");
// 针对多级路径的递归处理(可选)
registry.addViewController("/**/{path:[^\\.]*}")
.setViewName("forward:/index.html");
}
}

View File

@@ -0,0 +1,49 @@
package com.cczsa.xinghe.codegen.controller;
import com.cczsa.xinghe.codegen.entity.domain.template.CodeGen;
import com.cczsa.xinghe.codegen.service.CodeGenService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xia
* &#064;date 2026/1/10
* @version 0.0.1
*/
@Tag(name = "代码生成")
@RestController
@RequestMapping("/codegen")
@RequiredArgsConstructor
public class CodeGenController {
private final CodeGenService codeGenService;
@Operation(summary = "下载代码")
@PostMapping("/download")
public ResponseEntity<byte[]> downloadCode(@RequestBody @Valid CodeGen req) {
try {
byte[] zipData = codeGenService.generateCodeZip(req);
return ResponseEntity.ok()
// 设置下载文件名
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"generated-code.zip\"")
// 设置为二进制流
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(zipData.length)
.body(zipData);
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
}

View File

@@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import lombok.RequiredArgsConstructor;
@@ -35,7 +36,13 @@ public class FunOperationController {
@Operation(summary = "获取操作列表", description = "获取操作列表")
@PostMapping("/query")
public XResult<List<FunOperationQueryRes>> query(@RequestBody @Valid FunOperationQueryReq req) {
return funoperationService.query(req);
return funoperationService.query(req, null);
}
@Operation(summary = "菜单获取操作列表", description = "菜单获取操作列表")
@PostMapping("/query/{isTenant}")
public XResult<List<FunOperationQueryRes>> queryFunOperation(@RequestBody @Valid FunOperationQueryReq req, @PathVariable("isTenant") Boolean isTenant) {
return funoperationService.query(req, isTenant);
}
@Operation(summary = "创建/修改操作", description = "创建/修改操作")

View File

@@ -1,12 +1,22 @@
package com.cczsa.xinghe.codegen.controller;
import com.alibaba.fastjson2.JSONObject;
import com.cczsa.xinghe.codegen.util.XResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author xia
@@ -14,17 +24,49 @@ import org.springframework.web.bind.annotation.RestController;
* @version 0.0.1
*
*/
@Slf4j
@Tag(name = "登录")
@RequiredArgsConstructor
@RestController
@RequestMapping("/login")
public class LoginController {
@PostMapping("/")
public XResult<String> login(String username, String password) {
return null;
@Operation(summary = "登录", description = "登录")
@PostMapping("/login")
@Parameters({
@Parameter(name = "username", description = "用户名", required = true),
@Parameter(name = "password", description = "密码", required = true)
})
public XResult<Object> login(@RequestBody JSONObject login) {
if(!login.containsKey("username") || !login.containsKey("password")){
return XResult.failed("参数错误");
}
String username = login.getString("username");
String password = login.getString("password");
if ("admin".equals(username) && "9527".equals(password)) {
Map<String, Object> info = new HashMap<>();
info.put("token", "sk-"+System.currentTimeMillis());
info.put("roles", List.of("admin"));
info.put("username", "admin");
return XResult.ok(info);
}
return XResult.failed();
}
@Operation(summary = "用户信息", description = "用户信息")
@GetMapping("/users/info")
public XResult<Object> login() {
Map<String, Object> info = new HashMap<>();
info.put("roles", List.of("admin"));
info.put("username", "admin");
return XResult.ok(info);
}
}

View File

@@ -0,0 +1,81 @@
package com.cczsa.xinghe.codegen.controller;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuAddReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuBindFunReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuEditReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuQueryReq;
import com.cczsa.xinghe.codegen.entity.res.menu.MenuQueryRes;
import com.cczsa.xinghe.codegen.service.MenuService;
import com.cczsa.xinghe.codegen.util.XResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 菜单管理 控制层。
*
* @author xia
* @version 0.0.1
*/
@Tag(name = "菜单管理")
@RequiredArgsConstructor
@RestController
@RequestMapping("/menu")
public class MenuController {
private final MenuService menuService;
@Operation(summary = "获取菜单列表", description = "获取菜单列表")
@PostMapping("/query")
public XResult<List<MenuQueryRes>> query(@RequestBody @Valid MenuQueryReq req) {
return menuService.query(req);
}
@Operation(summary = "创建菜单", description = "创建菜单")
@PutMapping("/add")
public XResult<Void> add(@RequestBody @Valid MenuAddReq req) {
return menuService.add(req);
}
@Operation(summary = "修改菜单", description = "修改菜单")
@PostMapping("/edit")
public XResult<Void> edit(@RequestBody @Valid MenuEditReq req) {
return menuService.edit(req);
}
@Operation(summary = "删除菜单", description = "删除菜单")
@DeleteMapping("/delete/{id}")
public XResult<Void> delete(@PathVariable Long id) {
return menuService.delete(id);
}
@Operation(summary = "菜单绑定权限", description = "菜单绑定权限")
@PostMapping("/bind/fun")
public XResult<Void> bindFun(@RequestBody @Valid MenuBindFunReq req) {
return menuService.bindFun(req);
}
@Operation(summary = "删除菜单权限", description = "删除菜单权限")
@DeleteMapping("/delete/fun/{menuId}")
public XResult<Void> deleteFun(@PathVariable Long menuId) {
return menuService.deleteFun(menuId);
}
@Operation(summary = "根据ID获取菜单详情", description = "根据ID获取菜单详情")
@GetMapping("/get/{id}")
public XResult<MenuQueryRes> getById(@PathVariable Long id) {
return menuService.getById(id);
}
}

View File

@@ -0,0 +1,84 @@
package com.cczsa.xinghe.codegen.controller;
import com.cczsa.xinghe.codegen.entity.req.role.RoleAddReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleBindFunReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleEditReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleQueryFunReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleQueryReq;
import com.cczsa.xinghe.codegen.entity.res.role.RoleQueryFunRes;
import com.cczsa.xinghe.codegen.entity.res.role.RoleQueryRes;
import com.cczsa.xinghe.codegen.service.RoleService;
import com.cczsa.xinghe.codegen.util.XResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 角色管理 控制层。
*
* @author xia
* @version 0.0.1
*/
@Tag(name = "角色管理")
@RequiredArgsConstructor
@RestController
@RequestMapping("/role")
public class RoleController {
private final RoleService roleService;
@Operation(summary = "获取角色列表", description = "获取角色列表")
@PostMapping("/query")
public XResult<List<RoleQueryRes>> query(@RequestBody @Valid RoleQueryReq req) {
return roleService.query(req);
}
@Operation(summary = "创建角色", description = "创建角色")
@PutMapping("/add")
public XResult<Void> add(@RequestBody @Valid RoleAddReq req) {
return roleService.add(req);
}
@Operation(summary = "修改角色", description = "修改角色")
@PostMapping("/edit")
public XResult<Void> edit(@RequestBody @Valid RoleEditReq req) {
return roleService.edit(req);
}
@Operation(summary = "删除角色", description = "删除角色")
@DeleteMapping("/delete/{roleId}")
public XResult<Void> delete(@PathVariable Long roleId) {
return roleService.delete(roleId);
}
@Operation(summary = "角色设置权限", description = "角色设置权限")
@PostMapping("/bind/fun")
public XResult<Void> bindFun(@RequestBody @Valid RoleBindFunReq req) {
return roleService.bindFun(req);
}
@Operation(summary = "删除角色权限", description = "删除角色权限")
@DeleteMapping("/delete/fun/{roleBindFunId}")
public XResult<Void> deleteFun(@PathVariable Long roleBindFunId) {
return roleService.deleteFun(roleBindFunId);
}
@Operation(summary = "获取角色功能权限配置", description = "获取角色功能权限配置")
@PostMapping("/query/fun")
public XResult<List<RoleQueryFunRes>> queryRoleFun(@RequestBody @Valid RoleQueryFunReq req) {
return roleService.queryRoleFun(req);
}
}

View File

@@ -0,0 +1,69 @@
package com.cczsa.xinghe.codegen.controller;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateAddReq;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateEditReq;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateQueryReq;
import com.cczsa.xinghe.codegen.entity.res.template.TemplateQueryRes;
import com.cczsa.xinghe.codegen.service.TemplateService;
import com.cczsa.xinghe.codegen.util.XResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* 模板管理 控制层。
*
* @author xia
* @version 0.0.1
*/
@Tag(name = "模板管理")
@RequiredArgsConstructor
@RestController
@RequestMapping("/template")
public class TemplateController {
private final TemplateService templateService;
@Operation(summary = "获取模板列表", description = "获取模板列表")
@PostMapping("/query")
public XResult<List<TemplateQueryRes>> query(@RequestBody @Valid TemplateQueryReq req) {
return templateService.query(req);
}
@Operation(summary = "创建模板", description = "创建模板")
@PostMapping("/add")
public XResult<Void> add(@RequestBody @Valid TemplateAddReq req) {
return templateService.add(req);
}
@Operation(summary = "修改模板", description = "修改模板")
@PostMapping("/edit")
public XResult<Void> edit(@RequestBody @Valid TemplateEditReq req) {
return templateService.edit(req);
}
@Operation(summary = "删除模板", description = "删除模板")
@DeleteMapping("/delete/{id}")
public XResult<Void> delete(@PathVariable Long id) {
return templateService.delete(id);
}
@Operation(summary = "模板类型列表", description = "data响应为: [{\"0\": \"controller\"}]")
@GetMapping("/templateType")
public XResult<List<Map<Integer, String>>> getTemplateTypeList() {
return templateService.getTemplateTypeList();
}
}

View File

@@ -86,7 +86,7 @@ public class FunOperationEntity extends BaseEntity implements Serializable {
* 可配置字段
*/
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<String> fieldCofnig;
private List<String> fieldConfig;
/**
* 排序
@@ -103,4 +103,24 @@ public class FunOperationEntity extends BaseEntity implements Serializable {
*/
private Integer operationId;
/**
* 是否需要请求参数
*/
private Boolean isReqParams;
/**
* 是否需要响应参数
*/
private Boolean isResParams;
/**
* 是否分页
*/
private Boolean isPage;
/**
* 路径参数与请求参数true互斥
*/
private String pathParams;
}

View File

@@ -0,0 +1,50 @@
package com.cczsa.xinghe.codegen.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.EqualsAndHashCode;
/**
* 菜单绑定权限 实体类。
*
* @author My
* @since 0.0.1
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("cg_menu_bind_fun")
public class MenuBindFunEntity extends BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 菜单ID
*/
private Long menuId;
/**
* 功能ID
*/
private Long funId;
}

View File

@@ -0,0 +1,95 @@
package com.cczsa.xinghe.codegen.entity;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.MenuTypeEnum;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 菜单 实体类。
*
* @author xiayb
* @since 0.0.1
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("cg_menu")
public class MenuEntity extends BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 客户端类型0 PC端1 小程序端2 H5端
*/
private ClientTypeEnum clientType;
/**
* 菜单名称
*/
private String menuName;
/**
* 父菜单ID
*/
private Long parentId;
/**
* 操作ID/来自操作表
*/
private Long funId;
/**
* 0菜单1按钮
*/
private MenuTypeEnum menuType;
/**
* 路由路径
*/
private String path;
/**
* 页面路径
*/
private String pagePath;
/**
* 菜单图标
*/
private String icon;
/**
* 是否租户
*/
private Boolean isTenant;
/**
* 是否隐藏
*/
private Boolean isHide;
/**
* 排序
*/
private Integer sortOrder;
}

View File

@@ -0,0 +1,51 @@
package com.cczsa.xinghe.codegen.entity;
import com.cczsa.xinghe.codegen.entity.enums.RoleTypeEnum;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.EqualsAndHashCode;
/**
* 角色表 实体类。
*
* @author My
* @since 0.0.1
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("cg_role")
public class RoleEntity extends BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 角色名称
*/
private String roleName;
/**
* 角色类型 0平台 1套餐
*/
private RoleTypeEnum roleType;
}

View File

@@ -0,0 +1,76 @@
package com.cczsa.xinghe.codegen.entity;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.UsableConfigEnum;
import com.cczsa.xinghe.codegen.handler.PostgreSQLJsonTypeHandler;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 角色权限表 实体类。
*
* @author My
* @since 0.0.1
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("cg_role_fun")
public class RoleFunEntity extends BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 角色ID
*/
private Long roleId;
/**
* 权限ID
*/
private Long funId;
/**
* 数据权限
*/
private UsableConfigEnum dataScope;
/**
* 指定的数据权限范围
*/
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<Long> assignDataScope;
/**
* 排除的字段
*/
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<String> excludeField;
/**
* 客户端类型0 PC端1 小程序端2 H5端
*/
private ClientTypeEnum clientType;
}

View File

@@ -0,0 +1,60 @@
package com.cczsa.xinghe.codegen.entity;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.EqualsAndHashCode;
/**
* 实体类。
*
* @author My
* @since 0.0.1
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("cg_template")
public class TemplateEntity extends BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 是否使用
*/
private Boolean isUse;
/**
* 模板名称
*/
private String templateName;
/**
* 模板类型
*/
private TemplateTypeEnum templateType;
/**
* 正文
*/
private String content;
}

View File

@@ -0,0 +1,6 @@
/**
* @author xia
* &#064;date 2026/1/17
* @version 0.0.1
*/
package com.cczsa.xinghe.codegen.entity.domain;

View File

@@ -0,0 +1,43 @@
package com.cczsa.xinghe.codegen.entity.domain.template;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* @author xia
* &#064;date 2026/1/17
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "代码生成-参数")
public class CodeGen implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "代码生成类型不能为空")
@Schema(description = "代码生成类型")
private CodeGenType codeGenType;
@Schema(description = "功能ID")
private Long itemId;
@Hidden
@AssertTrue(message = "当代码生成类型为 CONTROLLER 时功能ID不能为空")
public boolean isItemIdValid() {
if (codeGenType == CodeGenType.CONTROLLER) {
return itemId != null;
}
return true;
}
}

View File

@@ -0,0 +1,36 @@
package com.cczsa.xinghe.codegen.entity.domain.template;
import com.fasterxml.jackson.annotation.JsonValue;
import com.mybatisflex.annotation.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
/**
* @author xia
* &#064;date 2026/1/17
* @version 0.0.1
*/
@Schema(description = "代码生成类型")
@Getter
public enum CodeGenType {
CONTROLLER(0, "controller"),
MODULE_DATA_INFO(1, "module_data_info"),
ROLE_PERMISSION(2,"role_permission"),
MENU_DATA_INFO(3, "menu_data_info");
private final int code;
private final String desc;
CodeGenType(int code, String desc) {
this.code = code;
this.desc = desc;
}
@EnumValue
@JsonValue
public int getCode() {
return code;
}
}

View File

@@ -0,0 +1,87 @@
package com.cczsa.xinghe.codegen.entity.domain.template;
import com.alibaba.fastjson2.JSONObject;
import com.cczsa.xinghe.codegen.entity.FunOperationEntity;
import com.cczsa.xinghe.codegen.util.StringUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author xia
* &#064;date 2026/1/19
* @version 0.0.1
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class FunOperationTemp extends FunOperationEntity {
/**
* 模块名称
*/
private String moduleName;
/**
* 模块编码
*/
private String moduleCode;
/**
* 功能名称
*/
private String itemName;
/**
* 功能编码
*/
private String itemCode;
/**
* URL路径
*/
private String url;
/**
* 方法名
*/
private String methodName;
/**
* 方法名 驼峰
*/
private String methodNamePascalCase;
/**
* 路径参数是否为空
*/
private Boolean isPathParams;
/**
* 路径参数 Long入参
*/
private String pathParamsLong;
/**
* 路径参数 Long入参
*/
private String pathParamsLongReq;
/**
* 路径参数 url入参
*/
private String pathParamsUrl;
/**
* usableConfig 转成字符串
*/
private String usableConfigJson;
/**
* fieldConfig 转成字符串
*/
private String fieldConfigJson;
public void info(){
url = StringUtils.toPath(this.getOperationCode());
methodName = StringUtils.toCamelCase(this.getOperationCode());
methodNamePascalCase = StringUtils.toPascalCase(this.getOperationCode());
isPathParams= StringUtils.isNotEmpty(this.getPathParams());
if (isPathParams){
pathParamsLongReq = "Long "+this.getPathParams();
pathParamsLong = "@PathVariable(\""+this.getPathParams()+"\") Long "+this.getPathParams();
pathParamsUrl = "/{"+this.getPathParams()+"}";
}
usableConfigJson = JSONObject.toJSONString(this.getUsableConfig());
fieldConfigJson = JSONObject.toJSONString(this.getFieldConfig()).replace("\"", "'");;
}
}

View File

@@ -0,0 +1,28 @@
package com.cczsa.xinghe.codegen.entity.domain.template;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.FunModuleEntity;
import com.cczsa.xinghe.codegen.entity.FunOperationEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* @author xia
* &#064;date 2026/1/17
* @version 0.0.1
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class FunctionCode extends TemplateObj{
// 模块信息
private FunModuleEntity moduleEntity;
// 功能信息
private FunItemEntity itemEntity;
// 操作信息
private List<FunOperationEntity> operationEntityList;
}

View File

@@ -0,0 +1,10 @@
package com.cczsa.xinghe.codegen.entity.domain.template;
/**
* @author xia
* &#064;date 2026/1/17
* @version 0.0.1
*/
public class TemplateObj {
}

View File

@@ -0,0 +1,36 @@
package com.cczsa.xinghe.codegen.entity.enums;
import com.fasterxml.jackson.annotation.JsonValue;
import com.mybatisflex.annotation.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
/**
* 客户端类型枚举
*
* @author My
*/
@Schema(description = "客户端类型",
example = "0",
allowableValues = {"0: PC端", "1: 小程序端", "2: H5端"})
@Getter
public enum ClientTypeEnum {
// 客户端类型0 PC端1 小程序端2 H5端
PC(0, "PC端"),
MINI_PROGRAM(1, "小程序端"),
H5(2, "H5端");
private final int code;
private final String desc;
ClientTypeEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
@JsonValue
@EnumValue
public int getCode() {
return code;
}
}

View File

@@ -0,0 +1,36 @@
package com.cczsa.xinghe.codegen.entity.enums;
import com.fasterxml.jackson.annotation.JsonValue;
import com.mybatisflex.annotation.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
/**
* 菜单类型
*
* @author My
*/
@Schema(description = "菜单类型",
example = "0",
allowableValues = {"0: 菜单", "1: 按钮"})
@Getter
public enum MenuTypeEnum {
// 0: 菜单 1: 按钮
MENU_ID(0, "菜单"),
BUTTON_ID(1, "按钮");
private final int code;
private final String desc;
MenuTypeEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
@JsonValue
@EnumValue
public int getCode() {
return code;
}
}

View File

@@ -0,0 +1,35 @@
package com.cczsa.xinghe.codegen.entity.enums;
import com.fasterxml.jackson.annotation.JsonValue;
import com.mybatisflex.annotation.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
/**
* 角色类型枚举
*
* @author My
*/
@Schema(description = "角色类型",
example = "0",
allowableValues = {"0: 平台", "1: 套餐"})
@Getter
public enum RoleTypeEnum {
PLATFORM(0, "平台"),
PACKAGE(1, "套餐");
private final int code;
private final String desc;
RoleTypeEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
@JsonValue
@EnumValue
public int getCode() {
return code;
}
}

View File

@@ -0,0 +1,59 @@
package com.cczsa.xinghe.codegen.entity.enums;
import com.fasterxml.jackson.annotation.JsonValue;
import com.mybatisflex.annotation.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 模板类型枚举
*
* @author My
*/
@Schema(description = "从接口:/templateType 获取列表")
@Getter
public enum TemplateTypeEnum {
CONTROLLER(0, "controller"),
REQUEST_PARAM(1, "请求参数"),
RESPONSE_PARAM(2, "响应参数"),
SERVICE(3, "服务接口"),
SERVICE_IMPL(4, "服务实现"),
MODULE_DATA_INFO(5, "模块功能操作数据生成"),
ROLE_DATA_INFO(6, "角色套餐权限数据生成"),
MENU_DATA_INFO(7, "菜单数据生成");
private final int code;
private final String desc;
TemplateTypeEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
@JsonValue
@EnumValue
public int getCode() {
return code;
}
/**
* 获取枚举值列表
*/
public static List<Map<Integer, String>> getEnumList() {
return Arrays.stream(values())
.map(enumValue -> {
Map<Integer, String> map = new HashMap<>();
map.put(enumValue.getCode(), enumValue.getDesc());
return map;
})
.collect(Collectors.toList());
}
}

View File

@@ -1,9 +1,9 @@
package com.cczsa.xinghe.codegen.entity.req.funItem;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
@@ -20,7 +20,6 @@ public class FunItemQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "模块ID不能为空")
@Schema(description = "模块ID")
private Long moduleId;
@@ -30,4 +29,7 @@ public class FunItemQueryReq implements Serializable {
@Schema(description = "功能编码")
private String itemCode;
@Schema(description = "是否租户")
private Boolean isTenant;
}

View File

@@ -41,7 +41,7 @@ public class FunItemSaveUpdateReq implements Serializable {
private String itemName;
@NotBlank(message = "功能编码不能为空")
@Pattern(regexp = "^[a-z]+$", message = "功能编码只能包含英文小写字母")
@Pattern(regexp = "^[a-z][a-zA-Z]*$", message = "功能编码只能以小写字母开头,可包含大小写字母,支持小驼峰命名")
@Schema(description = "功能编码")
private String itemCode;

View File

@@ -42,10 +42,12 @@ public class FunModuleSaveUpdateReq implements Serializable {
@Schema(description = "描述")
private String describe;
@Pattern(regexp = "^[a-z]+(\\.[a-z]+)*$", message = "参数包名只能包含小写英文字母和点(.)如com.cczsa.xinghe.codegen")
@NotBlank(message = "包名称不能为空")
@Schema(description = "包名称")
private String packageName;
@Pattern(regexp = "^[a-z]+(\\.[a-z]+)*$", message = "参数包名只能包含小写英文字母和点(.)如com.cczsa.xinghe.codegen")
@NotBlank(message = "参数包名不能为空")
@Schema(description = "参数包名")
private String apiPackageName;

View File

@@ -4,14 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取操作列表 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取操作列表-参数")
@@ -20,6 +16,11 @@ public class FunOperationQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "模块ID")
@NotNull(message = "模块ID不能为空")
private Long moduleId;
@Schema(description = "功能ID(表主键ID)")
private Long itemId;
@@ -29,4 +30,4 @@ public class FunOperationQueryReq implements Serializable {
@Schema(description = "操作编码")
private String operationCode;
}
}

View File

@@ -6,6 +6,7 @@ import com.cczsa.xinghe.codegen.entity.enums.UsableConfigEnum;
import com.cczsa.xinghe.codegen.handler.PostgreSQLJsonTypeHandler;
import com.mybatisflex.annotation.Column;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
@@ -54,7 +55,7 @@ public class FunOperationSaveUpdateReq implements Serializable {
private String funName;
@NotBlank(message = "操作编码不能为空")
@Pattern(regexp = "^[a-z]+(?:-[a-z]+)*$", message = "操作编码只能包含英文小写字母和连字符(-)且连字符不能在开头或结尾")
@Pattern(regexp = "^([a-z][a-zA-Z]*|([a-z]+(?:-[a-z]+)*))$", message = "操作编码只能以小写字母开头,可包含大小写字母支持小驼峰命名,或只包含小写字母和连字符(-)且连字符不能在开头或结尾")
@Schema(description = "操作编码")
private String operationCode;
@@ -73,7 +74,7 @@ public class FunOperationSaveUpdateReq implements Serializable {
@Schema(description = "可配置字段")
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<String> fieldCofnig;
private List<String> fieldConfig;
@Schema(description = "排序")
private Integer sortOrder;
@@ -87,4 +88,36 @@ public class FunOperationSaveUpdateReq implements Serializable {
@Max(value = 99, message = "操作ID必须大于等于10小于等于99")
private Integer operationId;
@NotNull(message = "是否需要请求参数不能为空")
@Schema(description = "是否需要请求参数")
private Boolean isReqParams;
@NotNull(message = "是否需要响应参数不能为空")
@Schema(description = "是否需要响应参数")
private Boolean isResParams;
@NotNull(message = "是否分页不能为空")
@Schema(description = "是否分页")
private Boolean isPage;
@Pattern(regexp = "^[a-zA-Z]*$", message = "路径参数只能包含英文字符")
@Schema(description = "路径参数")
private String pathParams;
@AssertTrue(message = "当不需要响应参数时,也不能分页")
public boolean isValidPageAndResParams() {
if (Boolean.FALSE.equals(isResParams)) {
return Boolean.FALSE.equals(isPage);
}
return true;
}
@AssertTrue(message = "当需要请求参数时,路径参数必须为空")
public boolean isValidReqParamsAndPathParams() {
if (Boolean.TRUE.equals(isReqParams)) {
return pathParams == null || pathParams.isEmpty();
}
return true;
}
}

View File

@@ -0,0 +1,66 @@
package com.cczsa.xinghe.codegen.entity.req.menu;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.MenuTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 创建菜单 请求参数
*
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "创建菜单-参数")
public class MenuAddReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "客户端类型不能为空")
@Schema(description = "客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum clientType;
@NotNull(message = "菜单名称不能为空")
@Schema(description = "菜单名称")
private String menuName;
@Schema(description = "父菜单ID")
private Long parentId = 0L;
@Pattern(
regexp = "^(?:$|/(?:[a-zA-Z0-9_=?#&-]+/)*[a-zA-Z0-9_=?#&-]+)$",
message = "路由路径格式不正确:必须以'/'开头,不能以'/'结尾,且只能包含字母、数字、下划线、横杠、等号、问号、井号、与号,以及分隔斜杠(不能连续)"
)
@Schema(description = "路由路径")
private String path;
@Schema(description = "页面路径")
private String pagePath;
@Schema(description = "菜单图标")
private String icon;
@NotNull(message = "是否租户不能为空")
@Schema(description = "是否租户")
private Boolean isTenant;
@Schema(description = "是否隐藏")
private Boolean isHide;
@Schema(description = "排序")
private Integer sortOrder;
@NotNull(message = "菜单类型不能为空")
@Schema(description = "0菜单1按钮")
private MenuTypeEnum menuType;
}

View File

@@ -0,0 +1,33 @@
package com.cczsa.xinghe.codegen.entity.req.menu;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 菜单绑定权限 请求参数
*
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "菜单绑定权限-参数")
public class MenuBindFunReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "菜单ID不能为空")
@Schema(description = "菜单ID")
private Long menuId;
@NotNull(message = "功能ID不能为空")
@Schema(description = "功能ID")
private Long funId;
}

View File

@@ -0,0 +1,68 @@
package com.cczsa.xinghe.codegen.entity.req.menu;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.MenuTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 修改菜单 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "修改菜单-参数")
public class MenuEditReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "主键ID不能为空")
@Schema(description = "主键ID")
private Long id;
@NotNull(message = "客户端类型不能为空")
@Schema(description = "客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum clientType;
@NotNull(message = "菜单名称不能为空")
@Schema(description = "菜单名称")
private String menuName;
@Schema(description = "父菜单ID")
private Long parentId = 0L;
@Pattern(
regexp = "^(?:$|/(?:[a-zA-Z0-9_=?#&-]+/)*[a-zA-Z0-9_=?#&-]+)$",
message = "路由路径格式不正确:必须以'/'开头,不能以'/'结尾,且只能包含字母、数字、下划线、横杠、等号、问号、井号、与号,以及分隔斜杠(不能连续)"
)
@Schema(description = "路由路径")
private String path;
@Schema(description = "页面路径")
private String pagePath;
@Schema(description = "菜单图标")
private String icon;
@NotNull(message = "是否租户不能为空")
@Schema(description = "是否租户")
private Boolean isTenant;
@Schema(description = "是否隐藏")
private Boolean isHide;
@Schema(description = "排序")
private Integer sortOrder;
@NotNull(message = "菜单类型不能为空")
@Schema(description = "0菜单1按钮")
private MenuTypeEnum menuType;
}

View File

@@ -0,0 +1,34 @@
package com.cczsa.xinghe.codegen.entity.req.menu;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取菜单列表 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取菜单列表-参数")
public class MenuQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull( message = "客户端类型不能为空")
@Schema(description = "客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum clientType;
@Schema(description = "菜单名称")
private String menuName;
@Schema(description = "父菜单ID")
private Long parentId;
}

View File

@@ -0,0 +1,41 @@
package com.cczsa.xinghe.codegen.entity.req.role;
import com.cczsa.xinghe.codegen.entity.enums.RoleTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 创建角色 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "创建角色-参数")
public class RoleAddReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Min(value = 100, message = "id必须大于等于100小于等于999")
@Max(value = 999, message = "id必须大于等于100小于等于999")
@NotNull(message = "角色id不能为空")
@Schema(description = "角色id")
private Long id;
@NotBlank(message = "角色名称不能为空")
@Schema(description = "角色名称")
private String roleName;
@NotNull(message = "角色类型不能为空")
@Schema(description = "角色类型")
private RoleTypeEnum roleType;
}

View File

@@ -0,0 +1,51 @@
package com.cczsa.xinghe.codegen.entity.req.role;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.UsableConfigEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 角色设置权限 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "角色设置权限-参数")
public class RoleBindFunReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "角色不能为空")
@Schema(description = "角色id")
private Long roleId;
@NotNull(message = "权限不能为空")
@Schema(description = "权限id")
private Long funId;
@Schema(description = "数据权限")
private UsableConfigEnum dataScope;
@Schema(description = "指定的部门ids")
private List<Long> deptDataScope;
@Schema(description = "指定的用户ids")
private List<Long> userDataScope;
@Schema(description = "排除的字段 根据 fieldConfig 进行设置")
private List<String> excludeField = new ArrayList<>();
@NotNull(message = "客户端类型不能为空")
@Schema(description = "客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum clientType;
}

View File

@@ -0,0 +1,41 @@
package com.cczsa.xinghe.codegen.entity.req.role;
import com.cczsa.xinghe.codegen.entity.enums.RoleTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 修改角色 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "修改角色-参数")
public class RoleEditReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Min(value = 100, message = "id必须大于等于100小于等于999")
@Max(value = 999, message = "id必须大于等于100小于等于999")
@NotNull(message = "角色id不能为空")
@Schema(description = "角色id")
private Long id;
@NotBlank(message = "角色名称不能为空")
@Schema(description = "角色名称")
private String roleName;
@NotNull(message = "角色类型不能为空")
@Schema(description = "角色类型")
private RoleTypeEnum roleType;
}

View File

@@ -0,0 +1,33 @@
package com.cczsa.xinghe.codegen.entity.req.role;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取角色功能权限配置 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取角色功能权限配置-参数")
public class RoleQueryFunReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "角色id不能为空")
@Schema(description = "角色id")
private Long roleId;
@NotNull(message = "客户端类型不能为空")
@Schema(description = "客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum clientType;
}

View File

@@ -0,0 +1,29 @@
package com.cczsa.xinghe.codegen.entity.req.role;
import com.cczsa.xinghe.codegen.entity.enums.RoleTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取角色列表 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取角色列表-参数")
public class RoleQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "角色名称")
private String roleName;
@Schema(description = "角色类型")
private RoleTypeEnum roleType;
}

View File

@@ -0,0 +1,42 @@
package com.cczsa.xinghe.codegen.entity.req.template;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 创建模板 请求参数
*
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "创建模板-参数")
public class TemplateAddReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "是否使用不能为空")
@Schema(description = "是否使用")
private Boolean isUse;
@NotBlank(message = "模板名称不能为空")
@Schema(description = "模板名称")
private String templateName;
@NotNull(message = "模板类型不能为空")
private TemplateTypeEnum templateType;
@NotBlank(message = "正文不能为空")
@Schema(description = "正文")
private String content;
}

View File

@@ -0,0 +1,44 @@
package com.cczsa.xinghe.codegen.entity.req.template;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 修改模板 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "修改模板-参数")
public class TemplateEditReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "id不能为空")
@Schema(description = "id")
private Long id;
@NotNull(message = "是否使用不能为空")
@Schema(description = "是否使用")
private Boolean isUse;
@NotBlank(message = "模板名称不能为空")
@Schema(description = "模板名称")
private String templateName;
@NotNull(message = "模板类型不能为空")
private TemplateTypeEnum templateType;
@NotBlank(message = "正文不能为空")
@Schema(description = "正文")
private String content;
}

View File

@@ -0,0 +1,31 @@
package com.cczsa.xinghe.codegen.entity.req.template;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取模板列表 请求参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取模板列表-参数")
public class TemplateQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "是否使用")
private Boolean isUse;
@Schema(description = "模板名称")
private String templateName;
private TemplateTypeEnum templateType;
}

View File

@@ -27,6 +27,9 @@ public class FunItemQueryRes implements Serializable {
@Schema(description = "模块ID")
private Long moduleId;
@Schema(description = "模块名称")
private String moduleName;
@Schema(description = "功能名称")
private String itemName;

View File

@@ -1,6 +1,7 @@
package com.cczsa.xinghe.codegen.entity.res.funModule;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;

View File

@@ -6,11 +6,6 @@ import com.cczsa.xinghe.codegen.entity.enums.UsableConfigEnum;
import com.cczsa.xinghe.codegen.handler.PostgreSQLJsonTypeHandler;
import com.mybatisflex.annotation.Column;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Getter;
import lombok.Setter;
@@ -38,9 +33,15 @@ public class FunOperationQueryRes implements Serializable {
@Schema(description = "模块ID(表主键ID)")
private Long moduleId;
@Schema(description = "模块名称")
private String moduleName;
@Schema(description = "功能ID(表主键ID)")
private Long itemId;
@Schema(description = "功能名称")
private String itemName;
@Schema(description = "是否直接放行")
private Boolean isGreenLight;
@@ -62,7 +63,7 @@ public class FunOperationQueryRes implements Serializable {
@Schema(description = "可配置字段")
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<String> fieldCofnig;
private List<String> fieldConfig;
@Schema(description = "排序")
private Integer sortOrder;
@@ -73,4 +74,16 @@ public class FunOperationQueryRes implements Serializable {
@Schema(description = "操作ID")
private Integer operationId;
@Schema(description = "是否需要请求参数")
private Boolean isReqParams;
@Schema(description = "是否需要响应参数")
private Boolean isResParams;
@Schema(description = "是否分页")
private Boolean isPage;
@Schema(description = "路径参数")
private String pathParams;
}

View File

@@ -0,0 +1,69 @@
package com.cczsa.xinghe.codegen.entity.res.menu;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.MenuTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 获取菜单列表 响应参数
*
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取菜单列表-响应")
public class MenuQueryRes implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
private Long id;
@Schema(description = "客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum clientType;
@Schema(description = "菜单名称")
private String menuName;
@Schema(description = "父菜单ID")
private Long parentId = 0L;
@Schema(description = "路由路径")
private String path;
@Schema(description = "菜单图标")
private String icon;
@Schema(description = "是否租户")
private Boolean isTenant;
@Schema(description = "是否隐藏")
private Boolean isHide;
@Schema(description = "排序")
private Integer sortOrder;
@Schema(description = "0菜单1按钮")
private MenuTypeEnum menuType;
@Schema(description = "功能ID")
private Long funId;
@Schema(description = "功能名称")
private String funName;
@Schema(description = "功能存在个数")
private Integer existNum;
@Schema(description = "子菜单")
private List<MenuQueryRes> children;
}

View File

@@ -0,0 +1,100 @@
package com.cczsa.xinghe.codegen.entity.res.role;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.MenuTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.UsableConfigEnum;
import com.cczsa.xinghe.codegen.handler.PostgreSQLJsonTypeHandler;
import com.mybatisflex.annotation.Column;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 获取角色功能权限配置 响应参数
*
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取角色功能权限配置-响应")
public class RoleQueryFunRes implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "菜单ID")
private Long id;
@Schema(description = "客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum clientType;
@Schema(description = "菜单名称")
private String menuName;
@Schema(description = "父菜单ID")
private Long parentId = 0L;
private MenuTypeEnum menuType;
@Schema(description = "路由路径")
private String path;
@Schema(description = "菜单图标")
private String icon;
@Schema(description = "是否租户")
private Boolean isTenant;
@Schema(description = "是否隐藏")
private Boolean isHide;
@Schema(description = "排序")
private Integer sortOrder;
@Schema(description = "权限id")
private Long funId;
@Schema(description = "操作名称")
private String funName;
@Schema(description = "可配置数据类型")
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<UsableConfigEnum> usableConfig;
@Schema(description = "可配置字段")
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<String> fieldConfig;
@Schema(description = "说明")
private String describe;
@Schema(description = "是否已选择")
private Boolean isSelect = false;
@Schema(description = "角色权限绑定的id")
private Long funBindId;
@Schema(description = "数据权限")
private UsableConfigEnum dataScope;
@Schema(description = "指定的数据权限范围")
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<Long> assignDataScope;
@Schema(description = "排除的字段")
@Column(typeHandler = PostgreSQLJsonTypeHandler.class)
private List<String> excludeField;
@Schema(description = "功能客户端类型0 PC端1 小程序端2 H5端")
private ClientTypeEnum funClientType;
@Schema(description = "子菜单")
private List<RoleQueryFunRes> children;
}

View File

@@ -0,0 +1,34 @@
package com.cczsa.xinghe.codegen.entity.res.role;
import com.cczsa.xinghe.codegen.entity.enums.RoleTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取角色列表 响应参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取角色列表-响应")
public class RoleQueryRes implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "角色id")
private Long id;
@Schema(description = "角色名称")
private String roleName;
@Schema(description = "角色类型")
private RoleTypeEnum roleType;
}

View File

@@ -0,0 +1,38 @@
package com.cczsa.xinghe.codegen.entity.res.template;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
/**
* 获取模板列表 响应参数
* @author xia
* @version 0.0.1
*/
@Getter
@Setter
@Schema(description = "获取模板列表-响应")
public class TemplateQueryRes implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "id")
private Long id;
@Schema(description = "是否使用")
private Boolean isUse;
@Schema(description = "模板名称")
private String templateName;
private TemplateTypeEnum templateType;
@Schema(description = "正文")
private String content;
}

View File

@@ -0,0 +1,16 @@
package com.cczsa.xinghe.codegen.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.mybatisflex.core.BaseMapper;
import com.cczsa.xinghe.codegen.entity.MenuEntity;
/**
* 菜单 映射层。
*
* @author xiayb
* @since 0.0.1
*/
@Mapper
public interface MenuMapper extends BaseMapper<MenuEntity> {
}

View File

@@ -0,0 +1,16 @@
package com.cczsa.xinghe.codegen.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.mybatisflex.core.BaseMapper;
import com.cczsa.xinghe.codegen.entity.RoleFunEntity;
/**
* 角色权限表 映射层。
*
* @author My
* @since 0.0.1
*/
@Mapper
public interface RoleFunMapper extends BaseMapper<RoleFunEntity> {
}

View File

@@ -0,0 +1,16 @@
package com.cczsa.xinghe.codegen.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.mybatisflex.core.BaseMapper;
import com.cczsa.xinghe.codegen.entity.RoleEntity;
/**
* 角色表 映射层。
*
* @author My
* @since 0.0.1
*/
@Mapper
public interface RoleMapper extends BaseMapper<RoleEntity> {
}

View File

@@ -0,0 +1,16 @@
package com.cczsa.xinghe.codegen.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.mybatisflex.core.BaseMapper;
import com.cczsa.xinghe.codegen.entity.TemplateEntity;
/**
* 映射层。
*
* @author My
* @since 0.0.1
*/
@Mapper
public interface TemplateMapper extends BaseMapper<TemplateEntity> {
}

View File

@@ -6,7 +6,7 @@ import com.mybatisflex.core.table.TableDef;
import java.io.Serial;
/**
* 操作 表定义层。
* 操作配置 表定义层。
*
* @author My
* @since 0.0.1
@@ -17,7 +17,7 @@ public class FunOperationDef extends TableDef {
private static final long serialVersionUID = 1L;
/**
* 操作
* 操作配置
*/
public static final FunOperationDef FUN_OPERATION_ENTITY = new FunOperationDef();
@@ -26,6 +26,11 @@ public class FunOperationDef extends TableDef {
*/
public final QueryColumn ID = new QueryColumn(this, "id");
/**
* 是否分页
*/
public final QueryColumn IS_PAGE = new QueryColumn(this, "is_page");
/**
* 功能ID(表主键ID)
*/
@@ -42,12 +47,12 @@ public class FunOperationDef extends TableDef {
public final QueryColumn FUN_TYPE = new QueryColumn(this, "fun_type");
/**
* 说明
* 说明说明
*/
public final QueryColumn DESCRIBE = new QueryColumn(this, "describe");
/**
* 模块ID(表主键ID)
* 模块ID
*/
public final QueryColumn MODULE_ID = new QueryColumn(this, "module_id");
@@ -56,10 +61,25 @@ public class FunOperationDef extends TableDef {
*/
public final QueryColumn SORT_ORDER = new QueryColumn(this, "sort_order");
/**
* 路径参数与请求参数true互斥
*/
public final QueryColumn PATH_PARAMS = new QueryColumn(this, "path_params");
/**
* 可配置字段
*/
public final QueryColumn FIELD_COFNIG = new QueryColumn(this, "field_cofnig");
public final QueryColumn FIELD_CONFIG = new QueryColumn(this, "field_config");
/**
* 是否需要请求参数
*/
public final QueryColumn IS_REQ_PARAMS = new QueryColumn(this, "is_req_params");
/**
* 是否需要响应参数
*/
public final QueryColumn IS_RES_PARAMS = new QueryColumn(this, "is_res_params");
/**
* 操作ID
@@ -94,7 +114,7 @@ public class FunOperationDef extends TableDef {
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, MODULE_ID, ITEM_ID, IS_GREEN_LIGHT, FUN_NAME, OPERATION_CODE, FUN_TYPE, REQUEST_TYPE, USABLE_CONFIG, FIELD_COFNIG, SORT_ORDER, DESCRIBE, OPERATION_ID};
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, MODULE_ID, ITEM_ID, IS_GREEN_LIGHT, OPERATION_ID, OPERATION_CODE, FUN_NAME, FUN_TYPE, REQUEST_TYPE, IS_REQ_PARAMS, IS_RES_PARAMS, IS_PAGE, PATH_PARAMS, USABLE_CONFIG, FIELD_CONFIG, SORT_ORDER, DESCRIBE};
public FunOperationDef() {
super("", "cg_fun_operation");

View File

@@ -0,0 +1,107 @@
package com.cczsa.xinghe.codegen.mapper.def;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.table.TableDef;
import java.io.Serial;
/**
* 菜单 表定义层。
*
* @author xiayb
* @since 0.0.1
*/
public class MenuDef extends TableDef {
@Serial
private static final long serialVersionUID = 1L;
/**
* 菜单
*/
public static final MenuDef MENU_ENTITY = new MenuDef();
/**
* 主键ID
*/
public final QueryColumn ID = new QueryColumn(this, "id");
/**
* 菜单图标
*/
public final QueryColumn ICON = new QueryColumn(this, "icon");
/**
* 路由路径
*/
public final QueryColumn PATH = new QueryColumn(this, "path");
/**
* 操作ID/来自操作表
*/
public final QueryColumn FUN_ID = new QueryColumn(this, "fun_id");
/**
* 是否隐藏
*/
public final QueryColumn IS_HIDE = new QueryColumn(this, "is_hide");
/**
* 是否租户
*/
public final QueryColumn IS_TENANT = new QueryColumn(this, "is_tenant");
/**
* 菜单名称
*/
public final QueryColumn MENU_NAME = new QueryColumn(this, "menu_name");
/**
* 0菜单1按钮
*/
public final QueryColumn MENU_TYPE = new QueryColumn(this, "menu_type");
/**
* 页面路径
*/
public final QueryColumn PAGE_PATH = new QueryColumn(this, "page_path");
/**
* 父菜单ID
*/
public final QueryColumn PARENT_ID = new QueryColumn(this, "parent_id");
/**
* 排序
*/
public final QueryColumn SORT_ORDER = new QueryColumn(this, "sort_order");
/**
* 客户端类型0 PC端1 小程序端2 H5端
*/
public final QueryColumn CLIENT_TYPE = new QueryColumn(this, "client_type");
/**
* 所有字段。
*/
public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*");
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, CLIENT_TYPE, MENU_NAME, PARENT_ID, FUN_ID, MENU_TYPE, PATH, PAGE_PATH, ICON, IS_TENANT, IS_HIDE, SORT_ORDER};
public MenuDef() {
super("", "cg_menu");
}
private MenuDef(String schema, String name, String alisa) {
super(schema, name, alisa);
}
public MenuDef as(String alias) {
String key = getNameWithSchema() + "." + alias;
return getCache(key, k -> new MenuDef("", "cg_menu", alias));
}
}

View File

@@ -0,0 +1,62 @@
package com.cczsa.xinghe.codegen.mapper.def;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.table.TableDef;
import java.io.Serial;
/**
* 角色表 表定义层。
*
* @author My
* @since 0.0.1
*/
public class RoleDef extends TableDef {
@Serial
private static final long serialVersionUID = 1L;
/**
* 角色表
*/
public static final RoleDef ROLE_ENTITY = new RoleDef();
/**
* 主键ID
*/
public final QueryColumn ID = new QueryColumn(this, "id");
/**
* 角色名称
*/
public final QueryColumn ROLE_NAME = new QueryColumn(this, "role_name");
/**
* 角色类型 0平台 1套餐
*/
public final QueryColumn ROLE_TYPE = new QueryColumn(this, "role_type");
/**
* 所有字段。
*/
public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*");
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, ROLE_NAME, ROLE_TYPE};
public RoleDef() {
super("", "cg_role");
}
private RoleDef(String schema, String name, String alisa) {
super(schema, name, alisa);
}
public RoleDef as(String alias) {
String key = getNameWithSchema() + "." + alias;
return getCache(key, k -> new RoleDef("", "cg_role", alias));
}
}

View File

@@ -0,0 +1,82 @@
package com.cczsa.xinghe.codegen.mapper.def;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.table.TableDef;
import java.io.Serial;
/**
* 角色权限表 表定义层。
*
* @author My
* @since 0.0.1
*/
public class RoleFunDef extends TableDef {
@Serial
private static final long serialVersionUID = 1L;
/**
* 角色权限表
*/
public static final RoleFunDef ROLE_FUN_ENTITY = new RoleFunDef();
/**
* 主键ID
*/
public final QueryColumn ID = new QueryColumn(this, "id");
/**
* 操作ID
*/
public final QueryColumn FUN_ID = new QueryColumn(this, "fun_id");
/**
* 角色ID
*/
public final QueryColumn ROLE_ID = new QueryColumn(this, "role_id");
/**
* 数据权限默认:0无
*/
public final QueryColumn DATA_SCOPE = new QueryColumn(this, "data_scope");
/**
* 客户端类型0 PC端1 小程序端2 H5端
*/
public final QueryColumn CLIENT_TYPE = new QueryColumn(this, "client_type");
/**
* 排除的字段
*/
public final QueryColumn EXCLUDE_FIELD = new QueryColumn(this, "exclude_field");
/**
* 指定的数据权限范围
*/
public final QueryColumn ASSIGN_DATA_SCOPE = new QueryColumn(this, "assign_data_scope");
/**
* 所有字段。
*/
public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*");
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, ROLE_ID, FUN_ID, DATA_SCOPE, ASSIGN_DATA_SCOPE, EXCLUDE_FIELD, CLIENT_TYPE};
public RoleFunDef() {
super("", "cg_role_fun");
}
private RoleFunDef(String schema, String name, String alisa) {
super(schema, name, alisa);
}
public RoleFunDef as(String alias) {
String key = getNameWithSchema() + "." + alias;
return getCache(key, k -> new RoleFunDef("", "cg_role_fun", alias));
}
}

View File

@@ -0,0 +1,72 @@
package com.cczsa.xinghe.codegen.mapper.def;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.table.TableDef;
import java.io.Serial;
/**
* 表定义层。
*
* @author My
* @since 0.0.1
*/
public class TemplateDef extends TableDef {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
public static final TemplateDef TEMPLATE_ENTITY = new TemplateDef();
/**
* 主键ID
*/
public final QueryColumn ID = new QueryColumn(this, "id");
/**
* 是否使用
*/
public final QueryColumn IS_USE = new QueryColumn(this, "is_use");
/**
* 正文
*/
public final QueryColumn CONTENT = new QueryColumn(this, "content");
/**
* 模板名称
*/
public final QueryColumn TEMPLATE_NAME = new QueryColumn(this, "template_name");
/**
* 模板类型
*/
public final QueryColumn TEMPLATE_TYPE = new QueryColumn(this, "template_type");
/**
* 所有字段。
*/
public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*");
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, IS_USE, TEMPLATE_NAME, TEMPLATE_TYPE, CONTENT};
public TemplateDef() {
super("", "cg_template");
}
private TemplateDef(String schema, String name, String alisa) {
super(schema, name, alisa);
}
public TemplateDef as(String alias) {
String key = getNameWithSchema() + "." + alias;
return getCache(key, k -> new TemplateDef("", "cg_template", alias));
}
}

View File

@@ -0,0 +1,12 @@
package com.cczsa.xinghe.codegen.service;
import com.cczsa.xinghe.codegen.entity.domain.template.CodeGen;
/**
* @author xia
* &#064;date 2026/1/10
* @version 0.0.1
*/
public interface CodeGenService {
byte[] generateCodeZip(CodeGen req);
}

View File

@@ -19,7 +19,7 @@ public interface FunOperationService {
/**
* 获取操作列表
*/
XResult<List<FunOperationQueryRes>> query(FunOperationQueryReq req);
XResult<List<FunOperationQueryRes>> query(FunOperationQueryReq req, Boolean isTenant);
/**
* 创建/修改操作

View File

@@ -0,0 +1,55 @@
package com.cczsa.xinghe.codegen.service;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuAddReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuBindFunReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuEditReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuQueryReq;
import com.cczsa.xinghe.codegen.entity.res.menu.MenuQueryRes;
import com.cczsa.xinghe.codegen.util.XResult;
import java.util.List;
/**
* 菜单管理 服务层接口。
*
* @author xia
* @version 0.0.1
*/
public interface MenuService {
/**
* 获取菜单列表
*/
XResult<List<MenuQueryRes>> query(MenuQueryReq req);
/**
* 创建菜单
*/
XResult<Void> add(MenuAddReq req);
/**
* 修改菜单
*/
XResult<Void> edit(MenuEditReq req);
/**
* 删除菜单
*/
XResult<Void> delete(Long id);
/**
* 菜单绑定权限
*/
XResult<Void> bindFun(MenuBindFunReq req);
/**
* 删除菜单权限
*/
XResult<Void> deleteFun(Long menuId);
/**
* 根据ID获取菜单详情
*/
XResult<MenuQueryRes> getById(Long id);
}

View File

@@ -0,0 +1,58 @@
package com.cczsa.xinghe.codegen.service;
import com.cczsa.xinghe.codegen.entity.req.role.RoleAddReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleBindFunReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleEditReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleQueryFunReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleQueryReq;
import com.cczsa.xinghe.codegen.entity.res.role.RoleQueryFunRes;
import com.cczsa.xinghe.codegen.entity.res.role.RoleQueryRes;
import com.cczsa.xinghe.codegen.util.XResult;
import java.util.List;
/**
* 角色管理 服务层接口。
*
* @author xia
* @version 0.0.1
*/
public interface RoleService {
/**
* 获取角色列表
*/
XResult<List<RoleQueryRes>> query(RoleQueryReq req);
/**
* 创建角色
*/
XResult<Void> add(RoleAddReq req);
/**
* 修改角色
*/
XResult<Void> edit(RoleEditReq req);
/**
* 删除角色
*/
XResult<Void> delete(Long roleId);
/**
* 角色设置权限
*/
XResult<Void> bindFun(RoleBindFunReq req);
/**
* 删除角色权限
*/
XResult<Void> deleteFun(Long roleBindFunId);
/**
* 获取角色功能权限配置
*/
XResult<List<RoleQueryFunRes>> queryRoleFun(RoleQueryFunReq req);
}

View File

@@ -0,0 +1,53 @@
package com.cczsa.xinghe.codegen.service;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateAddReq;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateEditReq;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateQueryReq;
import com.cczsa.xinghe.codegen.entity.res.template.TemplateQueryRes;
import com.cczsa.xinghe.codegen.util.XResult;
import java.util.List;
import java.util.Map;
/**
* 模板管理 服务层接口。
*
* @author xia
* @version 0.0.1
*/
public interface TemplateService {
/**
* 获取模板列表
*/
XResult<List<TemplateQueryRes>> query(TemplateQueryReq req);
/**
* 创建模板
*/
XResult<Void> add(TemplateAddReq req);
/**
* 修改模板
*/
XResult<Void> edit(TemplateEditReq req);
/**
* 删除模板
*/
XResult<Void> delete(Long id);
/**
* 获取模板类型列表
*/
XResult<List<Map<Integer, String>>> getTemplateTypeList();
/**
* 根据模板类型获取模板内容的方法
* @return 返回对应模板类型的字符串内容
*/
String getTemplateTypeContent(TemplateTypeEnum templateType);
}

View File

@@ -0,0 +1,6 @@
/**
* @author xia
* &#064;date 2026/1/17
* @version 0.0.1
*/
package com.cczsa.xinghe.codegen.service.flow;

View File

@@ -0,0 +1,209 @@
package com.cczsa.xinghe.codegen.service.flow.template;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.FunModuleEntity;
import com.cczsa.xinghe.codegen.entity.domain.template.FunOperationTemp;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import com.cczsa.xinghe.codegen.mapper.FunItemMapper;
import com.cczsa.xinghe.codegen.mapper.FunModuleMapper;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.mapper.def.FunOperationDef;
import com.cczsa.xinghe.codegen.service.TemplateService;
import com.cczsa.xinghe.codegen.util.StringUtils;
import com.mybatisflex.core.query.QueryWrapper;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupString;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author xia
* &#064;date 2026/1/17
* @version 0.0.1
*/
@Slf4j
@RequiredArgsConstructor
@LiteflowComponent(id = "controllerCodeCreate", name = "controller 代码生成")
public class ControllerCodeCreate extends NodeComponent {
private final FunModuleMapper funModuleMapper;
private final FunItemMapper funItemMapper;
private final FunOperationMapper funOperationMapper;
private final TemplateService templateService;
// 模块信息
private FunModuleEntity moduleEntity;
// 功能信息
private FunItemEntity itemEntity;
// 操作信息
private List<FunOperationTemp> operationEntityList;
// 压缩流
private ZipOutputStream zos;
/**
* setResponseData()/getResponseData():用于整个流程的输入输出
* setInput()/getInput():用于节点间的输入数据
* setOutput()/getOutput():用于节点间的输出数据
* setChainReqData()/getChainReqData():用于链间数据传递
*/
@Override
public void process() throws Exception {
Long itemId = this.getContextBean(Long.class);
itemEntity = funItemMapper.selectOneById(itemId);
if (itemEntity == null){
return;
}
moduleEntity = funModuleMapper.selectOneById(itemEntity.getModuleId());
if (itemEntity == null){
return;
}
FunOperationDef def = FunOperationDef.FUN_OPERATION_ENTITY;
QueryWrapper query = QueryWrapper.create()
.select(def.ALL_COLUMNS)
.from(def)
.where(def.MODULE_ID.eq(moduleEntity.getId()))
.and(def.ITEM_ID.eq(itemId))
.orderBy(def.ID,true);
operationEntityList = funOperationMapper.selectListByQueryAs(query,FunOperationTemp.class);
if (operationEntityList == null){
operationEntityList = List.of();
}
operationEntityList.forEach(FunOperationTemp::info);
// 流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
zos = new ZipOutputStream(outputStream);
// 生成controller代码
generateControllerCode(TemplateTypeEnum.CONTROLLER);
// 生成请求参数代码
generateControllerCode(TemplateTypeEnum.REQUEST_PARAM);
// 生成响应参数代码
generateControllerCode(TemplateTypeEnum.RESPONSE_PARAM);
// 生成服务接口代码
generateControllerCode(TemplateTypeEnum.SERVICE);
// 生成服务接口实现代码
generateControllerCode(TemplateTypeEnum.SERVICE_IMPL);
// 确保 ZIP 流结束
zos.finish();
// 返回数据
this.getSlot().setResponseData(outputStream.toByteArray());
}
/**
* 生成Controller代码
*/
public void generateControllerCode(TemplateTypeEnum templateType) throws IOException {
// 获取
String template = templateService.getTemplateTypeContent(templateType);
if (template == null){
return;
}
// 生成
STGroup group = new STGroupString("db_template",template, '$', '$');
ST classTemplate = group.getInstanceOf("classTemplate"); // 使用正确的模板名称
if (classTemplate == null) {
System.out.println(template);
throw new RuntimeException("Template 'classTemplate' not found");
}
// 设置模板数据
Map<String, Object> basics = new HashMap<>();
setTemplateData(classTemplate,basics);
if(templateType == TemplateTypeEnum.REQUEST_PARAM || templateType == TemplateTypeEnum.RESPONSE_PARAM){
for (FunOperationTemp item : operationEntityList){
if (!isValidItem(templateType, item)) {
continue;
}
// 生成代码并写入ZIP
String itemStr = StringUtils.capitalizeFirstLetter(itemEntity.getItemCode());
String operStr = StringUtils.toPascalCase(item.getOperationCode());
basics.put("itemCodeUp", itemStr+operStr);
basics.put("oper", item);
writeCodeToZip(classTemplate, templateType, itemStr+ operStr);
}
return;
}
// 生成代码并写入ZIP
writeCodeToZip(classTemplate, templateType,StringUtils.capitalizeFirstLetter(itemEntity.getItemCode()));
}
private boolean isValidItem(TemplateTypeEnum templateType, FunOperationTemp item) {
return switch (templateType) {
case REQUEST_PARAM -> item.getIsReqParams();
case RESPONSE_PARAM -> item.getIsResParams();
default -> false;
};
}
/**
* 根据 TemplateTypeEnum 获取文件后缀名
* @param templateType 模板类型
* @return 文件后缀名
*/
private String getFileSuffix(TemplateTypeEnum templateType) {
return switch (templateType) {
case CONTROLLER -> "Controller.java";
case REQUEST_PARAM -> "Req.java";
case RESPONSE_PARAM -> "Res.java";
case SERVICE -> "Service.java";
case SERVICE_IMPL -> "ServiceImpl.java";
default -> throw new IllegalArgumentException("Invalid template type: " + templateType);
};
}
/**
* 设置模板数据
*
* @param classTemplate 模板对象
* @param basics 基础信息
*/
private void setTemplateData(ST classTemplate, Map<String, Object> basics) {
classTemplate.add("item", itemEntity);
classTemplate.add("module", moduleEntity);
classTemplate.add("operationList", operationEntityList);
// 基础信息
String itemCodeUp = StringUtils.capitalizeFirstLetter(itemEntity.getItemCode());
basics.put("itemCodeUp", itemCodeUp);
basics.put("path", StringUtils.toPath(itemEntity.getItemCode()));
classTemplate.add("basics", basics);
}
/**
* 生成代码并写入ZIP
*/
private void writeCodeToZip(ST classTemplate, TemplateTypeEnum templateType,String fileName) throws IOException {
// 生成代码
String result = classTemplate.render();
ZipEntry entry = new ZipEntry(fileName + getFileSuffix(templateType));
zos.putNextEntry(entry);
zos.write(result.getBytes(StandardCharsets.UTF_8));
zos.closeEntry();
}
}

View File

@@ -0,0 +1,74 @@
package com.cczsa.xinghe.codegen.service.flow.template;
import com.cczsa.xinghe.codegen.entity.MenuEntity;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import com.cczsa.xinghe.codegen.mapper.MenuMapper;
import com.cczsa.xinghe.codegen.service.TemplateService;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupString;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author xia
* &#064;date 2026/1/23
* @version 0.0.1
*/
@Slf4j
@RequiredArgsConstructor
@LiteflowComponent(id = "menuDataInfo", name = "菜单数据生成")
public class MenuDataInfo extends NodeComponent {
private final TemplateService templateService;
private final MenuMapper menuMapper;
// 压缩流
private ZipOutputStream zos;
@Override
public void process() throws Exception {
// 获取 模版
String template = templateService.getTemplateTypeContent(TemplateTypeEnum.MENU_DATA_INFO);
if (template == null){
return;
}
// 流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
zos = new ZipOutputStream(outputStream);
// 平台角色
STGroup group = new STGroupString("dbXml",template, '$', '$');
// 平台角色 功能权限
ST menuTemplate = group.getInstanceOf("menuTemplate"); // 使用正确的模板名称
List<MenuEntity> menuEntities = menuMapper.selectAll();
menuEntities.sort(Comparator.comparing(MenuEntity::getId));
menuTemplate.add("menus",menuEntities);
writeCodeToZip(menuTemplate);
// 确保 ZIP 流结束
zos.finish();
// 返回数据
this.getSlot().setResponseData(outputStream.toByteArray());
}
private void writeCodeToZip(ST st) throws IOException {
// 生成代码
String result = st.render();
ZipEntry entry = new ZipEntry("insert-menus-data.xml");
zos.putNextEntry(entry);
zos.write(result.getBytes(StandardCharsets.UTF_8));
zos.closeEntry();
}
}

View File

@@ -0,0 +1,116 @@
package com.cczsa.xinghe.codegen.service.flow.template;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.FunModuleEntity;
import com.cczsa.xinghe.codegen.entity.FunOperationEntity;
import com.cczsa.xinghe.codegen.entity.domain.template.FunOperationTemp;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import com.cczsa.xinghe.codegen.mapper.FunItemMapper;
import com.cczsa.xinghe.codegen.mapper.FunModuleMapper;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.mapper.def.FunItemDef;
import com.cczsa.xinghe.codegen.mapper.def.FunModuleDef;
import com.cczsa.xinghe.codegen.mapper.def.FunOperationDef;
import com.cczsa.xinghe.codegen.service.TemplateService;
import com.mybatisflex.core.query.QueryWrapper;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupString;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author xia
* &#064;date 2026/1/20
* @version 0.0.1
*/
@Slf4j
@RequiredArgsConstructor
@LiteflowComponent(id = "moduleDataInfo", name = "模块权限相关数据生成")
public class ModuleDataInfoCreate extends NodeComponent {
private final FunModuleMapper funModuleMapper;
private final FunItemMapper funItemMapper;
private final FunOperationMapper funOperationMapper;
private final TemplateService templateService;
// 压缩流
private ZipOutputStream zos;
@Override
public void process() throws Exception {
// 获取 模版
String template = templateService.getTemplateTypeContent(TemplateTypeEnum.MODULE_DATA_INFO);
if (template == null){
return;
}
// 流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
zos = new ZipOutputStream(outputStream);
// 生成
STGroup group = new STGroupString("dbXml",template, '$', '$');
ST moduleTemplate = group.getInstanceOf("moduleTemplate"); // 使用正确的模板名称
// 模块数据生成
List<FunModuleEntity> funModuleEntities = funModuleMapper.selectAll();
// funModuleEntities 按 id 升序排序
funModuleEntities.sort(Comparator.comparing(FunModuleEntity::getId));
moduleTemplate.add("module", funModuleEntities);
writeCodeToZip(moduleTemplate,"module");
ST itemTemplate = group.getInstanceOf("itemTemplate"); // 使用正确的模板名称
// 功能数据生成
List<FunItemEntity> funItemEntities = funItemMapper.selectAll();
funItemEntities.sort(Comparator.comparing(FunItemEntity::getId));
itemTemplate.add("item", funItemEntities);
writeCodeToZip(itemTemplate,"item");
ST operationTemplate = group.getInstanceOf("operationTemplate"); // 使用正确的模板名称
// 操作数据生成
FunModuleDef moduleDef = FunModuleDef.FUN_MODULE_ENTITY;
FunItemDef itemDefDef = FunItemDef.FUN_ITEM_ENTITY;
FunOperationDef operationDef = FunOperationDef.FUN_OPERATION_ENTITY;
QueryWrapper wrapper = QueryWrapper.create();
wrapper.select(operationDef.ALL_COLUMNS,moduleDef.MODULE_NAME,moduleDef.MODULE_CODE,itemDefDef.ITEM_NAME,itemDefDef.ITEM_CODE)
.from(operationDef)
.leftJoin(moduleDef).on(operationDef.MODULE_ID.eq(moduleDef.ID))
.leftJoin(itemDefDef).on(operationDef.ITEM_ID.eq(itemDefDef.ID))
.where(operationDef.ID.isNotNull());
List<FunOperationTemp> funOperationEntities = funOperationMapper.selectListByQueryAs(wrapper,FunOperationTemp.class);
funOperationEntities.sort(Comparator.comparing(FunOperationEntity::getId));
funOperationEntities.forEach(FunOperationTemp::info);
operationTemplate.add("operation", funOperationEntities);
writeCodeToZip(operationTemplate,"operation");
// 确保 ZIP 流结束
zos.finish();
// 返回数据
this.getSlot().setResponseData(outputStream.toByteArray());
}
private void writeCodeToZip(ST st,String fileName) throws IOException {
// 生成代码
String result = st.render();
// insert-ms-fun-operation-data.xml
ZipEntry entry = new ZipEntry("insert-"+ fileName +"-data.xml");
zos.putNextEntry(entry);
zos.write(result.getBytes(StandardCharsets.UTF_8));
zos.closeEntry();
}
}

View File

@@ -0,0 +1,121 @@
package com.cczsa.xinghe.codegen.service.flow.template;
import com.cczsa.xinghe.codegen.entity.FunOperationEntity;
import com.cczsa.xinghe.codegen.entity.enums.ClientTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.mapper.def.FunItemDef;
import com.cczsa.xinghe.codegen.mapper.def.FunOperationDef;
import com.cczsa.xinghe.codegen.service.TemplateService;
import com.mybatisflex.core.query.QueryWrapper;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupString;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 角色 套餐权限相关数据生成
* @author xia
* &#064;date 2026/1/23
* @version 0.0.1
*/
@Slf4j
@RequiredArgsConstructor
@LiteflowComponent(id = "roleDataInfo", name = "角色 套餐权限相关数据生成")
public class RoleDataInfo extends NodeComponent {
private final FunOperationMapper funOperationMapper;
private final TemplateService templateService;
// 压缩流
private ZipOutputStream zos;
@Override
public void process() throws Exception {
// 获取 模版
String template = templateService.getTemplateTypeContent(TemplateTypeEnum.ROLE_DATA_INFO);
if (template == null){
return;
}
// 流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
zos = new ZipOutputStream(outputStream);
// 平台角色
STGroup group = new STGroupString("dbXml",template, '$', '$');
// 功能数据生成
FunOperationDef funOperationDef = FunOperationDef.FUN_OPERATION_ENTITY.as("o");
FunItemDef funItemDef = FunItemDef.FUN_ITEM_ENTITY.as("i");
QueryWrapper wrapper = QueryWrapper.create()
.select(funOperationDef.ALL_COLUMNS)
.from(funItemDef)
.leftJoin(funOperationDef).on(funOperationDef.ITEM_ID.eq(funItemDef.ID))
.where(funItemDef.IS_TENANT.eq(false))
.and(funOperationDef.IS_GREEN_LIGHT.eq(false));
List<FunOperationEntity> funOperationEntities = funOperationMapper.selectListByQuery(wrapper);
funOperationEntities.sort(Comparator.comparing(FunOperationEntity::getId));
// 循环 ClientTypeEnum
for (ClientTypeEnum clientTypeEnum : ClientTypeEnum.values()) {
// 平台角色 功能权限
ST roleBindFunTemplate = group.getInstanceOf("roleBindFunTemplate"); // 使用正确的模板名称
roleBindFunTemplate.add("operations",funOperationEntities);
roleBindFunTemplate.add("clientTypeCode",clientTypeEnum.getCode());
roleBindFunTemplate.add("clientTypeDesc",clientTypeEnum.getDesc());
writeCodeToZip(roleBindFunTemplate,"roleBindFun-"+clientTypeEnum.getDesc());
}
QueryWrapper wrapper2 = QueryWrapper.create()
.select(funOperationDef.ALL_COLUMNS)
.from(funItemDef)
.leftJoin(funOperationDef).on(funOperationDef.ITEM_ID.eq(funItemDef.ID))
.where(funItemDef.IS_TENANT.eq(true))
.and(funOperationDef.IS_GREEN_LIGHT.eq(false));
List<FunOperationEntity> mealsFun = funOperationMapper.selectListByQuery(wrapper2);
mealsFun.sort(Comparator.comparing(FunOperationEntity::getId));
// 功能数据生成
for (ClientTypeEnum clientTypeEnum : ClientTypeEnum.values()) {
// 平台套餐 功能权限
ST mealBindFunTemplate = group.getInstanceOf("mealBindFunTemplate"); // 使用正确的模板名称
mealBindFunTemplate.add("meals",mealsFun);
mealBindFunTemplate.add("clientTypeCode",clientTypeEnum.getCode());
mealBindFunTemplate.add("clientTypeDesc",clientTypeEnum.getDesc());
writeCodeToZip(mealBindFunTemplate,"mealBindFun-"+clientTypeEnum.getDesc());
}
// 确保 ZIP 流结束
zos.finish();
// 返回数据
this.getSlot().setResponseData(outputStream.toByteArray());
}
private void writeCodeToZip(ST st,String fileName) throws IOException {
// 生成代码
String result = st.render();
// insert-ms-fun-operation-data.xml
ZipEntry entry = new ZipEntry("insert-"+ fileName +"-data.xml");
zos.putNextEntry(entry);
zos.write(result.getBytes(StandardCharsets.UTF_8));
zos.closeEntry();
}
}

View File

@@ -0,0 +1,53 @@
package com.cczsa.xinghe.codegen.service.impl;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.domain.template.CodeGen;
import com.cczsa.xinghe.codegen.entity.domain.template.CodeGenType;
import com.cczsa.xinghe.codegen.mapper.FunItemMapper;
import com.cczsa.xinghe.codegen.mapper.FunModuleMapper;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.service.CodeGenService;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author xia
* &#064;date 2026/1/10
* @version 0.0.1
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CodeGenServiceImpl implements CodeGenService {
private final FunModuleMapper funModuleMapper;
private final FunItemMapper funItemMapper;
private final FunOperationMapper funOperationMapper;
@Resource
private FlowExecutor flowExecutor;
@Override
public byte[] generateCodeZip(CodeGen req) {
Long id = null;
if(req.getCodeGenType() == CodeGenType.CONTROLLER){
FunItemEntity funItemEntity = funItemMapper.selectOneById(req.getItemId());
if (funItemEntity == null) {
return null;
}
id = req.getItemId();
}
LiteflowResponse response = flowExecutor.execute2Resp(req.getCodeGenType().getDesc(),null,id);
log.info("执行结果:{}",response);
if (response.isSuccess()) {
return (byte[]) response.getSlot().getResponseData();
}
return null;
}
}

View File

@@ -1,5 +1,6 @@
package com.cczsa.xinghe.codegen.service.impl;
import cn.hutool.core.util.StrUtil;
import com.cczsa.xinghe.codegen.constant.CodegenConstant;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.FunModuleEntity;
@@ -12,10 +13,11 @@ import com.cczsa.xinghe.codegen.mapper.FunItemMapper;
import com.cczsa.xinghe.codegen.mapper.FunModuleMapper;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.mapper.def.FunItemDef;
import com.cczsa.xinghe.codegen.mapper.def.FunModuleDef;
import com.cczsa.xinghe.codegen.service.FunItemService;
import com.cczsa.xinghe.codegen.util.XResult;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@@ -43,13 +45,16 @@ public class FunItemServiceImpl implements FunItemService {
@Override
public XResult<List<FunItemQueryRes>> query(FunItemQueryReq req) {
FunItemDef funItemDef = FunItemDef.FUN_ITEM_ENTITY;
FunModuleDef funModuleDef = FunModuleDef.FUN_MODULE_ENTITY;
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.select(funItemDef.ALL_COLUMNS)
queryWrapper.select(funItemDef.ALL_COLUMNS, funModuleDef.MODULE_NAME)
.from(funItemDef)
.eq(FunItemEntity::getModuleId, req.getModuleId())
.join(funModuleDef).on(funItemDef.MODULE_ID.eq(funModuleDef.ID))
.eq(FunItemEntity::getModuleId, req.getModuleId(), ObjectUtil.areNotNull(req.getModuleId()))
.eq(FunItemEntity::getIsTenant, req.getIsTenant(), ObjectUtil.areNotNull(req.getIsTenant()))
.like(FunItemEntity::getItemName, req.getItemName(), StrUtil.isNotBlank(req.getItemName()))
.like(FunItemEntity::getItemCode, req.getItemCode(), StrUtil.isNotBlank(req.getItemCode()))
.orderBy(FunItemEntity::getSortOrder, true);
.orderBy(FunItemEntity::getSortOrder, false);
List<FunItemQueryRes> funItemQueryRes = funItemMapper.selectListByQueryAs(queryWrapper, FunItemQueryRes.class);
return XResult.ok(funItemQueryRes);
}
@@ -60,6 +65,7 @@ public class FunItemServiceImpl implements FunItemService {
@Transactional
@Override
public XResult<Void> saveUpdate(FunItemSaveUpdateReq req) {
Long id = req.getId();
if (id != null) {
// 删除原数据
@@ -84,6 +90,19 @@ public class FunItemServiceImpl implements FunItemService {
if (funItemMapper.selectCountByQuery(queryItem) > 0) {
return XResult.failed("功能ID已存在");
}
// 同模块中 功能编码要唯一
if (StrUtil.isNotBlank(req.getItemCode())) {
QueryWrapper queryItemCode = new QueryWrapper();
queryItemCode.eq(FunItemEntity::getModuleId, req.getModuleId());
queryItemCode.eq(FunItemEntity::getItemCode, req.getItemCode());
if (req.getId() != null) {
queryItemCode.ne(FunItemEntity::getId, req.getId());
}
if (funItemMapper.selectCountByQuery(queryItemCode) > 0) {
return XResult.failed("同模块中功能编码已存在");
}
}
FunItemEntity funItemEntity = new FunItemEntity();
BeanUtils.copyProperties(req, funItemEntity);
funItemEntity.setId(id);

View File

@@ -1,5 +1,6 @@
package com.cczsa.xinghe.codegen.service.impl;
import cn.hutool.core.util.StrUtil;
import com.cczsa.xinghe.codegen.constant.CodegenConstant;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.FunModuleEntity;
@@ -18,7 +19,6 @@ import com.cczsa.xinghe.codegen.mapper.def.FunModuleDef;
import com.cczsa.xinghe.codegen.mapper.def.FunOperationDef;
import com.cczsa.xinghe.codegen.service.FunModuleService;
import com.cczsa.xinghe.codegen.util.XResult;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
@@ -54,7 +54,7 @@ public class FunModuleServiceImpl implements FunModuleService {
.from(funModuleDef)
.like(FunModuleEntity::getModuleName, req.getModuleName(), StrUtil.isNotBlank(req.getModuleName()))
.like(FunModuleEntity::getModuleCode, req.getModuleCode(), StrUtil.isNotBlank(req.getModuleCode()))
.orderBy(FunModuleEntity::getSortOrder, true);
.orderBy(FunModuleEntity::getSortOrder, false);
List<FunModuleQueryRes> funModuleQueryRes = funModuleMapper.selectListByQueryAs(queryWrapper, FunModuleQueryRes.class);
return XResult.ok(funModuleQueryRes);
}

View File

@@ -1,8 +1,10 @@
package com.cczsa.xinghe.codegen.service.impl;
import cn.hutool.core.util.StrUtil;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.FunModuleEntity;
import com.cczsa.xinghe.codegen.entity.FunOperationEntity;
import com.cczsa.xinghe.codegen.entity.enums.UsableConfigEnum;
import com.cczsa.xinghe.codegen.entity.req.funOperation.FunOperationDeleteReq;
import com.cczsa.xinghe.codegen.entity.req.funOperation.FunOperationQueryReq;
import com.cczsa.xinghe.codegen.entity.req.funOperation.FunOperationSaveUpdateReq;
@@ -10,11 +12,13 @@ import com.cczsa.xinghe.codegen.entity.res.funOperation.FunOperationQueryRes;
import com.cczsa.xinghe.codegen.mapper.FunItemMapper;
import com.cczsa.xinghe.codegen.mapper.FunModuleMapper;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.mapper.def.FunItemDef;
import com.cczsa.xinghe.codegen.mapper.def.FunModuleDef;
import com.cczsa.xinghe.codegen.mapper.def.FunOperationDef;
import com.cczsa.xinghe.codegen.service.FunOperationService;
import com.cczsa.xinghe.codegen.util.XResult;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.CollectionUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@@ -40,15 +44,24 @@ public class FunOperationServiceImpl implements FunOperationService {
* 获取操作列表
*/
@Override
public XResult<List<FunOperationQueryRes>> query(FunOperationQueryReq req) {
public XResult<List<FunOperationQueryRes>> query(FunOperationQueryReq req, Boolean isTenant) {
boolean isTenantNotNull = isTenant != null;
FunOperationDef funOperationDef = FunOperationDef.FUN_OPERATION_ENTITY;
FunModuleDef funModuleDef = FunModuleDef.FUN_MODULE_ENTITY;
FunItemDef funItemDef = FunItemDef.FUN_ITEM_ENTITY;
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.select(funOperationDef.ALL_COLUMNS)
queryWrapper.select(funOperationDef.ALL_COLUMNS, funItemDef.ITEM_NAME, funModuleDef.MODULE_NAME)
.from(funOperationDef)
.eq(FunOperationEntity::getItemId, req.getItemId())
.join(funItemDef).on(funOperationDef.ITEM_ID.eq(funItemDef.ID))
.join(funModuleDef).on(funOperationDef.MODULE_ID.eq(funModuleDef.ID))
.eq(FunOperationEntity::getModuleId, req.getModuleId())
.eq(FunOperationEntity::getItemId, req.getItemId(), req.getItemId() != null)
.like(FunOperationEntity::getOperationCode, req.getOperationCode(), StrUtil.isNotBlank(req.getOperationCode()))
.like(FunOperationEntity::getFunName, req.getFunName(), StrUtil.isNotBlank(req.getFunName()))
.orderBy(FunOperationEntity::getSortOrder, true);
.eq(FunItemEntity::getIsTenant, isTenant, isTenantNotNull)
.eq(FunOperationEntity::getIsGreenLight,false,isTenantNotNull) // 直接放行,不用提供绑定
.orderBy(FunOperationEntity::getId, true)
.orderBy(FunOperationEntity::getSortOrder, false);
List<FunOperationQueryRes> funOperationQueryRes = funOperationMapper.selectListByQueryAs(queryWrapper, FunOperationQueryRes.class);
return XResult.ok(funOperationQueryRes);
}
@@ -59,6 +72,9 @@ public class FunOperationServiceImpl implements FunOperationService {
@Transactional
@Override
public XResult<Void> saveUpdate(FunOperationSaveUpdateReq req) {
if (req.getIsReqParams() && StrUtil.isNotBlank(req.getPathParams())) {
return XResult.failed("请求参数和路径参数冲突");
}
Long id = req.getId();
if (req.getId() != null) {
// 删除原数据
@@ -90,6 +106,29 @@ public class FunOperationServiceImpl implements FunOperationService {
if (funOperationMapper.selectCountByQuery(queryOperation) > 0) {
return XResult.failed("操作ID已存在");
}
// 同模块 同功能中 操作编码不能重复
FunOperationDef operationDef = FunOperationDef.FUN_OPERATION_ENTITY;
FunItemDef itemDef = FunItemDef.FUN_ITEM_ENTITY;
QueryWrapper queryOperationCode = new QueryWrapper();
queryOperationCode.from(operationDef);
queryOperationCode.eq(FunOperationEntity::getModuleId, req.getModuleId());
queryOperationCode.eq(FunOperationEntity::getItemId, req.getItemId());
queryOperationCode.eq(FunOperationEntity::getOperationCode, req.getOperationCode());
if (req.getId() != null) {
queryOperationCode.join(itemDef).on(operationDef.ITEM_ID.eq(itemDef.ID));
queryOperationCode.ne(FunItemEntity::getId, req.getId());
}
if (funOperationMapper.selectCountByQuery(queryOperationCode) > 0) {
return XResult.failed("同模块同功能中操作编码已存在");
}
// usableConfig 排序
List<UsableConfigEnum> usableConfig = req.getUsableConfig();
if (CollectionUtil.isNotEmpty(usableConfig)) {
// 按照枚举的code值升序排序
usableConfig.sort((a, b) -> Integer.compare(a.getCode(), b.getCode()));
req.setUsableConfig(usableConfig);
}
FunOperationEntity funOperationEntity = new FunOperationEntity();
BeanUtils.copyProperties(req, funOperationEntity);
funOperationEntity.setId(id);

View File

@@ -0,0 +1,324 @@
package com.cczsa.xinghe.codegen.service.impl;
import cn.hutool.core.util.StrUtil;
import com.cczsa.xinghe.codegen.entity.FunItemEntity;
import com.cczsa.xinghe.codegen.entity.FunOperationEntity;
import com.cczsa.xinghe.codegen.entity.MenuEntity;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuAddReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuBindFunReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuEditReq;
import com.cczsa.xinghe.codegen.entity.req.menu.MenuQueryReq;
import com.cczsa.xinghe.codegen.entity.res.menu.MenuQueryRes;
import com.cczsa.xinghe.codegen.mapper.FunItemMapper;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.mapper.MenuMapper;
import com.cczsa.xinghe.codegen.mapper.RoleFunMapper;
import com.cczsa.xinghe.codegen.mapper.def.FunOperationDef;
import com.cczsa.xinghe.codegen.mapper.def.MenuDef;
import com.cczsa.xinghe.codegen.mapper.def.RoleFunDef;
import com.cczsa.xinghe.codegen.service.MenuService;
import com.cczsa.xinghe.codegen.util.XResult;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 菜单管理 服务层实现。
*
* @author xia
* @version 0.0.1
*/
@Service
@RequiredArgsConstructor
public class MenuServiceImpl implements MenuService {
private final MenuMapper menuMapper;
private final FunOperationMapper funOperationMapper;
private final FunItemMapper funItemMapper;
private final RoleFunMapper roleFunMapper;
/**
* 获取菜单列表
*/
@Override
public XResult<List<MenuQueryRes>> query(MenuQueryReq req) {
MenuDef menuDef = MenuDef.MENU_ENTITY;
FunOperationDef funOperationDef = FunOperationDef.FUN_OPERATION_ENTITY;
QueryWrapper query = new QueryWrapper();
query.select(
menuDef.ALL_COLUMNS,
funOperationDef.ID.as("funId"),
funOperationDef.FUN_NAME.as("funName")
)
.from(menuDef)
.leftJoin(funOperationDef).on(menuDef.FUN_ID.eq(funOperationDef.ID))
.eq(MenuEntity::getClientType, req.getClientType())
.like(MenuEntity::getMenuName, req.getMenuName(), StrUtil.isNotBlank(req.getMenuName()))
.eq(MenuEntity::getParentId, req.getParentId(), req.getParentId() != null)
.orderBy(MenuEntity::getSortOrder, false);
List<MenuQueryRes> menuEntities = menuMapper.selectListByQueryAs(query, MenuQueryRes.class);
fillExistNumForMenuList(menuEntities);
// 构建树形结构
List<MenuQueryRes> treeList = buildMenuTree(menuEntities);
return XResult.ok(treeList);
}
/**
* 为菜单列表填充功能存在个数信息
*
* @param menuEntities 菜单实体列表
*/
private void fillExistNumForMenuList(List<MenuQueryRes> menuEntities) {
// 统计每个功能ID在整个系统中的出现次数
Map<Long, Integer> funIdCountMap = new HashMap<>();
// 遍历所有菜单统计功能ID出现次数
for (MenuQueryRes menu : menuEntities) {
if (menu.getFunId() != null) {
funIdCountMap.put(menu.getFunId(),
funIdCountMap.getOrDefault(menu.getFunId(), 0) + 1);
}
}
// 更新每个菜单中的 existNum 字段
for (MenuQueryRes menu : menuEntities) {
if (menu.getFunId() != null && funIdCountMap.containsKey(menu.getFunId())) {
menu.setExistNum(funIdCountMap.get(menu.getFunId()));
}
}
}
/**
* 构建树形结构
*/
private List<MenuQueryRes> buildMenuTree(List<MenuQueryRes> menuEntities) {
// 创建一个Map用于快速查找分组
Map<Long, MenuQueryRes> menuMap = new HashMap<>();
for (MenuQueryRes menu : menuEntities) {
menuMap.put(menu.getId(), menu);
}
// 构建树形结构
List<MenuQueryRes> rootMenuList = new ArrayList<>();
for (MenuQueryRes menu : menuEntities) {
Long parentId = menu.getParentId();
if (parentId == 0) {
// 根分组
rootMenuList.add(menu);
} else {
// 如果父节点在结果中,则挂到父节点下
MenuQueryRes parentMenu = menuMap.get(parentId);
if (parentMenu != null) {
if (parentMenu.getChildren() == null) {
parentMenu.setChildren(new ArrayList<>());
}
parentMenu.getChildren().add(menu);
} else {
// 如果父节点不在结果中,则将该节点作为根节点处理
rootMenuList.add(menu);
}
}
}
return rootMenuList;
}
/**
* 创建菜单
*/
@Override
public XResult<Void> add(MenuAddReq req) {
// 获取最大ID
MenuDef menuDef = MenuDef.MENU_ENTITY;
QueryWrapper queryId = new QueryWrapper();
queryId.select(menuDef.ID)
.from(menuDef)
.orderBy(MenuEntity::getId, false);
Long maxId = menuMapper.selectOneByQueryAs(queryId, Long.class);
if (maxId == null) {
maxId = 10000L;
} else {
maxId++;
}
QueryWrapper query = new QueryWrapper();
query.select(menuDef.ID)
.from(menuDef)
.eq(MenuEntity::getParentId, req.getParentId())
.eq(MenuEntity::getClientType, req.getClientType())
.eq(MenuEntity::getMenuName, req.getMenuName());
long count = menuMapper.selectCountByQuery(query);
if (count > 0) {
return XResult.failed("菜单已存在");
}
MenuEntity menuEntity = new MenuEntity();
menuEntity.setId(maxId);
BeanUtils.copyProperties(req, menuEntity);
menuMapper.insertSelective(menuEntity);
return XResult.ok();
}
/**
* 修改菜单
*/
@Override
public XResult<Void> edit(MenuEditReq req) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(MenuEntity::getId, req.getId());
MenuEntity menuEntity = menuMapper.selectOneByQuery(queryWrapper);
if (menuEntity == null) {
return XResult.failed("菜单不存在");
}
MenuDef menuDef = MenuDef.MENU_ENTITY;
QueryWrapper queryCount = new QueryWrapper();
queryCount.select(menuDef.ID)
.from(menuDef)
.eq(MenuEntity::getParentId, req.getParentId())
.eq(MenuEntity::getMenuName, req.getMenuName())
.ne(MenuEntity::getId, req.getId());
long count = menuMapper.selectCountByQuery(queryCount);
if (count > 0) {
return XResult.failed("菜单已存在");
}
BeanUtils.copyProperties(req, menuEntity);
menuMapper.update(menuEntity);
return XResult.ok();
}
/**
* 删除菜单
*/
@Transactional
@Override
public XResult<Void> delete(Long id) {
// 是否有子菜单
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(MenuEntity::getParentId, id);
long count = menuMapper.selectCountByQuery(queryWrapper);
if (count > 0) {
return XResult.failed("请先删除子菜单");
}
// 获取菜单
MenuEntity menuEntity = menuMapper.selectOneById(id);
// 删除配置的角色
if (menuEntity != null && menuEntity.getFunId() != null){
// 删除角色的权限
RoleFunDef roleFunDef = RoleFunDef.ROLE_FUN_ENTITY;
QueryWrapper deleteRoleFun = new QueryWrapper();
deleteRoleFun.from(roleFunDef);
deleteRoleFun.where(roleFunDef.CLIENT_TYPE.eq(menuEntity.getClientType()));
deleteRoleFun.and(roleFunDef.FUN_ID.eq(menuEntity.getFunId()));
roleFunMapper.deleteByQuery(deleteRoleFun);
}
// 删除菜单
menuMapper.deleteById(id);
return XResult.ok();
}
/**
* 菜单绑定权限
*/
@Transactional
@Override
public XResult<Void> bindFun(MenuBindFunReq req) {
// 获取菜单
MenuEntity menuEntity = menuMapper.selectOneById(req.getMenuId());
if (menuEntity == null) {
return XResult.failed("菜单不存在");
}
QueryWrapper queryFun = new QueryWrapper();
queryFun.eq(FunOperationEntity::getId, req.getFunId());
FunOperationEntity funOperationEntity = funOperationMapper.selectOneByQuery(queryFun);
if (funOperationEntity == null) {
return XResult.failed("权限不存在:" + req.getFunId());
}
// 获取功能
QueryWrapper queryItem = new QueryWrapper();
queryItem.eq(FunItemEntity::getId, funOperationEntity.getItemId());
FunItemEntity funItemEntity = funItemMapper.selectOneByQuery(queryItem);
if (funItemEntity == null) {
return XResult.failed("功能不存在:" + req.getFunId());
}
Boolean menuIsTenant = menuEntity.getIsTenant();
Boolean itemIsTenant = funItemEntity.getIsTenant();
if (!menuIsTenant.equals(itemIsTenant)) {
return XResult.failed("菜单和权限是否租户不一致:" + req.getFunId());
}
menuEntity.setFunId(req.getFunId());
menuMapper.update(menuEntity);
// 删除配置的角色操作权限
RoleFunDef roleFunDef = RoleFunDef.ROLE_FUN_ENTITY;
QueryWrapper wrapper = new QueryWrapper();
wrapper.from(roleFunDef);
wrapper.where(roleFunDef.CLIENT_TYPE.eq(menuEntity.getClientType()));
wrapper.and(roleFunDef.FUN_ID.eq(req.getFunId()));
return XResult.ok();
}
/**
* 删除菜单权限
*/
@Transactional
@Override
public XResult<Void> deleteFun(Long menuId) {
// 获取菜单
QueryWrapper queryMenu = new QueryWrapper();
queryMenu.eq(MenuEntity::getId, menuId);
MenuEntity menuEntity = menuMapper.selectOneByQuery(queryMenu);
if (menuEntity == null) {
return XResult.failed("菜单不存在");
}
Long funId = menuEntity.getFunId();
if (funId == null) {
return XResult.failed("菜单未绑定权限");
}
menuEntity.setFunId(null);
menuMapper.update(menuEntity, false);
// 删除配置的 角色绑定操作权限
RoleFunDef roleFunDef = RoleFunDef.ROLE_FUN_ENTITY;
QueryWrapper wrapper = new QueryWrapper();
wrapper.from(roleFunDef);
wrapper.where(roleFunDef.CLIENT_TYPE.eq(menuEntity.getClientType()));
wrapper.and(roleFunDef.FUN_ID.eq(funId));
roleFunMapper.deleteByQuery(wrapper);
return XResult.ok();
}
/**
* 根据ID获取菜单详情
*/
@Override
public XResult<MenuQueryRes> getById(Long id) {
MenuDef menuDef = MenuDef.MENU_ENTITY;
FunOperationDef funOperationDef = FunOperationDef.FUN_OPERATION_ENTITY;
QueryWrapper query = new QueryWrapper();
query.select(
menuDef.ALL_COLUMNS,
funOperationDef.ID.as("funId"),
funOperationDef.FUN_NAME.as("funName")
)
.from(menuDef)
.leftJoin(funOperationDef).on(menuDef.FUN_ID.eq(funOperationDef.ID))
.eq(MenuEntity::getId, id);
MenuQueryRes menuQueryRes = menuMapper.selectOneByQueryAs(query, MenuQueryRes.class);
if (menuQueryRes == null) {
return XResult.failed("菜单不存在");
}
QueryWrapper wrapper = QueryWrapper.create();
wrapper.eq(MenuEntity::getFunId, menuQueryRes.getFunId());
long l = menuMapper.selectCountByQuery(wrapper);
menuQueryRes.setExistNum(Math.toIntExact(l));
return XResult.ok(menuQueryRes);
}
}

View File

@@ -0,0 +1,314 @@
package com.cczsa.xinghe.codegen.service.impl;
import cn.hutool.core.util.StrUtil;
import com.cczsa.xinghe.codegen.entity.FunOperationEntity;
import com.cczsa.xinghe.codegen.entity.MenuEntity;
import com.cczsa.xinghe.codegen.entity.RoleEntity;
import com.cczsa.xinghe.codegen.entity.RoleFunEntity;
import com.cczsa.xinghe.codegen.entity.enums.RoleTypeEnum;
import com.cczsa.xinghe.codegen.entity.enums.UsableConfigEnum;
import com.cczsa.xinghe.codegen.entity.req.role.RoleAddReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleBindFunReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleEditReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleQueryFunReq;
import com.cczsa.xinghe.codegen.entity.req.role.RoleQueryReq;
import com.cczsa.xinghe.codegen.entity.res.role.RoleQueryFunRes;
import com.cczsa.xinghe.codegen.entity.res.role.RoleQueryRes;
import com.cczsa.xinghe.codegen.mapper.FunOperationMapper;
import com.cczsa.xinghe.codegen.mapper.MenuMapper;
import com.cczsa.xinghe.codegen.mapper.RoleFunMapper;
import com.cczsa.xinghe.codegen.mapper.RoleMapper;
import com.cczsa.xinghe.codegen.mapper.def.FunOperationDef;
import com.cczsa.xinghe.codegen.mapper.def.MenuDef;
import com.cczsa.xinghe.codegen.mapper.def.RoleDef;
import com.cczsa.xinghe.codegen.mapper.def.RoleFunDef;
import com.cczsa.xinghe.codegen.service.RoleService;
import com.cczsa.xinghe.codegen.util.XResult;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 角色管理 服务层实现。
*
* @author xia
* @version 0.0.1
*/
@Service
@RequiredArgsConstructor
public class RoleServiceImpl implements RoleService {
private final RoleMapper roleMapper;
private final RoleFunMapper roleFunMapper;
private final FunOperationMapper funOperationMapper;
private final MenuMapper menuMapper;
/**
* 获取角色列表
*/
@Override
public XResult<List<RoleQueryRes>> query(RoleQueryReq req) {
RoleDef roleDef = RoleDef.ROLE_ENTITY;
QueryWrapper query = new QueryWrapper();
query.select(roleDef.ALL_COLUMNS)
.from(roleDef)
.like(RoleEntity::getRoleName, req.getRoleName(), StrUtil.isNotBlank(req.getRoleName()))
.eq(RoleEntity::getRoleType, req.getRoleType(), req.getRoleType() != null);
List<RoleQueryRes> roleQueryRes = roleMapper.selectListByQueryAs(query, RoleQueryRes.class);
return XResult.ok(roleQueryRes);
}
/**
* 创建角色
*/
@Override
public XResult<Void> add(RoleAddReq req) {
// 角色是否存在
QueryWrapper queryRole = new QueryWrapper();
queryRole.eq(RoleEntity::getRoleName, req.getRoleName());
queryRole.eq(RoleEntity::getRoleType, req.getRoleType());
if (roleMapper.selectCountByQuery(queryRole) > 0) {
return XResult.failed("角色已存在");
}
RoleEntity role = new RoleEntity();
role.setId(req.getId());
role.setRoleName(req.getRoleName());
role.setRoleType(req.getRoleType());
roleMapper.insertSelective(role);
return XResult.ok();
}
/**
* 修改角色
*/
@Override
public XResult<Void> edit(RoleEditReq req) {
RoleEntity role = roleMapper.selectOneById(req.getId());
if (role == null) {
return XResult.failed("角色不存在");
}
// 角色是否存在
QueryWrapper queryRole = new QueryWrapper();
queryRole.eq(RoleEntity::getRoleName, req.getRoleName());
queryRole.eq(RoleEntity::getRoleType, req.getRoleType());
queryRole.ne(RoleEntity::getId, req.getId());
if (roleMapper.selectCountByQuery(queryRole) > 0) {
return XResult.failed("角色已存在");
}
BeanUtils.copyProperties(req, role);
roleMapper.update(role);
return XResult.ok();
}
/**
* 删除角色
*/
@Transactional
@Override
public XResult<Void> delete(Long roleId) {
// 删除角色
QueryWrapper deleteRole = new QueryWrapper();
deleteRole.eq(RoleEntity::getId, roleId);
roleMapper.deleteByQuery(deleteRole);
// 删除角色权限
QueryWrapper deleteRoleFun = new QueryWrapper();
deleteRoleFun.eq(RoleFunEntity::getRoleId, roleId);
roleFunMapper.deleteByQuery(deleteRoleFun);
return XResult.ok();
}
/**
* 角色设置权限
*/
@Override
public XResult<Void> bindFun(RoleBindFunReq req) {
// ID = 操作id+ 角色ID + 客户端类型
String id = req.getFunId().toString() + req.getRoleId().toString()+req.getClientType().getCode();
FunOperationEntity funOperationEntity1 = funOperationMapper.selectOneById(Long.parseLong(id));
if (funOperationEntity1 != null) {
return XResult.ok();
}
FunOperationEntity funOperationEntity = funOperationMapper.selectOneById(req.getFunId());
if (funOperationEntity == null) {
return XResult.failed("权限不存在");
}
List<UsableConfigEnum> usableConfig = funOperationEntity.getUsableConfig();
List<String> fieldConfig = funOperationEntity.getFieldConfig();
// 校验assignDataScope中的值是否都在usableConfig中存在
UsableConfigEnum dataScope = req.getDataScope();
if (dataScope != null && dataScope != UsableConfigEnum.NO_PROCESSING) {
if (!usableConfig.contains(dataScope)) {
return XResult.failed("可配置数据类型不存在");
}
}
List<String> excludeField = req.getExcludeField();
// 校验excludeField中的值是否都在fieldConfig中存在
if (excludeField != null && !excludeField.isEmpty()) {
if (fieldConfig == null || fieldConfig.isEmpty()) {
return XResult.failed("可配置字段不存在");
}
for (String field : excludeField) {
if (!fieldConfig.contains(field)) {
return XResult.failed("可配置字段不存在:" + field);
}
}
}
// 新增权限
RoleFunEntity roleFunEntity = new RoleFunEntity();
if (dataScope == UsableConfigEnum.SPECIFIED_DEPARTMENT) {
if (req.getDeptDataScope() == null || req.getDeptDataScope().isEmpty()) {
return XResult.failed("请选择指定的部门");
}
roleFunEntity.setAssignDataScope(req.getDeptDataScope());
// 用户
} else if (dataScope == UsableConfigEnum.SPECIFIED_USER) {
if (req.getUserDataScope() == null || req.getUserDataScope().isEmpty()) {
return XResult.failed("请选择指定的用户");
}
roleFunEntity.setAssignDataScope(req.getUserDataScope());
} else {
roleFunEntity.setAssignDataScope(new ArrayList<>());
}
roleFunEntity.setRoleId(req.getRoleId());
roleFunEntity.setFunId(req.getFunId());
roleFunEntity.setDataScope(req.getDataScope());
roleFunEntity.setExcludeField(req.getExcludeField());
roleFunEntity.setClientType(req.getClientType());
// 删除旧权限
QueryWrapper deleteRoleFun = new QueryWrapper();
deleteRoleFun.eq(RoleFunEntity::getClientType, req.getClientType());
deleteRoleFun.eq(RoleFunEntity::getRoleId, req.getRoleId());
deleteRoleFun.eq(RoleFunEntity::getFunId, req.getFunId());
roleFunMapper.deleteByQuery(deleteRoleFun);
roleFunEntity.setId(Long.parseLong(id));
// 新增权限
roleFunMapper.insertSelective(roleFunEntity);
return XResult.ok();
}
/**
* 删除角色权限
*/
@Override
public XResult<Void> deleteFun(Long roleBindFunId) {
QueryWrapper deleteRoleFun = new QueryWrapper();
deleteRoleFun.eq(RoleFunEntity::getId, roleBindFunId);
roleFunMapper.deleteByQuery(deleteRoleFun);
return XResult.ok();
}
/**
* 获取角色功能权限配置
*/
@Override
public XResult<List<RoleQueryFunRes>> queryRoleFun(RoleQueryFunReq req) {
// 获取角色
RoleEntity roleEntity = roleMapper.selectOneById(req.getRoleId());
if (roleEntity == null) {
return XResult.failed("角色不存在");
}
RoleTypeEnum roleType = roleEntity.getRoleType();
boolean isTenant = roleType == RoleTypeEnum.PACKAGE;
// 获取菜单
MenuDef menuDef = MenuDef.MENU_ENTITY;
FunOperationDef funOperationDef = FunOperationDef.FUN_OPERATION_ENTITY;
QueryWrapper queryMenu = new QueryWrapper();
queryMenu.select
(
menuDef.ALL_COLUMNS,
funOperationDef.ID.as("funId"),
funOperationDef.FUN_NAME,
funOperationDef.USABLE_CONFIG,
funOperationDef.FIELD_CONFIG,
funOperationDef.DESCRIBE
)
.from(menuDef)
.leftJoin(funOperationDef).on(menuDef.FUN_ID.eq(funOperationDef.ID))
.eq(MenuEntity::getClientType, req.getClientType())
.eq(MenuEntity::getIsTenant, isTenant)
.orderBy(MenuEntity::getSortOrder, false);
List<RoleQueryFunRes> roleQueryFunList = menuMapper.selectListByQueryAs(queryMenu, RoleQueryFunRes.class);
// 获取角色功能权限
RoleFunDef roleFunDef = RoleFunDef.ROLE_FUN_ENTITY;
QueryWrapper queryRoleFun = new QueryWrapper();
queryRoleFun.select(roleFunDef.ALL_COLUMNS)
.from(roleFunDef)
.eq(RoleFunEntity::getClientType,req.getClientType())
.eq(RoleFunEntity::getRoleId, req.getRoleId());
List<RoleFunEntity> roleFunEntities = roleFunMapper.selectListByQuery(queryRoleFun);
for (RoleQueryFunRes roleQueryFunRes : roleQueryFunList) {
if(isTenant){
roleQueryFunRes.setUsableConfig(new ArrayList<>());
roleQueryFunRes.setFieldConfig(new ArrayList<>());
}
// 获取菜单功能
RoleFunEntity roleFunEntity = roleFunEntities.stream()
.filter(entity -> entity.getFunId().equals(roleQueryFunRes.getFunId()))
.findFirst()
.orElse(null);
if (roleFunEntity != null) {
// 设置角色权限配置
roleQueryFunRes.setDataScope(roleFunEntity.getDataScope());
roleQueryFunRes.setExcludeField(roleFunEntity.getExcludeField());
roleQueryFunRes.setAssignDataScope(roleFunEntity.getAssignDataScope());
roleQueryFunRes.setIsSelect(true);
roleQueryFunRes.setFunBindId(roleFunEntity.getId());
roleQueryFunRes.setFunClientType(roleFunEntity.getClientType());
} else {
// 如果角色没有此功能的权限,设置默认值
roleQueryFunRes.setDataScope(null);
roleQueryFunRes.setExcludeField(new ArrayList<>());
roleQueryFunRes.setAssignDataScope(new ArrayList<>());
}
}
// 构建树形结构
List<RoleQueryFunRes> treeList = buildMenuTree(roleQueryFunList);
return XResult.ok(treeList);
}
/**
* 构建树形结构
*/
private List<RoleQueryFunRes> buildMenuTree(List<RoleQueryFunRes> roleQueryFunList) {
// 创建一个Map用于快速查找分组
Map<Long, RoleQueryFunRes> menuMap = new HashMap<>();
for (RoleQueryFunRes menu : roleQueryFunList) {
menuMap.put(menu.getId(), menu);
}
// 构建树形结构
List<RoleQueryFunRes> rootMenuList = new ArrayList<>();
for (RoleQueryFunRes menu : roleQueryFunList) {
Long parentId = menu.getParentId();
if (parentId == 0) {
// 根分组
rootMenuList.add(menu);
} else {
// 如果父节点在结果中,则挂到父节点下
RoleQueryFunRes parentMenu = menuMap.get(parentId);
if (parentMenu != null) {
if (parentMenu.getChildren() == null) {
parentMenu.setChildren(new ArrayList<>());
}
parentMenu.getChildren().add(menu);
} else {
// 如果父节点不在结果中,则将该节点作为根节点处理
rootMenuList.add(menu);
}
}
}
return rootMenuList;
}
}

View File

@@ -0,0 +1,158 @@
package com.cczsa.xinghe.codegen.service.impl;
import cn.hutool.core.util.StrUtil;
import com.cczsa.xinghe.codegen.entity.TemplateEntity;
import com.cczsa.xinghe.codegen.entity.enums.TemplateTypeEnum;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateAddReq;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateEditReq;
import com.cczsa.xinghe.codegen.entity.req.template.TemplateQueryReq;
import com.cczsa.xinghe.codegen.entity.res.template.TemplateQueryRes;
import com.cczsa.xinghe.codegen.mapper.TemplateMapper;
import com.cczsa.xinghe.codegen.mapper.def.TemplateDef;
import com.cczsa.xinghe.codegen.service.TemplateService;
import com.cczsa.xinghe.codegen.util.XResult;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* 模板管理 服务层实现。
*
* @author xia
* @version 0.0.1
*/
@Service
@RequiredArgsConstructor
public class TemplateServiceImpl implements TemplateService {
private final TemplateMapper templateMapper;
/**
* 获取模板列表
*/
@Override
public XResult<List<TemplateQueryRes>> query(TemplateQueryReq req) {
TemplateDef templateDef = TemplateDef.TEMPLATE_ENTITY;
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.select(templateDef.ALL_COLUMNS)
.from(templateDef)
.like(TemplateEntity::getTemplateName, req.getTemplateName(), StrUtil.isNotBlank(req.getTemplateName()))
.eq(TemplateEntity::getTemplateType, req.getTemplateType(), req.getTemplateType() != null)
.eq(TemplateEntity::getIsUse, req.getIsUse(), req.getIsUse() != null);
List<TemplateQueryRes> templateQueryRes = templateMapper.selectListByQueryAs(queryWrapper, TemplateQueryRes.class);
return XResult.ok(templateQueryRes);
}
/**
* 创建模板
*/
@Override
public XResult<Void> add(TemplateAddReq req) {
// 模板名称是否存在
QueryWrapper queryName = new QueryWrapper();
queryName.eq(TemplateEntity::getTemplateName, req.getTemplateName());
long count = templateMapper.selectCountByQuery(queryName);
if (count > 0) {
return XResult.failed("模板名称已存在");
}
TemplateEntity templateEntity = new TemplateEntity();
BeanUtils.copyProperties(req, templateEntity);
templateMapper.insert(templateEntity);
// 其它的设置为未使用
if(req.getIsUse()){
setCurrentTemplate(templateEntity.getId());
}
return XResult.ok();
}
/**
* 设置模板为当前使用
* 同一类型下只能有一个模板被标记为使用中
* @param templateId 模板ID
*/
public void setCurrentTemplate(Long templateId) {
// 获取模板
TemplateEntity templateEntity = templateMapper.selectOneById(templateId);
if (templateEntity == null) {
return;
}
// 获取模板类型
TemplateTypeEnum templateType = templateEntity.getTemplateType();
// 查询同一类型下的所有模板
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(TemplateEntity::getTemplateType, templateType);
// 将同一类型下除当前模板外的所有模板设置为未使用
TemplateEntity entity = new TemplateEntity();
entity.setIsUse(false);
templateMapper.updateByQuery(entity,true,queryWrapper);
// 将当前模板设置为使用中
templateEntity.setIsUse(true);
templateMapper.update(templateEntity);
}
/**
* 修改模板
*/
@Override
public XResult<Void> edit(TemplateEditReq req) {
// 获取模板
TemplateEntity templateEntity = templateMapper.selectOneById(req.getId());
if (templateEntity == null) {
return XResult.failed("模板不存在");
}
// 模板名称是否存在
QueryWrapper queryName = new QueryWrapper();
queryName.eq(TemplateEntity::getTemplateName, req.getTemplateName());
queryName.ne(TemplateEntity::getId, req.getId());
long count = templateMapper.selectCountByQuery(queryName);
if (count > 0) {
return XResult.failed("模板名称已存在");
}
BeanUtils.copyProperties(req, templateEntity);
templateMapper.update(templateEntity);
// 其它的设置为未使用
if(req.getIsUse()){
setCurrentTemplate(templateEntity.getId());
}
return XResult.ok();
}
/**
* 删除模板
*/
@Override
public XResult<Void> delete(Long id) {
templateMapper.deleteById(id);
return XResult.ok();
}
/**
* 获取模板类型列表
*/
@Override
public XResult<List<Map<Integer, String>>> getTemplateTypeList() {
return XResult.ok(TemplateTypeEnum.getEnumList());
}
@Override
public String getTemplateTypeContent(TemplateTypeEnum templateType) {
TemplateDef def = TemplateDef.TEMPLATE_ENTITY;
QueryWrapper query = new QueryWrapper();
query.select(def.CONTENT)
.from(def)
.where(def.TEMPLATE_TYPE.eq(templateType))
.and(def.IS_USE.eq(true));
return templateMapper.selectOneByQueryAs(query, String.class);
}
}

View File

@@ -0,0 +1,105 @@
package com.cczsa.xinghe.codegen.util;
/**
* 字符串工具类
*
* @author xia
* @date 2026/1/19
* @version 0.0.1
*/
public class StringUtils {
/**
* 将字符串首字母大写
* @param str 输入字符串
* @return 首字母大写的字符串
*/
public static String capitalizeFirstLetter(String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
/**
* 将字符串转为路径
* 例子: user-add -> /user/add
* @param str 输入字符串
* @return 转换后的路径字符串
*/
public static String toPath(String str) {
if (str == null || str.isEmpty()) {
return str;
}
// 将连字符替换为斜杠,并在开头添加斜杠
return "/" + str.replace("-", "/");
}
/**
* 将连字符分隔的字符串转为驼峰命名
* 例子test-user -> testUser
* @param str 输入字符串
* @return 驼峰命名字符串
*/
public static String toCamelCase(String str) {
if (str == null || str.isEmpty()) {
return str;
}
StringBuilder result = new StringBuilder();
String[] parts = str.split("-");
for (int i = 0; i < parts.length; i++) {
if (i == 0) {
// 第一部分保持原样(小写)
result.append(parts[i]);
} else {
// 后续部分首字母大写
if (!parts[i].isEmpty()) {
result.append(parts[i].substring(0, 1).toUpperCase())
.append(parts[i].substring(1));
}
}
}
return result.toString();
}
/**
* 将连字符分隔的字符串转为大驼峰命名PascalCase
* 例子test-user -> TestUser
* @param str 输入字符串
* @return 大驼峰命名字符串
*/
public static String toPascalCase(String str) {
if (str == null || str.isEmpty()) {
return str;
}
StringBuilder result = new StringBuilder();
String[] parts = str.split("-");
for (String part : parts) {
if (!part.isEmpty()) {
result.append(part.substring(0, 1).toUpperCase())
.append(part.substring(1));
}
}
return result.toString();
}
/**
* 判断字符串是否为空
* 包括 null、空字符串 ""、"null"(不区分大小写)
* @param str 输入字符串
* @return 如果为空返回 true否则返回 false
*/
public static boolean isEmpty(String str) {
return str == null || str.isEmpty() || str.trim().equalsIgnoreCase("null");
}
/**
* 判断字符串是否不为空
* @param str 输入字符串
* @return 如果不为空返回 true否则返回 false
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
}

View File

@@ -0,0 +1,22 @@
server:
port: 7011
spring:
datasource:
url: jdbc:postgresql://192.168.1.26:5432/xinghe-codegen
username: postgres
password: root
driver-class-name: org.postgresql.Driver
type: com.zaxxer.hikari.HikariDataSource # 使用 HikariCP 作为连接池
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 60000
idle-timeout: 300000
max-lifetime: 1200000
validation-timeout: 5000
leak-detection-threshold: 60000
liteflow:
rule-source: liteflow/*.el.xml
enable: true

View File

@@ -1,18 +1,4 @@
server:
port: 7011
spring:
datasource:
url: jdbc:postgresql://192.168.1.26:5432/xinghe-codegen
username: postgres
password: root
driver-class-name: org.postgresql.Driver
type: com.zaxxer.hikari.HikariDataSource # 使用 HikariCP 作为连接池
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 60000
idle-timeout: 300000
max-lifetime: 1200000
validation-timeout: 5000
leak-detection-threshold: 60000
# 使用不同模块的数据库配置
profiles:
active: pro

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<!-- 主流程controller 代码生成 -->
<chain name="controller">
THEN(controllerCodeCreate);
</chain>
<!-- 主流程:数据初始化 -->
<chain name="module_data_info">
THEN(moduleDataInfo);
</chain>
<!-- 主流程:角色 套餐权限 -->
<chain name="role_permission">
THEN(roleDataInfo);
</chain>
<!-- 主流程:角色 套餐权限 -->
<chain name="menu_data_info">
THEN(menuDataInfo);
</chain>
</flow>

View File

@@ -0,0 +1,45 @@
/** 白屏阶段会执行的 CSS 加载动画 */
#app-loading {
position: relative;
top: 45vh;
margin: 0 auto;
color: #409eff;
font-size: 12px;
}
#app-loading,
#app-loading::before,
#app-loading::after {
width: 2em;
height: 2em;
border-radius: 50%;
animation: 2s ease-in-out infinite app-loading-animation;
}
#app-loading::before,
#app-loading::after {
content: "";
position: absolute;
}
#app-loading::before {
left: -4em;
animation-delay: -0.2s;
}
#app-loading::after {
left: 4em;
animation-delay: 0.2s;
}
@keyframes app-loading-animation {
0%,
80%,
100% {
box-shadow: 0 2em 0 -2em;
}
40% {
box-shadow: 0 2em 0 0;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/app-loading.css" />
<title>功能管理</title>
<script type="module" crossorigin src="/static/index-e2eede5f.js"></script>
<link rel="modulepreload" crossorigin href="/static/vue-5ea6dbbd.js">
<link rel="modulepreload" crossorigin href="/static/element-9324df56.js">
<link rel="modulepreload" crossorigin href="/static/vxe-5e0bd050.js">
<link rel="stylesheet" href="/static/index-213f7bee.css">
</head>
<body>
<div id="app">
<div id="app-loading"></div>
</div>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.error-page[data-v-2fba9562]{height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center}.error-page-svg[data-v-2fba9562]{width:400px;margin-bottom:50px}

View File

@@ -0,0 +1 @@
import{_}from"./index-e2eede5f.js";import{ag as e,l as n,m as c,p as d,H as l,U as t,O as o,S as p}from"./vue-5ea6dbbd.js";const u={},i={class:"error-page"},f={class:"error-page-svg"};function m(r,g){const a=e("el-button"),s=e("router-link");return n(),c("div",i,[d("div",f,[l(r.$slots,"default",{},void 0,!0)]),t(s,{to:"/"},{default:o(()=>[t(a,{type:"primary"},{default:o(()=>[p("回到首页")]),_:1})]),_:1})])}const x=_(u,[["render",m],["__scopeId","data-v-2fba9562"]]);export{x as E};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.search-wrapper[data-v-9ca48dd1]{margin-bottom:20px}.search-wrapper[data-v-9ca48dd1] .el-card__body{padding-bottom:2px}.toolbar-wrapper[data-v-9ca48dd1]{display:flex;justify-content:space-between;margin-bottom:20px}.table-wrapper[data-v-9ca48dd1]{margin-bottom:20px}

View File

@@ -0,0 +1 @@
.app-container[data-v-3401b7f6]{padding:20px}.role-info[data-v-3401b7f6]{margin-bottom:20px;display:flex;justify-content:space-between;align-items:center}.role-info h2[data-v-3401b7f6]{margin:0}.permission-wrapper[data-v-3401b7f6]{display:flex;gap:20px;margin-bottom:30px}.menu-tree[data-v-3401b7f6]{width:30%;border-right:1px solid #ebeef5;padding-right:20px}.menu-tree h3[data-v-3401b7f6]{margin:0 0 15px;font-size:16px;font-weight:600}.menu-tree .tree-node[data-v-3401b7f6]{display:flex;align-items:center;gap:5px}.menu-tree .tree-node.is-active[data-v-3401b7f6]{color:#67c23a;font-weight:600}.menu-tree .tree-node .node-icon[data-v-3401b7f6]{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;font-size:16px;color:#909399}.menu-tree .tree-node .el-icon[data-v-3401b7f6]{color:#67c23a}.menu-tree .tree-node .node-badge[data-v-3401b7f6]{margin-left:4px}.menu-tree .tree-node .node-badge[data-v-3401b7f6] .el-badge__content{transform:translateY(-50%) translate(0);right:-10px}.permission-config[data-v-3401b7f6]{width:70%}.permission-config h3[data-v-3401b7f6]{margin:0 0 15px;font-size:16px;font-weight:600}.fun-permission[data-v-3401b7f6]{margin-bottom:30px}.fun-permission .menu-title[data-v-3401b7f6]{margin-bottom:15px;font-weight:600;color:#409eff}.fun-permission .menu-title .menu-title-header[data-v-3401b7f6]{display:flex;align-items:center;gap:8px;margin-bottom:10px}.fun-permission .menu-title .menu-info-tags[data-v-3401b7f6]{display:flex;flex-wrap:wrap;gap:8px}.fun-permission .fun-item[data-v-3401b7f6]{padding:15px;background-color:#f5f7fa;border-radius:4px;display:flex;flex-direction:column;align-items:flex-start;gap:10px}.fun-permission .switch-with-text[data-v-3401b7f6]{display:flex;align-items:center;gap:8px}.fun-permission .switch-label[data-v-3401b7f6]{font-size:14px;color:#606266}.fun-permission .empty-tip[data-v-3401b7f6]{text-align:center;padding:30px;color:#909399;background-color:#f5f7fa;border-radius:4px}.data-permission[data-v-3401b7f6]{background-color:#f5f7fa;padding:15px;border-radius:4px}.data-permission .el-form-item[data-v-3401b7f6]{margin-bottom:20px}.operation-buttons[data-v-3401b7f6]{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
import{h as O}from"./index-bfe0dfe9.js";import{B as P,E as g,C as A}from"./element-9324df56.js";import{G as _,r as b,e as m,d as i,b as h,l as v,M as I,O as y,m as C,a7 as S,F as D,u as T}from"./vue-5ea6dbbd.js";const U=_({__name:"index",props:{idType:{},moduleId:{},itemId:{},modelValue:{},placeholder:{default:"请选择ID"},disabled:{type:Boolean,default:!1},clearable:{type:Boolean,default:!0},originalId:{}},emits:["update:modelValue","change","clear"],setup(a,{emit:t}){const e=a,n=b(!1),o=b([]),E=m(()=>{let l=[...o.value];return e.originalId!==void 0&&!l.includes(e.originalId)&&(l=[e.originalId,...l].sort((u,d)=>u-d)),l.map(u=>({label:u.toString(),value:u}))}),c=m({get:()=>e.modelValue,set:l=>t("update:modelValue",l)}),s=()=>e.idType===0?!0:e.idType===1?e.moduleId===void 0||e.moduleId===null||e.moduleId===0?(console.warn("获取功能ID列表失败: moduleId 为必传参数"),!1):!0:e.idType===2?e.moduleId===void 0||e.moduleId===null||e.moduleId===0?(console.warn("获取操作ID列表失败: moduleId 为必传参数"),!1):e.itemId===void 0||e.itemId===null||e.itemId===0?(console.warn("获取操作ID列表失败: itemId 为必传参数"),!1):!0:(console.warn(`未知的 idType: ${e.idType}`),!1),r=async()=>{if(!s()){o.value=[];return}try{n.value=!0;const l=await O({idType:e.idType,moduleId:e.moduleId,itemId:e.itemId});o.value=l.data||[]}catch(l){console.error("获取ID列表失败:",l),g.error("获取ID列表失败"),o.value=[]}finally{n.value=!1}};i(()=>e.idType,()=>{r()}),i(()=>e.moduleId,()=>{(e.idType===1||e.idType===2)&&(s()?r():o.value=[])}),i(()=>e.itemId,()=>{e.idType===2&&(s()?r():o.value=[])});const f=l=>{t("change",l)},p=()=>{t("clear")};return h(()=>{r()}),(l,u)=>(v(),I(T(P),{modelValue:c.value,"onUpdate:modelValue":u[0]||(u[0]=d=>c.value=d),placeholder:l.placeholder,disabled:l.disabled,clearable:l.clearable,loading:n.value,onChange:f,onClear:p},{default:y(()=>[(v(!0),C(D,null,S(E.value,d=>(v(),I(T(A),{key:d.value,label:d.label,value:d.value},null,8,["label","value"]))),128))]),_:1},8,["modelValue","placeholder","disabled","clearable","loading"]))}});var N=(a=>(a[a.MODULE=0]="MODULE",a[a.ITEM=1]="ITEM",a[a.OPERATION=2]="OPERATION",a))(N||{});const B=[{label:"新增",value:0},{label:"删除",value:1},{label:"修改",value:2},{label:"查询",value:3},{label:"上传",value:4},{label:"下载",value:5},{label:"导入",value:6},{label:"导出",value:7},{label:"打印",value:8},{label:"注册",value:9},{label:"登录",value:10},{label:"登出",value:11},{label:"短信",value:12},{label:"邮件",value:13},{label:"微信",value:14},{label:"其它",value:99}],V={0:"新增",1:"删除",2:"修改",3:"查询",4:"上传",5:"下载",6:"导入",7:"导出",8:"打印",9:"注册",10:"登录",11:"登出",12:"短信",13:"邮件",14:"微信",99:"其它"},w=[{label:"GET",value:0},{label:"HEAD",value:1},{label:"POST",value:2},{label:"PUT",value:3},{label:"PATCH",value:4},{label:"DELETE",value:5},{label:"OPTIONS",value:6},{label:"TRACE",value:7}],G={0:"GET",1:"HEAD",2:"POST",3:"PUT",4:"PATCH",5:"DELETE",6:"OPTIONS",7:"TRACE"},k=[{label:"所有",value:1},{label:"本人",value:2},{label:"本部门",value:3},{label:"本部门及子部门",value:4},{label:"指定部门",value:5},{label:"指定人员",value:6}],F={1:"所有",2:"本人",3:"本部门",4:"本部门及子部门",5:"指定部门",6:"指定人员"};export{N as I,V as O,G as R,k as U,U as _,B as a,w as b,F as c};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.search-wrapper[data-v-25594890]{margin-bottom:20px}.search-wrapper[data-v-25594890] .el-card__body{padding-bottom:2px}.toolbar-wrapper[data-v-25594890]{display:flex;justify-content:space-between;margin-bottom:20px}.table-wrapper[data-v-25594890]{margin-bottom:20px}

Some files were not shown because too many files have changed in this diff Show More