Compare commits

..

12 Commits

Author SHA1 Message Date
5c15453c97 chore(config): 将配置文件中的敏感信息替换为环境变量占位符
- 将 application.yml 中的邮件密码、token密钥、阿里云OSS等敏感配置替换为环境变量
- 将 application-dev.yml 中的数据库连接、Redis、MQTT等配置替换为环境变量占位符
- 将 application-prod.yml 中的数据库连接、Redis、MQTT、阿里云等配置替换为环境变量
- 为代码生成器添加环境变量支持和 .env 文件加载功能
- 更新 .gitignore 文件以忽略 .env 相关配置文件
- 修改 README.md 文档说明环境变量配置方式
- 修复联系邮箱地址错误
2026-01-08 18:34:45 +08:00
f1ba2cbecc chore(config): 将配置文件中的敏感信息替换为环境变量占位符
- 将 application.yml 中的邮件密码、token密钥、阿里云OSS等敏感配置替换为环境变量
- 将 application-dev.yml 中的数据库连接、Redis、MQTT等配置替换为环境变量占位符
- 将 application-prod.yml 中的数据库连接、Redis、MQTT、阿里云等配置替换为环境变量
- 为代码生成器添加环境变量支持和 .env 文件加载功能
- 更新 .gitignore 文件以忽略 .env 相关配置文件
- 修改 README.md 文档说明环境变量配置方式
- 修复联系邮箱地址错误
2026-01-08 18:13:07 +08:00
2814a4e655 refactor(clinic): 移除诊所模块的控制器和实体类
- 移除 ClinicAppointmentController 挂号控制器
- 移除 ClinicDoctorApplyController 医生入驻申请控制器
- 移除 ClinicDoctorUserController 分销商用户记录表控制器
- 移除 ClinicPatientUserController 患者控制器
- 移除 ClinicPrescriptionController 处方主表控制器
- 移除 ClinicPrescriptionItemController 处方明细表控制器
- 移除 ClinicAppointment 挂号实体类
- 移除 ClinicDoctorApply 医生入驻申请实体类
- 移除 ClinicDoctorUser 分销商用户记录表实体类
- 移除 ClinicPatientUser 患者实体类
2026-01-08 13:56:23 +08:00
8aa814a2a4 feat(clinic): 添加处方主表和明细表功能模块- 新增处方主表和明细表的实体类定义
- 实现处方主表和明细表的CRUD控制器- 创建处方主表和明细表的Mapper接口及XML映射文件
- 添加处方主表和明细表的Service接口及实现类
- 完成处方主表和明细表的查询参数封装
-修正前端页面中row-key及删除方法的字段引用问题- 更新代码生成器模板以适配新的主键字段命名规则
2025-10-22 02:03:35 +08:00
7bf80cb179 feat(admin): 移除管理员界面的旧版 SVG 图标- 删除了位于 /dict/admin/public/assets/ 目录下的 logo.svg 文件- 清理了项目中不再使用的图标资源
- 减少了前端静态资源体积
-为后续引入新版图标系统做准备
- 更新了相关引用路径(如有)- 确保移除后功能正常运行且无报错
2025-10-19 09:31:25 +08:00
ba6896855a feat(admin): 添加管理后台logo文件- 新增128x128尺寸的SVG格式logo文件
- 使用Method Draw工具创建矢量图形
- 包含背景层和图层1的基础结构
- 支持透明背景显示
- 为管理后台界面提供品牌标识- 便于后续UI组件中引用和展示
2025-10-18 09:16:51 +08:00
4c7a7e2452 refactor(entity):优化实体类模板注解生成逻辑
- 移除了时间类型字段的冗余声明注解
- 合并了条件判断逻辑,减少嵌套层级- 调整了注释与注解的排列顺序
- 统一处理字段注解生成流程
- 简化了主键和填充字段的注解条件判断
-优化了代码格式,提高可读性
2025-10-16 20:42:29 +08:00
c61fe0c3bf feat(generator):为不同时间类型字段添加特定日期格式化注解
- 为 LocalDateTime 类型字段添加 "yyyy-MM-dd HH:mm:ss" 格式
-为 LocalDate 类型字段添加 "yyyy-MM-dd" 格式- 为 LocalTime 类型字段添加 "HH:mm:ss" 格式
- 为 Date 类型字段保留原有 "yyyy-MM-dd HH:mm:ss" 格式- 优化时间字段格式化逻辑,提高代码可读性
2025-10-16 20:39:08 +08:00
c2df93faeb feat(generator):为不同时间类型字段添加特定日期格式化注解
- 为 LocalDateTime 类型字段添加 "yyyy-MM-dd HH:mm:ss" 格式
-为 LocalDate 类型字段添加 "yyyy-MM-dd" 格式- 为 LocalTime 类型字段添加 "HH:mm:ss" 格式
- 为 Date 类型字段保留原有 "yyyy-MM-dd HH:mm:ss" 格式- 优化时间字段格式化逻辑,提高代码可读性
2025-10-16 20:34:41 +08:00
e65003ddb3 feat(generator):为时间类型字段添加日期格式化注解
- 在实体类模板中为LocalDateTime、LocalDate、LocalTime和Date类型字段添加@JsonFormat注解
- 设置默认日期格式为"yyyy-MM-dd HH:mm:ss"- 确保生成的实体类能正确序列化和反序列化时间字段
2025-10-16 20:34:06 +08:00
d92b81ab55 feat(web): 新增 BaseController 基类并优化代码生成模板
- 添加 BaseController 基类,包含常用方法如获取登录用户、租户ID等
- 实现统一的 ApiResult 返回结果处理方法
- 添加请求参数空字符串转 null 的处理逻辑- 新增方法参数类型转换异常的统一处理机制
- 更新代码生成器模板,将 ID 类型从 Integer 改为 Long
- 修改代码生成器配置,使用新的 BaseController 替代 SimpleBaseController
- 优化 HTTP 请求头获取逻辑,支持大小写兼容的 AppId 获取方式
2025-10-16 20:29:43 +08:00
ed6bb2772f feat(web): 新增 BaseController 基类并优化代码生成模板
- 添加 BaseController 基类,包含常用方法如获取登录用户、租户ID等
- 实现统一的 ApiResult 返回结果处理方法
- 添加请求参数空字符串转 null 的处理逻辑- 新增方法参数类型转换异常的统一处理机制
- 更新代码生成器模板,将 ID 类型从 Integer 改为 Long
- 修改代码生成器配置,使用新的 BaseController 替代 SimpleBaseController
- 优化 HTTP 请求头获取逻辑,支持大小写兼容的 AppId 获取方式
2025-10-16 20:29:33 +08:00
11 changed files with 904 additions and 223 deletions

8
.gitignore vendored
View File

@@ -31,6 +31,14 @@ build/
.vscode/
/cert/
/src/main/resources/dev/
.env
.env.*
/src/main/resources/application-local.yml
/src/main/resources/application-*-local.yml
/src/main/resources/application-secrets.yml
/src/main/resources/application-*.secrets.yml
/config/application-local.yml
/config/application-*-local.yml
### macOS ###
.DS_Store

110
README.md
View File

@@ -87,17 +87,28 @@ CREATE DATABASE websoft_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
### 3. 配置文件
编辑 `src/main/resources/application-dev.yml` 文件,配置数据库连接:
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/websoft_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
username: your_username
password: your_password
redis:
host: localhost
port: 6379
password: your_redis_password
本项目的 `application-*.yml` 已使用环境变量占位符,避免将真实密码提交到 Git。
推荐使用 `.env` 管理本地开发环境变量:
- 复制模板:`cp .env.example .env`
-`.env` 中填好值后启动前加载zsh/bash
- `set -a; source .env; set +a`
开发环境可通过环境变量配置数据库/Redis 连接(示例):
```bash
export SPRING_DATASOURCE_URL='jdbc:mysql://localhost:3306/websoft_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8'
export SPRING_DATASOURCE_USERNAME='your_username'
export SPRING_DATASOURCE_PASSWORD='your_password'
export SPRING_REDIS_HOST='localhost'
export SPRING_REDIS_PORT='6379'
export SPRING_REDIS_PASSWORD='your_redis_password'
```
代码生成器(`src/test/java/com/gxwebsoft/generator/*Generator.java`)使用(支持从项目根目录自动读取 `.env`;也可直接导出环境变量):
```bash
export CODEGEN_DB_URL='jdbc:mysql://localhost:3306/websoft_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8'
export CODEGEN_DB_USERNAME='your_username'
export CODEGEN_DB_PASSWORD='your_password'
```
### 4. 启动项目
@@ -118,40 +129,36 @@ mvn spring-boot:run
## ⚙️ 配置说明
### 数据库配置
`application-dev.yml` 中配置数据库连接
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/websoft_db
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
```
`application-dev.yml` / `application-prod.yml` 里使用占位符读取以下环境变量
- `SPRING_DATASOURCE_URL`
- `SPRING_DATASOURCE_USERNAME`
- `SPRING_DATASOURCE_PASSWORD`
### Redis配置
```yaml
spring:
redis:
host: localhost
port: 6379
password: your_redis_password
database: 0
```
环境变量:
- `SPRING_REDIS_HOST`
- `SPRING_REDIS_PORT`
- `SPRING_REDIS_PASSWORD`
### 阿里云OSS配置
```yaml
config:
endpoint: https://oss-cn-shenzhen.aliyuncs.com
accessKeyId: your_access_key_id
accessKeySecret: your_access_key_secret
bucketName: your_bucket_name
bucketDomain: https://your-domain.com
```
环境变量:
- `ALIYUN_OSS_ENDPOINT`
- `ALIYUN_OSS_ACCESS_KEY_ID`
- `ALIYUN_OSS_ACCESS_KEY_SECRET`
- `ALIYUN_OSS_BUCKET_NAME`
- `ALIYUN_OSS_BUCKET_DOMAIN`
- `ALIYUN_OSS_ALIYUN_DOMAIN`
### 其他配置
- **JWT密钥**`config.token-key` 用于JWT令牌加密
- **JWT密钥**`JWT_SECRET``application-dev.yml`
- **令牌加密Key**`APP_TOKEN_KEY``application.yml``config.token-key`
- **文件上传路径**`config.upload-path` 本地文件存储路径
- **邮件服务**配置SMTP服务器用于发送邮件
- **微信支付**`WECHATPAY_API_V3_KEY`
### 开源注意事项
- 不要把数据库/Redis/MQTT/云服务密钥等写入 `application-*.yml` 或代码里;用环境变量或部署平台的 Secret 管理。
- 如果历史上曾提交过真实密钥,需要在对应平台轮换/作废,并清理 Git 历史(否则旧提交仍可被检出)。
## 🎯 核心功能
@@ -245,7 +252,7 @@ src/main/java/com/gxwebsoft/
```bash
# 1. 启动MySQL和Redis服务
# 2. 创建数据库并导入初始数据
# 3. 修改配置文件
# 3. 配置环境变量推荐cp .env.example .env然后 set -a; source .env; set +a
# 4. 启动应用
mvn spring-boot:run
```
@@ -255,12 +262,29 @@ mvn spring-boot:run
# 1. 打包应用
mvn clean package -Dmaven.test.skip=true
# 2. 运行jar包
java -jar target/com-gxwebsoft-modules-1.5.0.jar --spring.profiles.active=prod
# 2. 配置生产环境变量(示例)
export SPRING_PROFILES_ACTIVE=prod
export SPRING_DATASOURCE_URL='jdbc:mysql://<host>:3306/<db>?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai'
export SPRING_DATASOURCE_USERNAME='<user>'
export SPRING_DATASOURCE_PASSWORD='<password>'
export SPRING_REDIS_HOST='<host>'
export SPRING_REDIS_PORT='6379'
export SPRING_REDIS_PASSWORD='<password>'
# 3. 使用Docker部署可选
# 3. 运行jar包
java -jar target/com-gxwebsoft-modules-1.5.0.jar
# 4. 使用Docker部署可选
docker build -t websoft-api .
docker run -d -p 9200:9200 websoft-api
docker run -d -p 9200:9200 \
-e SPRING_PROFILES_ACTIVE=prod \
-e SPRING_DATASOURCE_URL='jdbc:mysql://<host>:3306/<db>?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai' \
-e SPRING_DATASOURCE_USERNAME='<user>' \
-e SPRING_DATASOURCE_PASSWORD='<password>' \
-e SPRING_REDIS_HOST='<host>' \
-e SPRING_REDIS_PORT='6379' \
-e SPRING_REDIS_PASSWORD='<password>' \
websoft-api
```
## 🤝 贡献指南
@@ -278,7 +302,7 @@ docker run -d -p 9200:9200 websoft-api
## 📞 联系我们
- 官网https://websoft.top
- 邮箱170083662@qq.top
- 邮箱170083662@qq.com
- QQ群479713884
---

View File

@@ -0,0 +1,221 @@
package com.gxwebsoft.common.core.web;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.common.core.Constants;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Controller基类
*
* @author WebSoft
* @since 2017-06-10 10:10:19
*/
public class BaseController {
@Resource
private HttpServletRequest request;
@Resource
// private RedisUtil redisUtil;
/**
* 获取当前登录的user
*
* @return User
*/
// public User getLoginUser() {
// try {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// if (authentication != null) {
// Object object = authentication.getPrincipal();
// if (object instanceof User) {
// return (User) object;
// }
// }
// } catch (Exception e) {
// System.out.println(e.getMessage());
// }
// return null;
// }
/**
* 获取当前登录的userId
*
* @return userId
*/
public Integer getLoginUserId() {
return null;
}
/**
* 获取当前登录的tenantId
*
* @return tenantId
*/
public Integer getTenantId() {
String tenantId;
// 2 从请求头拿ID
tenantId = request.getHeader("tenantId");
if(StrUtil.isNotBlank(tenantId)){
return Integer.valueOf(tenantId);
}
return null;
}
/**
* 返回成功
*
* @return ApiResult
*/
public ApiResult<?> success() {
return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG);
}
/**
* 返回成功
*
* @param message 状态信息
* @return ApiResult
*/
public ApiResult<?> success(String message) {
return success().setMessage(message);
}
/**
* 返回成功
*
* @param data 返回数据
* @return ApiResult
*/
public <T> ApiResult<T> success(T data) {
return new ApiResult<>(Constants.RESULT_OK_CODE, Constants.RESULT_OK_MSG, data);
}
/**
* 返回成功
*
* @param message 状态信息
* @return ApiResult
*/
public <T> ApiResult<T> success(String message, T data) {
return success(data).setMessage(message);
}
/**
* 返回分页查询数据
*
* @param list 当前页数据
* @param count 总数量
* @return ApiResult
*/
public <T> ApiResult<PageResult<T>> success(List<T> list, Long count) {
return success(new PageResult<>(list, count));
}
/**
* 返回分页查询数据
*
* @param iPage IPage
* @return ApiResult
*/
public <T> ApiResult<PageResult<T>> success(IPage<T> iPage) {
return success(iPage.getRecords(), iPage.getTotal());
}
/**
* 返回失败
*
* @return ApiResult
*/
public ApiResult<?> fail() {
return new ApiResult<>(Constants.RESULT_ERROR_CODE, Constants.RESULT_ERROR_MSG);
}
/**
* 返回失败
*
* @param message 状态信息
* @return ApiResult
*/
public ApiResult<?> fail(String message) {
return fail().setMessage(message);
}
/**
* 返回失败
*
* @param data 返回数据
* @return ApiResult
*/
public <T> ApiResult<T> fail(T data) {
return fail(Constants.RESULT_ERROR_MSG, data);
}
/**
* 返回失败
*
* @param message 状态信息
* @param data 返回数据
* @return ApiResult
*/
public <T> ApiResult<T> fail(String message, T data) {
return new ApiResult<>(Constants.RESULT_ERROR_CODE, message, data);
}
/**
* 请求参数的空字符串转为null
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
// 自定义函数
public String getAuthorization(){
return request.getHeader("Authorization");
}
public String getAppId() {
// 兼容小写
if(request.getHeader("appid") != null){
return request.getHeader("appid");
}
return request.getHeader("AppId");
}
/**
* 处理方法参数类型转换异常
* 主要处理URL路径参数中传入"NaN"等无法转换为Integer的情况
*
* @param ex 方法参数类型不匹配异常
* @return ApiResult
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ApiResult<?> handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex) {
String parameterName = ex.getName();
Object value = ex.getValue();
Class<?> requiredType = ex.getRequiredType();
// 记录错误日志
System.err.println("参数类型转换异常: 参数名=" + parameterName +
", 传入值=" + value +
", 期望类型=" + (requiredType != null ? requiredType.getSimpleName() : "unknown"));
// 如果是ID参数且传入的是"NaN",返回友好的错误信息
if ("id".equals(parameterName) && "NaN".equals(String.valueOf(value))) {
return fail("无效的ID参数请检查传入的ID值");
}
// 其他类型转换错误的通用处理
return fail("参数格式错误: " + parameterName + " 的值 '" + value + "' 无法转换为 " +
(requiredType != null ? requiredType.getSimpleName() : "目标类型"));
}
}

View File

@@ -1,52 +0,0 @@
package com.gxwebsoft.common.core.web;
import org.springframework.web.bind.annotation.RestController;
/**
* 简化版控制器基类,用于代码生成
* Created by WebSoft on 2019-10-29 15:55
*/
@RestController
public class SimpleBaseController {
/**
* 响应成功结果
*
* @param data 数据内容
* @param <T> 数据类型
* @return 响应结果
*/
protected <T> ApiResult<T> success(T data) {
return new ApiResult<T>(0, "操作成功", data);
}
/**
* 响应成功结果
*
* @return 响应结果
*/
protected ApiResult<String> success(String message) {
return new ApiResult<String>(0, message, null);
}
/**
* 响应失败结果
*
* @param message 错误信息
* @return 响应结果
*/
protected ApiResult<String> fail(String message) {
return new ApiResult<String>(1, message, null);
}
/**
* 响应失败结果
*
* @param code 错误码
* @param message 错误信息
* @return 响应结果
*/
protected ApiResult<String> fail(int code, String message) {
return new ApiResult<String>(code, message, null);
}
}

View File

@@ -7,18 +7,18 @@ server:
# 数据源配置
spring:
datasource:
url: jdbc:mysql://8.134.169.209:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: modules
password: P7KsAyDXG8YdLnkA
url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8}
username: ${SPRING_DATASOURCE_USERNAME:modules}
password: ${SPRING_DATASOURCE_PASSWORD:}
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
# redis
redis:
database: 0
host: 8.134.169.209
port: 16379
password: redis_WSDb88
host: ${SPRING_REDIS_HOST:localhost}
port: ${SPRING_REDIS_PORT:6379}
password: ${SPRING_REDIS_PASSWORD:}
# 日志配置
logging:
@@ -34,12 +34,12 @@ socketio:
# MQTT配置
mqtt:
enabled: false # 添加开关来禁用MQTT服务
host: tcp://1.14.159.185:1883
username: swdev
password: Sw20250523
client-id-prefix: hjm_car_
topic: /SW_GPS/#
qos: 2
host: ${MQTT_HOST:}
username: ${MQTT_USERNAME:}
password: ${MQTT_PASSWORD:}
client-id-prefix: ${MQTT_CLIENT_ID_PREFIX:hjm_car_}
topic: ${MQTT_TOPIC:/SW_GPS/#}
qos: ${MQTT_QOS:2}
connection-timeout: 10
keep-alive-interval: 20
auto-reconnect: true
@@ -52,7 +52,7 @@ config:
# JWT配置
jwt:
secret: websoft-jwt-secret-key-2025-dev-environment
secret: ${JWT_SECRET:}
expire: 86400 # token过期时间(秒) 24小时
# 开发环境证书配置

View File

@@ -3,9 +3,9 @@
# 数据源配置
spring:
datasource:
url: jdbc:mysql://1Panel-mysql-Bqdt:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: modules
password: 8YdLnk7KsPAyDXGA
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
@@ -14,9 +14,9 @@ spring:
# redis
redis:
database: 0
host: 1Panel-redis-Q1LE
port: 6379
password: redis_WSDb88
host: ${SPRING_REDIS_HOST}
port: ${SPRING_REDIS_PORT:6379}
password: ${SPRING_REDIS_PASSWORD:}
# 日志配置
logging:
@@ -33,12 +33,12 @@ socketio:
# MQTT配置
mqtt:
enabled: false # 添加开关来禁用MQTT服务
host: tcp://1.14.159.185:1883
username: swdev
password: Sw20250523
client-id-prefix: hjm_car_
topic: /SW_GPS/#
qos: 2
host: ${MQTT_HOST:}
username: ${MQTT_USERNAME:}
password: ${MQTT_PASSWORD:}
client-id-prefix: ${MQTT_CLIENT_ID_PREFIX:hjm_car_}
topic: ${MQTT_TOPIC:/SW_GPS/#}
qos: ${MQTT_QOS:2}
connection-timeout: 10
keep-alive-interval: 20
auto-reconnect: true
@@ -50,12 +50,12 @@ config:
upload-path: /www/wwwroot/file.ws/
# 阿里云OSS云存储
endpoint: https://oss-cn-shenzhen.aliyuncs.com
accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP
accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM
bucketName: oss-gxwebsoft
bucketDomain: https://oss.wsdns.cn
aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com
endpoint: ${ALIYUN_OSS_ENDPOINT:}
accessKeyId: ${ALIYUN_OSS_ACCESS_KEY_ID:}
accessKeySecret: ${ALIYUN_OSS_ACCESS_KEY_SECRET:}
bucketName: ${ALIYUN_OSS_BUCKET_NAME:}
bucketDomain: ${ALIYUN_OSS_BUCKET_DOMAIN:}
aliyunDomain: ${ALIYUN_OSS_ALIYUN_DOMAIN:}
# 生产环境证书配置
certificate:
@@ -72,9 +72,9 @@ payment:
aliyun:
knowledge-base:
access-key-id: LTAI5tD5YRKuxWz6Eg7qrM4P
access-key-secret: bO8TBDXflOwbtSKimPpG8XrJnyzgTk
workspace-id: llm-4pf5auwewoz34zqu
access-key-id: ${ALIYUN_KB_ACCESS_KEY_ID:}
access-key-secret: ${ALIYUN_KB_ACCESS_KEY_SECRET:}
workspace-id: ${ALIYUN_KB_WORKSPACE_ID:}
ai:
template:

View File

@@ -65,7 +65,7 @@ spring:
mail:
host: smtp.qq.com
username: 170083662@qq.com
password: mnfokualhfaucaie
password: ${SPRING_MAIL_PASSWORD:}
default-encoding: UTF-8
properties:
mail:
@@ -95,7 +95,7 @@ config:
swagger-title: 网宿软件 API文档
swagger-description: websoft - 基于java spring、vue3、antd构建的前后端分离快速开发框架
swagger-version: 2.0
token-key: WLgNsWJ8rPjRtnjzX/Gx2RGS80Kwnm/ZeLbvIL+NrBs=
token-key: ${APP_TOKEN_KEY:}
# 主服务器
server-url: https://server.websoft.top/api
# 文件服务器
@@ -106,12 +106,12 @@ config:
local-upload-path: /Users/gxwebsoft/Documents/uploads
# 阿里云OSS云存储
endpoint: https://oss-cn-shenzhen.aliyuncs.com
accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP
accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM
bucketName: oss-gxwebsoft
bucketDomain: https://oss.wsdns.cn
aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com
endpoint: ${ALIYUN_OSS_ENDPOINT:}
accessKeyId: ${ALIYUN_OSS_ACCESS_KEY_ID:}
accessKeySecret: ${ALIYUN_OSS_ACCESS_KEY_SECRET:}
bucketName: ${ALIYUN_OSS_BUCKET_NAME:}
bucketDomain: ${ALIYUN_OSS_BUCKET_DOMAIN:}
aliyunDomain: ${ALIYUN_OSS_ALIYUN_DOMAIN:}
# 商城订单配置
shop:
@@ -176,7 +176,7 @@ certificate:
# 微信支付证书配置
wechat-pay:
dev:
api-v3-key: "0kF5OlPr482EZwtn9zGufUcqa7ovgxRL"
api-v3-key: ${WECHATPAY_API_V3_KEY:}
private-key-file: "apiclient_key.pem"
apiclient-cert-file: "apiclient_cert.pem"
wechatpay-cert-file: "wechatpay_cert.pem"

View File

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.gxwebsoft.generator.engine.BeetlTemplateEnginePlus;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -31,27 +32,40 @@ public class ClinicGenerator {
// JAVA输出目录
private static final String OUTPUT_DIR = "/src/main/java";
// Vue文件输出位置
private static final String OUTPUT_LOCATION_VUE = "/Users/gxwebsoft/VUE/generator-vue";
private static final String OUTPUT_LOCATION_VUE = "/Users/gxwebsoft/JAVA/generator/output/admin";
// UniApp文件输出目录
private static final String OUTPUT_LOCATION_UNIAPP = "/Users/gxwebsoft/APP/template-10001";
private static final String OUTPUT_LOCATION_UNIAPP = "/Users/gxwebsoft/JAVA/generator/output/taro";
// Vue文件输出目录
private static final String OUTPUT_DIR_VUE = "/src";
// 作者名称
private static final String AUTHOR = "科技小王子";
// 是否在xml中添加二级缓存配置
private static final boolean ENABLE_CACHE = false;
static {
loadDotEnvIfPresent();
}
// 数据库连接配置
private static final String DB_URL = "jdbc:mysql://8.134.169.209:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8";
private static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DB_USERNAME = "modules";
private static final String DB_PASSWORD = "P7KsAyDXG8YdLnkA";
private static final String DB_URL = envOrProperty(
"CODEGEN_DB_URL",
"SPRING_DATASOURCE_URL",
"jdbc:mysql://localhost:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"
);
private static final String DB_DRIVER = envOrProperty(
"CODEGEN_DB_DRIVER",
"SPRING_DATASOURCE_DRIVER_CLASS_NAME",
"com.mysql.cj.jdbc.Driver"
);
private static final String DB_USERNAME = envOrProperty("CODEGEN_DB_USERNAME", "SPRING_DATASOURCE_USERNAME", "modules");
private static final String DB_PASSWORD = envOrProperty("CODEGEN_DB_PASSWORD", "SPRING_DATASOURCE_PASSWORD", "");
// 包名
private static final String PACKAGE_NAME = "com.gxwebsoft";
// 模块名
private static final String MODULE_NAME = "clinic";
// 需要生成的表
private static final String[] TABLE_NAMES = new String[]{
"clinic_appointment",
// "clinic_appointment",
// "clinic_doctor_apply",
// "clinic_doctor_medical_record",
// "clinic_doctor_user",
@@ -65,6 +79,7 @@ public class ClinicGenerator {
// "clinic_prescription_item",
// "clinic_report",
// "clinic_visit_record",
"clinic_",
};
// 需要去除的表前缀
private static final String[] TABLE_PREFIX = new String[]{
@@ -98,6 +113,52 @@ public class ClinicGenerator {
// 模板所在位置
private static final String TEMPLATES_DIR = "/src/test/java/com/gxwebsoft/generator/templates";
private static String envOrProperty(String primaryKey, String fallbackKey, String defaultValue) {
String value = envOrProperty(primaryKey, "");
if (value.isBlank() && fallbackKey != null && !fallbackKey.isBlank()) {
value = envOrProperty(fallbackKey, "");
}
return value.isBlank() ? defaultValue : value;
}
private static String envOrProperty(String key, String defaultValue) {
String value = System.getProperty(key);
if (value == null || value.isBlank()) value = System.getenv(key);
if (value == null || value.isBlank()) return defaultValue;
return value;
}
private static boolean shouldImportDotEnvKey(String key) {
return key.startsWith("CODEGEN_") || key.startsWith("SPRING_DATASOURCE_");
}
private static void loadDotEnvIfPresent() {
var envPath = Paths.get(OUTPUT_LOCATION, ".env");
if (!Files.isRegularFile(envPath)) return;
try {
for (String rawLine : Files.readAllLines(envPath, StandardCharsets.UTF_8)) {
String line = rawLine.trim();
if (line.isEmpty() || line.startsWith("#")) continue;
if (line.startsWith("export ")) line = line.substring("export ".length()).trim();
int equalsIndex = line.indexOf('=');
if (equalsIndex <= 0) continue;
String key = line.substring(0, equalsIndex).trim();
if (key.isEmpty() || !shouldImportDotEnvKey(key)) continue;
if (System.getProperty(key) != null || System.getenv(key) != null) continue;
String value = line.substring(equalsIndex + 1).trim();
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
value = value.substring(1, value.length() - 1);
}
System.setProperty(key, value);
}
} catch (Exception e) {
System.err.println("Warning: failed to load .env from " + envPath + " (" + e.getClass().getSimpleName() + ")");
}
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
@@ -135,7 +196,7 @@ public class ClinicGenerator {
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setInclude(TABLE_NAMES);
strategy.setTablePrefix(TABLE_PREFIX);
strategy.setSuperControllerClass(PACKAGE_NAME + ".common.core.web.SimpleBaseController");
strategy.setSuperControllerClass(PACKAGE_NAME + ".common.core.web.BaseController");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);

View File

@@ -0,0 +1,467 @@
package com.gxwebsoft.generator;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.gxwebsoft.generator.engine.BeetlTemplateEnginePlus;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* CMS模块-代码生成工具
*
* @author WebSoft
* @since 2021-09-05 00:31:14
*/
public class CreditGenerator {
// 输出位置
private static final String OUTPUT_LOCATION = System.getProperty("user.dir");
//private static final String OUTPUT_LOCATION = "D:/codegen"; // 不想生成到项目中可以写磁盘路径
// JAVA输出目录
private static final String OUTPUT_DIR = "/src/main/java";
// Vue文件输出位置
private static final String OUTPUT_LOCATION_VUE = "/Users/gxwebsoft/JAVA/generator/output/admin";
// UniApp文件输出目录
private static final String OUTPUT_LOCATION_UNIAPP = "/Users/gxwebsoft/JAVA/generator/output/taro";
// Vue文件输出目录
private static final String OUTPUT_DIR_VUE = "/src";
// 作者名称
private static final String AUTHOR = "科技小王子";
// 是否在xml中添加二级缓存配置
private static final boolean ENABLE_CACHE = false;
static {
loadDotEnvIfPresent();
}
// 数据库连接配置
private static final String DB_URL = envOrProperty(
"CODEGEN_DB_URL",
"SPRING_DATASOURCE_URL",
"jdbc:mysql://localhost:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8"
);
private static final String DB_DRIVER = envOrProperty(
"CODEGEN_DB_DRIVER",
"SPRING_DATASOURCE_DRIVER_CLASS_NAME",
"com.mysql.cj.jdbc.Driver"
);
private static final String DB_USERNAME = envOrProperty("CODEGEN_DB_USERNAME", "SPRING_DATASOURCE_USERNAME", "modules");
private static final String DB_PASSWORD = envOrProperty("CODEGEN_DB_PASSWORD", "SPRING_DATASOURCE_PASSWORD", "");
// 包名
private static final String PACKAGE_NAME = "com.gxwebsoft";
// 模块名
private static final String MODULE_NAME = "credit";
// 需要生成的表
private static final String[] TABLE_NAMES = new String[]{
// "credit_user",
// "credit_judiciary",
// "credit_company",
// "credit_breach_of_trust",
// "credit_case_filing",
// "credit_company",
// "credit_competitor",
// "credit_court_announcement",
// "credit_court_session",
// "credit_customer",
// "credit_delivery_notice",
// "credit_external",
// "credit_final_version",
// "credit_gqdj",
// "credit_judgment_debtor",
// "credit_judicial_document",
// "credit_mediation",
// "credit_risk_relation",
// "credit_supplier",
// "credit_xgxf",
// "credit_administrative_license",
// "credit_bankruptcy",
// "credit_branch",
// "credit_historical_legal_person",
// "credit_nearby_company",
"credit_patent",
// "credit_suspected_relationship"
};
// 需要去除的表前缀
private static final String[] TABLE_PREFIX = new String[]{
"tb_"
};
// 不需要作为查询参数的字段
private static final String[] PARAM_EXCLUDE_FIELDS = new String[]{
"tenant_id",
"create_time",
"update_time"
};
// 查询参数使用String的类型
private static final String[] PARAM_TO_STRING_TYPE = new String[]{
"Date",
"LocalDate",
"LocalTime",
"LocalDateTime"
};
// 查询参数使用EQ的类型
private static final String[] PARAM_EQ_TYPE = new String[]{
"Integer",
"Boolean",
"BigDecimal"
};
// 是否添加权限注解
private static final boolean AUTH_ANNOTATION = true;
// 是否添加日志注解
private static final boolean LOG_ANNOTATION = true;
// controller的mapping前缀
private static final String CONTROLLER_MAPPING_PREFIX = "/api";
// 模板所在位置
private static final String TEMPLATES_DIR = "/src/test/java/com/gxwebsoft/generator/templates";
private static String envOrProperty(String primaryKey, String fallbackKey, String defaultValue) {
String value = envOrProperty(primaryKey, "");
if (value.isBlank() && fallbackKey != null && !fallbackKey.isBlank()) {
value = envOrProperty(fallbackKey, "");
}
return value.isBlank() ? defaultValue : value;
}
private static String envOrProperty(String key, String defaultValue) {
String value = System.getProperty(key);
if (value == null || value.isBlank()) value = System.getenv(key);
if (value == null || value.isBlank()) return defaultValue;
return value;
}
private static boolean shouldImportDotEnvKey(String key) {
return key.startsWith("CODEGEN_") || key.startsWith("SPRING_DATASOURCE_");
}
private static void loadDotEnvIfPresent() {
var envPath = Paths.get(OUTPUT_LOCATION, ".env");
if (!Files.isRegularFile(envPath)) return;
try {
for (String rawLine : Files.readAllLines(envPath, StandardCharsets.UTF_8)) {
String line = rawLine.trim();
if (line.isEmpty() || line.startsWith("#")) continue;
if (line.startsWith("export ")) line = line.substring("export ".length()).trim();
int equalsIndex = line.indexOf('=');
if (equalsIndex <= 0) continue;
String key = line.substring(0, equalsIndex).trim();
if (key.isEmpty() || !shouldImportDotEnvKey(key)) continue;
if (System.getProperty(key) != null || System.getenv(key) != null) continue;
String value = line.substring(equalsIndex + 1).trim();
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
value = value.substring(1, value.length() - 1);
}
System.setProperty(key, value);
}
} catch (Exception e) {
System.err.println("Warning: failed to load .env from " + envPath + " (" + e.getClass().getSimpleName() + ")");
}
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir(OUTPUT_LOCATION + OUTPUT_DIR);
gc.setAuthor(AUTHOR);
gc.setOpen(false);
gc.setFileOverride(true);
gc.setEnableCache(ENABLE_CACHE);
gc.setSwagger2(true);
gc.setIdType(IdType.AUTO);
gc.setServiceName("%sService");
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl(DB_URL);
// dsc.setSchemaName("public");
dsc.setDriverName(DB_DRIVER);
dsc.setUsername(DB_USERNAME);
dsc.setPassword(DB_PASSWORD);
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(MODULE_NAME);
pc.setParent(PACKAGE_NAME);
mpg.setPackageInfo(pc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setInclude(TABLE_NAMES);
strategy.setTablePrefix(TABLE_PREFIX);
strategy.setSuperControllerClass(PACKAGE_NAME + ".common.core.web.BaseController");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
strategy.setLogicDeleteFieldName("deleted");
mpg.setStrategy(strategy);
// 模板配置
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setController(TEMPLATES_DIR + "/controller.java");
templateConfig.setEntity(TEMPLATES_DIR + "/entity.java");
templateConfig.setMapper(TEMPLATES_DIR + "/mapper.java");
templateConfig.setXml(TEMPLATES_DIR + "/mapper.xml");
templateConfig.setService(TEMPLATES_DIR + "/service.java");
templateConfig.setServiceImpl(TEMPLATES_DIR + "/serviceImpl.java");
mpg.setTemplate(templateConfig);
mpg.setTemplateEngine(new BeetlTemplateEnginePlus());
// 自定义模板配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
Map<String, Object> map = new HashMap<>();
map.put("packageName", PACKAGE_NAME);
map.put("paramExcludeFields", PARAM_EXCLUDE_FIELDS);
map.put("paramToStringType", PARAM_TO_STRING_TYPE);
map.put("paramEqType", PARAM_EQ_TYPE);
map.put("authAnnotation", AUTH_ANNOTATION);
map.put("logAnnotation", LOG_ANNOTATION);
map.put("controllerMappingPrefix", CONTROLLER_MAPPING_PREFIX);
// 添加项目类型标识,用于模板中的条件判断
map.put("isUniApp", false); // Vue 项目
map.put("isVueAdmin", true); // 后台管理项目
this.setMap(map);
}
};
String templatePath = TEMPLATES_DIR + "/param.java.btl";
List<FileOutConfig> focList = new ArrayList<>();
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION + OUTPUT_DIR + "/"
+ PACKAGE_NAME.replace(".", "/")
+ "/" + pc.getModuleName() + "/param/"
+ tableInfo.getEntityName() + "Param" + StringPool.DOT_JAVA;
}
});
/**
* 以下是生成VUE项目代码
* 生成文件的路径 /api/shop/goods/index.ts
*/
templatePath = TEMPLATES_DIR + "/index.ts.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE
+ "/api/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/" + "index.ts";
}
});
// UniApp 使用专门的模板
String uniappTemplatePath = TEMPLATES_DIR + "/index.ts.uniapp.btl";
focList.add(new FileOutConfig(uniappTemplatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE
+ "/api/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/" + "index.ts";
}
});
// 生成TS文件 (/api/shop/goods/model/index.ts)
templatePath = TEMPLATES_DIR + "/model.ts.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE
+ "/api/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/model/" + "index.ts";
}
});
// UniApp 使用专门的 model 模板
String uniappModelTemplatePath = TEMPLATES_DIR + "/model.ts.uniapp.btl";
focList.add(new FileOutConfig(uniappModelTemplatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE
+ "/api/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/model/" + "index.ts";
}
});
// 生成Vue文件(/views/shop/goods/index.vue)
templatePath = TEMPLATES_DIR + "/index.vue.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE
+ "/views/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/" + "index.vue";
}
});
// 生成components文件(/views/shop/goods/components/edit.vue)
templatePath = TEMPLATES_DIR + "/components.edit.vue.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE
+ "/views/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/components/" + tableInfo.getEntityPath() + "Edit.vue";
}
});
// 生成components文件(/views/shop/goods/components/search.vue)
templatePath = TEMPLATES_DIR + "/components.search.vue.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_VUE + OUTPUT_DIR_VUE
+ "/views/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/components/" + "search.vue";
}
});
// ========== 移动端页面文件生成 ==========
// 生成移动端列表页面配置文件 (/src/shop/goods/index.config.ts)
templatePath = TEMPLATES_DIR + "/index.config.ts.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE
+ "/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/" + "index.config.ts";
}
});
// 生成移动端列表页面组件文件 (/src/shop/goods/index.tsx)
templatePath = TEMPLATES_DIR + "/index.tsx.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE
+ "/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/" + "index.tsx";
}
});
// 生成移动端新增/编辑页面配置文件 (/src/shop/goods/add.config.ts)
templatePath = TEMPLATES_DIR + "/add.config.ts.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE
+ "/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/" + "add.config.ts";
}
});
// 生成移动端新增/编辑页面组件文件 (/src/shop/goods/add.tsx)
templatePath = TEMPLATES_DIR + "/add.tsx.btl";
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
return OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE
+ "/" + pc.getModuleName() + "/"
+ tableInfo.getEntityPath() + "/" + "add.tsx";
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
mpg.execute();
// 自动更新 app.config.ts
updateAppConfig(TABLE_NAMES, MODULE_NAME);
}
/**
* 自动更新 app.config.ts 文件,添加新生成的页面路径
*/
private static void updateAppConfig(String[] tableNames, String moduleName) {
String appConfigPath = OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + "/app.config.ts";
try {
// 读取原文件内容
String content = new String(Files.readAllBytes(Paths.get(appConfigPath)));
// 为每个表生成页面路径
StringBuilder newPages = new StringBuilder();
for (String tableName : tableNames) {
String entityPath = tableName.replaceAll("_", "");
// 转换为驼峰命名
String[] parts = tableName.split("_");
StringBuilder camelCase = new StringBuilder(parts[0]);
for (int i = 1; i < parts.length; i++) {
camelCase.append(parts[i].substring(0, 1).toUpperCase()).append(parts[i].substring(1));
}
entityPath = camelCase.toString();
newPages.append(" '").append(entityPath).append("/index',\n");
newPages.append(" '").append(entityPath).append("/add',\n");
}
// 查找对应模块的子包配置
String modulePattern = "\"root\":\\s*\"" + moduleName + "\",\\s*\"pages\":\\s*\\[([^\\]]*)]";
Pattern pattern = Pattern.compile(modulePattern, Pattern.DOTALL);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
String existingPages = matcher.group(1);
// 检查页面是否已存在,避免重复添加
boolean needUpdate = false;
String[] newPageArray = newPages.toString().split("\n");
for (String newPage : newPageArray) {
if (!newPage.trim().isEmpty() && !existingPages.contains(newPage.trim().replace(" ", "").replace(",", ""))) {
needUpdate = true;
break;
}
}
if (needUpdate) {
// 备份原文件
String backupPath = appConfigPath + ".backup." + System.currentTimeMillis();
Files.copy(Paths.get(appConfigPath), Paths.get(backupPath));
System.out.println("已备份原文件到: " + backupPath);
// 在现有页面列表末尾添加新页面
String updatedPages = existingPages.trim();
if (!updatedPages.endsWith(",")) {
updatedPages += ",";
}
updatedPages += "\n" + newPages.toString().trim();
// 替换内容
String updatedContent = content.replace(matcher.group(1), updatedPages);
// 写入更新后的内容
Files.write(Paths.get(appConfigPath), updatedContent.getBytes());
System.out.println("✅ 已自动更新 app.config.ts添加了以下页面路径:");
System.out.println(newPages.toString());
} else {
System.out.println(" app.config.ts 中已包含所有页面路径,无需更新");
}
} else {
System.out.println("⚠️ 未找到 " + moduleName + " 模块的子包配置,请手动添加页面路径");
}
} catch (Exception e) {
System.err.println("❌ 更新 app.config.ts 失败: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -13,6 +13,8 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
<% } %>
<% } %>
<% /* 为时间类型字段添加日期格式化注解的导入 */ %>
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* ${table.comment!}
@@ -48,63 +50,33 @@ public class ${entity} implements Serializable {
private static final long serialVersionUID = 1L;
<% } %>
<% /** -----------BEGIN 字段循环遍历----------- **/ %>
<% for(field in table.fields) { %>
<%
var keyPropertyName;
if(field.keyFlag) {
keyPropertyName = field.propertyName;
}
%>
<% for(field in table.fields) {
var keyPropertyName = field.keyFlag ? field.propertyName : null;
%>
<% if(isNotEmpty(field.comment)) { %>
<% if(swagger2) { %>
@Schema(description = "${field.comment}")
<% }else{ %>
/**
<% if(isNotEmpty(field.comment)) { %><% if(swagger2) { %> @Schema(description = "${field.comment}")
<% }else{ %> /**
* ${field.comment}
*/
<% } %>
<% } %>
<% /* 主键 */ %>
<% if(field.keyFlag) { %>
<% if(field.keyIdentityFlag) { %>
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
<% } else if(isNotEmpty(idType)) { %>
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
<% } else if(field.convert) { %>
@TableId("${field.annotationColumnName}")
<% } %>
<% /* 普通字段 */ %>
<% } else if(isNotEmpty(field.fill)) { %>
<% if(field.convert){ %>
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
<% }else{ %>
@TableField(fill = FieldFill.${field.fill})
<% } %>
<% } else if(field.convert) { %>
@TableField("${field.annotationColumnName}")
<% } %>
<% /* 乐观锁注解 */ %>
<% if(versionFieldName!'' == field.name) { %>
@Version
<% } %>
<% /* 逻辑删除注解 */ %>
<% if(logicDeleteFieldName!'' == field.name) { %>
@TableLogic
<% } %>
private ${field.propertyType} ${field.propertyName};
<% } %><% } %><% /* 为时间类型字段添加日期格式化注解 */ %><% if(field.propertyType == 'LocalDateTime' || field.propertyType == 'LocalDate' || field.propertyType == 'LocalTime' || field.propertyType == 'Date') { %><% if(field.propertyType == 'LocalDateTime') { %> @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
<% } else if(field.propertyType == 'LocalDate') { %> @JsonFormat(pattern = "yyyy-MM-dd")
<% } else if(field.propertyType == 'LocalTime') { %> @JsonFormat(pattern = "HH:mm:ss")
<% } else if(field.propertyType == 'Date') { %> @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
<% } %><% } %><% /* 添加其他注解(主键、字段填充等) */ %><% if(field.keyFlag) { %><% if(field.keyIdentityFlag) { %> @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
<% } else if(isNotEmpty(idType)) { %> @TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
<% } else if(field.convert) { %> @TableId("${field.annotationColumnName}")
<% } %><% } else if(isNotEmpty(field.fill)) { %><% if(field.convert){ %> @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
<% }else{ %> @TableField(fill = FieldFill.${field.fill})
<% } %><% } else if(field.convert) { %> @TableField("${field.annotationColumnName}")
<% } %><% if(versionFieldName!'' == field.name) { %> @Version
<% } %><% if(logicDeleteFieldName!'' == field.name) { %> @TableLogic
<% } %> private ${field.propertyType} ${field.propertyName};
<% } %>
<% /** -----------END 字段循环遍历----------- **/ %>
<% if(!entityLombokModel) { %>
<% for(field in table.fields) { %>
<%
var getprefix = '';
if(field.propertyType == 'boolean') {
getprefix = 'is';
} else {
getprefix = 'get';
}
<% for(field in table.fields) {
var getprefix = field.propertyType == 'boolean' ? 'is' : 'get';
%>
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};

View File

@@ -3,7 +3,7 @@
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="${table.entityPath}Id"
row-key="id"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
@@ -98,7 +98,7 @@
};
// 完整的列配置(包含所有字段)
const allColumns = ref<ColumnItem[]>([
const columns = ref<ColumnItem[]>([
<% for(field in table.fields) { %>
<% if(field.propertyName != 'tenantId'){ %>
{
@@ -133,26 +133,6 @@
}
]);
// 默认显示的核心列最多5个主要字段
const defaultVisibleColumns = [
<% var count = 0; %>
<% for(field in table.fields) { %>
<% if(field.keyFlag || field.propertyName == 'name' || field.propertyName == 'title' || field.propertyName == 'status' || field.propertyName == 'createTime'){ %>
'${field.propertyName}',
<% count = count + 1; %>
<% if(count >= 5) break; %>
<% } %>
<% } %>
'action'
];
// 根据默认可见列过滤显示的列
const columns = computed(() => {
return allColumns.value.filter(col =>
defaultVisibleColumns.includes(col.dataIndex) || col.key === 'action'
);
});
/* 搜索 */
const reload = (where?: ${entity}Param) => {
selection.value = [];
@@ -173,7 +153,7 @@
/* 删除单个 */
const remove = (row: ${entity}) => {
const hide = message.loading('请求中..', 0);
remove${entity}(row.${table.entityPath}Id)
remove${entity}(row.id)
.then((msg) => {
hide();
message.success(msg);
@@ -198,7 +178,7 @@
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatch${entity}(selection.value.map((d) => d.${table.entityPath}Id))
removeBatch${entity}(selection.value.map((d) => d.id))
.then((msg) => {
hide();
message.success(msg);