commit 33423fc4d23d2cbf1547e9fc2948ddf3790c3d4a Author: lcj <2331845269@qq.com> Date: Wed Jul 23 16:38:10 2025 +0800 first commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..25b312e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# http://editorconfig.org +root = true + +# 空格替代Tab缩进在各种编辑工具下效果一致 +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{json,yml,yaml}] +indent_size = 2 + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ee651b --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml + +.flattened-pom.xml + +.gitee +.run +logs/ +docs +/file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..32b3071 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2019 RuoYi-Vue-Plus + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fc3131a --- /dev/null +++ b/README.md @@ -0,0 +1,185 @@ + +
+ +- - - +## 平台简介 + +[![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus) +[![Star](https://gitcode.com/dromara/RuoYi-Vue-Plus/star/badge.svg)](https://gitcode.com/dromara/RuoYi-Vue-Plus) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) +[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) +
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.3.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.4-blue.svg)]() +[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() +[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() + +> Dromara RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群与多租户` 场景全方位升级(不兼容原框架) + +> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
+活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 + +> 系统演示: [传送门](https://plus-doc.dromara.org/#/common/demo_system) + +> 官方前端项目地址: [plus-ui](https://gitee.com/JavaLionLi/plus-ui)
+> 成员前端项目地址: 基于vben5 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5) + +> 文档地址: [plus-doc](https://plus-doc.dromara.org) + +## 赞助商 + +MaxKey 业界领先单点登录产品 - https://gitee.com/dromara/MaxKey
+CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow
+数舵科技 软件定制开发APP小程序等 - http://www.shuduokeji.com/
+引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc
+**启山商城系统 多租户商城源码可免费商用可二次开发 - https://www.73app.cn/**
+[如何成为赞助商 加群联系作者详谈](https://plus-doc.dromara.org/#/common/add_group) + +# 本框架与RuoYi的功能差异 + +| 功能 | 本框架 | RuoYi | +|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| +| 前端项目 | 采用 Vue3 + TS + ElementPlus 重写 | 基于Vue2/Vue3 + JS | +| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 | +| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 | +| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat | +| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 | +| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | +| 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 | +| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | +| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | +| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | +| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | +| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | +| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 | +| 数据分页 | 采用 Mybatis-Plus 分页插件
框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 | +| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤
只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展
生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | +| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件
支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 | +| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密
支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 | +| 接口传输加密 | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性 | 无 | +| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译
支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 | +| 多数据源框架 | 采用 dynamic-datasource 支持市面大部分数据库
通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源
支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 | +| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 | +| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | +| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | +| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | +| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | +| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | +| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | +| 分布式锁 | 采用 Lock4j 底层基于 Redisson | 无 | +| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | +| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | +| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | +| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 | +| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | +| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | +| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | +| Excel框架 | 采用 Alibaba EasyExcel 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | +| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | +| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | +| 监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | +| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗
用了它即可实时查看请求经过的每一处每一个节点 | 无 | +| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面
降低80%的开发量 把精力都投入到业务设计上
框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 | +| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 | +| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 | +| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 | +| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 | +| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 | + + +## 本框架与RuoYi的业务差异 + +| 业务 | 功能说明 | 本框架 | RuoYi | +|--------|----------------------------------------------------------------------|-----|------------------| +| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 | +| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 | +| 客户端管理 | 系统内对接的所有客户端管理 如: pc端、小程序端等
支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效 | 支持 | 无 | +| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 | +| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 | +| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 | +| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 | +| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 | +| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 | +| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 | +| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 | +| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 | +| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 | +| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 | +| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 | +| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 | +| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 | +| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 | +| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 | +| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 | +| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | +| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 | +| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | + +## 参考文档 + +使用框架前请仔细阅读文档重点注意事项 +
+>[初始化项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) +>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) +> +>[专栏与视频 入门必看](https://plus-doc.dromara.org/#/common/column) +>>[https://plus-doc.dromara.org/#/common/column](https://plus-doc.dromara.org/#/common/column) +> +>[部署项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) +>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) +> +>[如何加群](https://plus-doc.dromara.org/#/common/add_group) +>>[https://plus-doc.dromara.org/#/common/add_group](https://plus-doc.dromara.org/#/common/add_group) +> +>[参考文档 Wiki](https://plus-doc.dromara.org) +>>[https://plus-doc.dromara.org](https://plus-doc.dromara.org) + +## 软件架构图 + +![Plus部署架构图](https://foruda.gitee.com/images/1678981882624240692/ae2a3f3e_1766278.png "Plus部署架构图.png") + +## 如何参与贡献 + +[参与贡献的方式 https://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution) + +## 捐献作者 +作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭 + + + +## 演示图例 + +| | | +|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1735829153637063344/3c21fd4c_1419627.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1735829181303499815/4522cefa_1419627.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1735829377205259767/76a705d7_1419627.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1722959592856812900/e2d0d342_1419627.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") | + + + + + + + + + + + + diff --git a/file/resource/design/main.exe b/file/resource/design/main.exe new file mode 100644 index 0000000..b6711ac Binary files /dev/null and b/file/resource/design/main.exe differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3480f20 --- /dev/null +++ b/pom.xml @@ -0,0 +1,521 @@ + + + 4.0.0 + + org.dromara + xinnengyuan + ${revision} + + xinnengyuan + 新能源项目 + + + 5.3.0 + 3.4.2 + UTF-8 + UTF-8 + 21 + 3.5.16 + 2.8.4 + 0.15.0 + 4.0.3 + 2.3 + 1.40.0 + 3.5.10 + 3.9.1 + 5.8.35 + 3.4.1 + 3.44.0 + 2.2.7 + 4.3.1 + 1.3.0 + 1.4.6 + 0.2.0 + 1.18.36 + 1.76 + 1.16.7 + + 2.7.0 + + + 2.28.22 + 0.31.3 + + 3.3.3 + + 1.2.83 + + 8.7.2-20250101 + + 1.7.4 + + + 3.2.2 + 3.2.2 + 3.11.0 + 3.1.2 + 1.3.0 + + 1.20.0 + + + + + local + + + local + info + ruoyi + 123456 + + + + dev + + + dev + info + ruoyi + 123456 + + + + true + + + + prod + + prod + info + ruoyi + 123456 + + + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + cn.hutool + hutool-bom + ${hutool.version} + pom + import + + + + + org.dromara.warm + warm-flow-mybatis-plus-sb3-starter + ${warm-flow.version} + + + org.dromara.warm + warm-flow-plugin-ui-sb-web + ${warm-flow.version} + + + + + me.zhyd.oauth + JustAuth + ${justauth.version} + + + + + org.dromara + ruoyi-common-bom + ${revision} + pom + import + + + + org.springdoc + springdoc-openapi-starter-webmvc-api + ${springdoc.version} + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + + com.github.therapi + therapi-runtime-javadoc + ${therapi-javadoc.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + com.alibaba + easyexcel + ${easyexcel.version} + + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + + cn.dev33 + sa-token-spring-boot3-starter + ${satoken.version} + + + + cn.dev33 + sa-token-jwt + ${satoken.version} + + + cn.hutool + hutool-all + + + + + cn.dev33 + sa-token-core + ${satoken.version} + + + + + com.baomidou + dynamic-datasource-spring-boot3-starter + ${dynamic-ds.version} + + + + org.mybatis + mybatis + ${mybatis.version} + + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-jsqlparser + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-annotation + ${mybatis-plus.version} + + + + + p6spy + p6spy + ${p6spy.version} + + + + + software.amazon.awssdk + s3 + ${aws.sdk.version} + + + + software.amazon.awssdk.crt + aws-crt + ${aws.crt.version} + + + + software.amazon.awssdk + s3-transfer-manager + ${aws.sdk.version} + + + + org.dromara.sms4j + sms4j-spring-boot-starter + ${sms4j.version} + + + + de.codecentric + spring-boot-admin-starter-server + ${spring-boot-admin.version} + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + + + com.aizuda + snail-job-client-starter + ${snailjob.version} + + + com.aizuda + snail-job-client-job-core + ${snailjob.version} + + + + + org.bouncycastle + bcprov-jdk15to18 + ${bouncycastle.version} + + + + io.github.linpeilie + mapstruct-plus-spring-boot-starter + ${mapstruct-plus.version} + + + + + org.lionsoul + ip2region + ${ip2region.version} + + + + commons-io + commons-io + 2.15.0 + + + + com.alibaba + fastjson + ${fastjson.version} + + + + org.dromara + ruoyi-system + ${revision} + + + + org.dromara + ruoyi-app + ${revision} + + + + org.dromara + ruoyi-job + ${revision} + + + + org.dromara + ruoyi-generator + ${revision} + + + + + org.dromara + ruoyi-workflow + ${revision} + + + + + org.locationtech.jts + jts-core + ${jts.version} + + + + + + + ruoyi-admin + ruoyi-common + ruoyi-extend + ruoyi-modules + + pom + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + com.github.therapi + therapi-runtime-javadoc-scribe + ${therapi-javadoc.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + io.github.linpeilie + mapstruct-plus-processor + ${mapstruct-plus.version} + + + org.projectlombok + lombok-mapstruct-binding + ${mapstruct-plus.lombok.version} + + + + -parameters + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + -Dfile.encoding=UTF-8 + + ${profiles.active} + + exclude + + + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + src/main/resources + + false + + + src/main/resources + + + application* + bootstrap* + banner* + + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + false + + + + + + + diff --git a/ruoyi-admin/Dockerfile b/ruoyi-admin/Dockerfile new file mode 100644 index 0000000..c934bce --- /dev/null +++ b/ruoyi-admin/Dockerfile @@ -0,0 +1,30 @@ +# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ +#FROM bellsoft/liberica-openjdk-debian:17.0.11-cds +FROM bellsoft/liberica-openjdk-debian:21.0.5-cds +#FROM findepi/graalvm:java17-native + +LABEL maintainer="lilemy" + +RUN mkdir -p /ruoyi/server/logs \ + /ruoyi/server/temp \ + /ruoyi/skywalking/agent + +WORKDIR /ruoyi/server + +ENV SERVER_PORT=8899 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" + +EXPOSE ${SERVER_PORT} + +ADD ./target/ruoyi-admin.jar ./app.jar +# 工作流字体文件 +ADD ./zhFonts/ /usr/share/fonts/zhFonts/ + +SHELL ["/bin/bash", "-c"] + +ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ + # 应用名称 如果想区分集群节点监控 改成不同的名称即可 + #-Dskywalking.agent.service_name=ruoyi-server \ + #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \ + -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ + -jar app.jar + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml new file mode 100644 index 0000000..341d24a --- /dev/null +++ b/ruoyi-admin/pom.xml @@ -0,0 +1,152 @@ + + + + xinnengyuan + org.dromara + ${revision} + + 4.0.0 + jar + ruoyi-admin + + + web服务入口 + + + + + + + com.mysql + mysql-connector-j + + + + + + + + + + + + + + + + + + + + + + + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-social + + + + org.dromara + ruoyi-common-ratelimiter + + + + org.dromara + ruoyi-common-mail + + + + org.dromara + ruoyi-system + + + + org.dromara + ruoyi-app + + + + org.dromara + ruoyi-job + + + + + org.dromara + ruoyi-generator + + + + + org.dromara + ruoyi-workflow + + + + de.codecentric + spring-boot-admin-starter-client + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + + + + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + ${project.artifactId} + + + + + + diff --git a/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java new file mode 100644 index 0000000..f19a18c --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java @@ -0,0 +1,36 @@ +package org.dromara; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 启动程序 + * + * @author Lion Li + */ +@SpringBootApplication +@EnableAsync +@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) +@EnableScheduling +public class DromaraApplication implements WebMvcConfigurer { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(DromaraApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println("(♥◠‿◠)ノ゙ RuoYi-Vue-Plus启动成功 ლ(´ڡ`ლ)゙"); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java b/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java new file mode 100644 index 0000000..edf0a8d --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java @@ -0,0 +1,17 @@ +package org.dromara; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author Lion Li + */ +public class DromaraServletInitializer extends SpringBootServletInitializer { + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(DromaraApplication.class); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java new file mode 100644 index 0000000..06797a1 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -0,0 +1,239 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginBody; +import org.dromara.common.core.domain.model.RegisterBody; +import org.dromara.common.core.domain.model.SocialLoginBody; +import org.dromara.common.core.utils.*; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.social.config.properties.SocialLoginConfigProperties; +import org.dromara.common.social.config.properties.SocialProperties; +import org.dromara.common.social.utils.SocialUtils; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.service.ISysClientService; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.ISysSocialService; +import org.dromara.system.service.ISysTenantService; +import org.dromara.web.domain.vo.LoginTenantVo; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.domain.vo.TenantListVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.dromara.web.service.SysRegisterService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 认证 + * + * @author Lion Li + */ +@Slf4j +@SaIgnore +@RequiredArgsConstructor +@RestController +@RequestMapping("/auth") +public class AuthController { + + private final SocialProperties socialProperties; + private final SysLoginService loginService; + private final SysRegisterService registerService; + private final ISysConfigService configService; + private final ISysTenantService tenantService; + private final ISysSocialService socialUserService; + private final ISysClientService clientService; + private final ScheduledExecutorService scheduledExecutorService; + + + /** + * 登录方法 + * + * @param body 登录信息 + * @return 结果 + */ + @ApiEncrypt + @PostMapping("/login") + public R login(@RequestBody String body) { + LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class); + ValidatorUtils.validate(loginBody); + // 授权类型和客户端id + String clientId = loginBody.getClientId(); + String grantType = loginBody.getGrantType(); + SysClientVo client = clientService.queryByClientId(clientId); + // 查询不到 client 或 client 内不包含 grantType + if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { + log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); + return R.fail(MessageUtils.message("auth.grant.type.error")); + } else if (!SystemConstants.NORMAL.equals(client.getStatus())) { + return R.fail(MessageUtils.message("auth.grant.type.blocked")); + } + // 校验租户 + loginService.checkTenant(loginBody.getTenantId()); + // 登录 + LoginVo loginVo = IAuthStrategy.login(body, client, grantType); + + Long userId = LoginHelper.getUserId(); + scheduledExecutorService.schedule(() -> { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage("欢迎登录新能源项目管理系统"); + dto.setUserIds(List.of(userId)); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); + return R.ok(loginVo); + } + + /** + * 获取跳转URL + * + * @param source 登录来源 + * @return 结果 + */ + @GetMapping("/binding/{source}") + public R authBinding(@PathVariable("source") String source, + @RequestParam String tenantId, @RequestParam String domain) { + SocialLoginConfigProperties obj = socialProperties.getType().get(source); + if (ObjectUtil.isNull(obj)) { + return R.fail(source + "平台账号暂不支持"); + } + AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties); + Map map = new HashMap<>(); + map.put("tenantId", tenantId); + map.put("domain", domain); + map.put("state", AuthStateUtils.createState()); + String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8)); + return R.ok("操作成功", authorizeUrl); + } + + /** + * 前端回调绑定授权(需要token) + * + * @param loginBody 请求体 + * @return 结果 + */ + @PostMapping("/social/callback") + public R socialCallback(@RequestBody SocialLoginBody loginBody) { + // 校验token + StpUtil.checkLogin(); + // 获取第三方登录信息 + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + AuthUser authUserData = response.getData(); + // 判断授权响应是否成功 + if (!response.ok()) { + return R.fail(response.getMsg()); + } + loginService.socialRegister(authUserData); + return R.ok(); + } + + + /** + * 取消授权(需要token) + * + * @param socialId socialId + */ + @DeleteMapping(value = "/unlock/{socialId}") + public R unlockSocial(@PathVariable Long socialId) { + // 校验token + StpUtil.checkLogin(); + Boolean rows = socialUserService.deleteWithValidById(socialId); + return rows ? R.ok() : R.fail("取消授权失败"); + } + + + /** + * 退出登录 + */ + @PostMapping("/logout") + public R logout() { + loginService.logout(); + return R.ok("退出成功"); + } + + /** + * 用户注册 + */ + @ApiEncrypt + @PostMapping("/register") + public R register(@Validated @RequestBody RegisterBody user) { + if (!configService.selectRegisterEnabled(user.getTenantId())) { + return R.fail("当前系统没有开启注册功能!"); + } + registerService.register(user); + return R.ok(); + } + + /** + * 登录页面租户下拉框 + * + * @return 租户列表 + */ + @GetMapping("/tenant/list") + public R tenantList(HttpServletRequest request) throws Exception { + // 返回对象 + LoginTenantVo result = new LoginTenantVo(); + boolean enable = TenantHelper.isEnable(); + result.setTenantEnabled(enable); + // 如果未开启租户这直接返回 + if (!enable) { + return R.ok(result); + } + + List tenantList = tenantService.queryList(new SysTenantBo()); + List voList = MapstructUtils.convert(tenantList, TenantListVo.class); + try { + // 如果只超管返回所有租户 + if (LoginHelper.isSuperAdmin()) { + result.setVoList(voList); + return R.ok(result); + } + } catch (NotLoginException ignored) { + } + + // 获取域名 + String host; + String referer = request.getHeader("referer"); + if (StringUtils.isNotBlank(referer)) { + // 这里从referer中取值是为了本地使用hosts添加虚拟域名,方便本地环境调试 + host = referer.split("//")[1].split("/")[0]; + } else { + host = new URL(request.getRequestURL().toString()).getHost(); + } + // 根据域名进行筛选 + List list = StreamUtils.filter(voList, vo -> + StringUtils.equalsIgnoreCase(vo.getDomain(), host)); + result.setVoList(CollUtil.isNotEmpty(list) ? list : voList); + return R.ok(result); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java new file mode 100644 index 0000000..1a476a9 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java @@ -0,0 +1,136 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.mail.config.properties.MailProperties; +import org.dromara.common.mail.utils.MailUtils; +import org.dromara.common.ratelimiter.annotation.RateLimiter; +import org.dromara.common.ratelimiter.enums.LimitType; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.common.web.enums.CaptchaType; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.web.domain.vo.CaptchaVo; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.Duration; +import java.util.LinkedHashMap; + +/** + * 验证码操作处理 + * + * @author Lion Li + */ +@SaIgnore +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +public class CaptchaController { + + private final CaptchaProperties captchaProperties; + private final MailProperties mailProperties; + + /** + * 短信验证码 + * + * @param phonenumber 用户手机号 + */ + @RateLimiter(key = "#phonenumber", time = 60, count = 1) + @GetMapping("/resource/sms/code") + public R smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { + String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + // 验证码模板id 自行处理 (查数据库或写死均可) + String templateId = ""; + LinkedHashMap map = new LinkedHashMap<>(1); + map.put("code", code); + SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); + SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map); + if (!smsResponse.isSuccess()) { + log.error("验证码短信发送异常 => {}", smsResponse); + return R.fail(smsResponse.getData().toString()); + } + return R.ok(); + } + + /** + * 邮箱验证码 + * + * @param email 邮箱 + */ + @RateLimiter(key = "#email", time = 60, count = 1) + @GetMapping("/resource/email/code") + public R emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { + if (!mailProperties.getEnabled()) { + return R.fail("当前系统没有开启邮箱功能!"); + } + String key = GlobalConstants.CAPTCHA_CODE_KEY + email; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + try { + MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。"); + } catch (Exception e) { + log.error("验证码短信发送异常 => {}", e.getMessage()); + return R.fail(e.getMessage()); + } + return R.ok(); + } + + /** + * 生成验证码 + */ + @RateLimiter(time = 60, count = 10, limitType = LimitType.IP) + @GetMapping("/auth/code") + public R getCode() { + CaptchaVo captchaVo = new CaptchaVo(); + boolean captchaEnabled = captchaProperties.getEnable(); + if (!captchaEnabled) { + captchaVo.setCaptchaEnabled(false); + return R.ok(captchaVo); + } + // 保存验证码信息 + String uuid = IdUtil.simpleUUID(); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; + // 生成验证码 + CaptchaType captchaType = captchaProperties.getType(); + boolean isMath = CaptchaType.MATH == captchaType; + Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); + CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); + AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); + captcha.setGenerator(codeGenerator); + captcha.createCode(); + // 如果是数学验证码,使用SpEL表达式处理验证码结果 + String code = captcha.getCode(); + if (isMath) { + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); + code = exp.getValue(String.class); + } + RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + captchaVo.setUuid(uuid); + captchaVo.setImg(captcha.getImageBase64()); + return R.ok(captchaVo); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java new file mode 100644 index 0000000..c444f28 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java @@ -0,0 +1,32 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import org.dromara.common.core.config.RuoYiConfig; +import org.dromara.common.core.utils.StringUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 首页 + * + * @author Lion Li + */ +@SaIgnore +@RequiredArgsConstructor +@RestController +public class IndexController { + + /** + * 系统基础配置 + */ + private final RuoYiConfig ruoyiConfig; + + /** + * 访问首页,提示语 + */ + @GetMapping("/") + public String index() { + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); + } +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java new file mode 100644 index 0000000..664df1e --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java @@ -0,0 +1,25 @@ +package org.dromara.web.domain.vo; + +import lombok.Data; + +/** + * 验证码信息 + * + * @author Michelle.Chung + */ +@Data +public class CaptchaVo { + + /** + * 是否开启验证码 + */ + private Boolean captchaEnabled = true; + + private String uuid; + + /** + * 验证码图片 + */ + private String img; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java new file mode 100644 index 0000000..0a83ace --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java @@ -0,0 +1,25 @@ +package org.dromara.web.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 登录租户对象 + * + * @author Michelle.Chung + */ +@Data +public class LoginTenantVo { + + /** + * 租户开关 + */ + private Boolean tenantEnabled; + + /** + * 租户对象列表 + */ + private List voList; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java new file mode 100644 index 0000000..834afe5 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java @@ -0,0 +1,54 @@ +package org.dromara.web.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 登录验证信息 + * + * @author Michelle.Chung + */ +@Data +public class LoginVo { + + /** + * 授权令牌 + */ + @JsonProperty("access_token") + private String accessToken; + + /** + * 刷新令牌 + */ + @JsonProperty("refresh_token") + private String refreshToken; + + /** + * 授权令牌 access_token 的有效期 + */ + @JsonProperty("expire_in") + private Long expireIn; + + /** + * 刷新令牌 refresh_token 的有效期 + */ + @JsonProperty("refresh_expire_in") + private Long refreshExpireIn; + + /** + * 应用id + */ + @JsonProperty("client_id") + private String clientId; + + /** + * 令牌权限 + */ + private String scope; + + /** + * 用户 openid + */ + private String openid; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java new file mode 100644 index 0000000..db9c271 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java @@ -0,0 +1,31 @@ +package org.dromara.web.domain.vo; + +import org.dromara.system.domain.vo.SysTenantVo; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +/** + * 租户列表 + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysTenantVo.class) +public class TenantListVo { + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 域名 + */ + private String domain; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java new file mode 100644 index 0000000..07595e0 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java @@ -0,0 +1,165 @@ +package org.dromara.web.listener; + +import cn.dev33.satoken.config.SaTokenConfig; +import cn.dev33.satoken.listener.SaTokenListener; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.domain.dto.UserOnlineDTO; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +/** + * 用户行为 侦听器的实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Component +@Slf4j +public class UserActionListener implements SaTokenListener { + + private final SaTokenConfig tokenConfig; + private final SysLoginService loginService; + + /** + * 每次登录时触发 + */ + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = ServletUtils.getClientIP(); + UserOnlineDTO dto = new UserOnlineDTO(); + dto.setIpaddr(ip); + dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + dto.setBrowser(userAgent.getBrowser().getName()); + dto.setOs(userAgent.getOs().getName()); + dto.setLoginTime(System.currentTimeMillis()); + dto.setTokenId(tokenValue); + String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY); + String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY); + dto.setUserName(username); + dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY)); + dto.setDeviceType(loginModel.getDevice()); + dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY)); + TenantHelper.dynamic(tenantId, () -> { + if(tokenConfig.getTimeout() == -1) { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); + } else { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); + } + }); + // 记录登录日志 + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(Constants.LOGIN_SUCCESS); + logininforEvent.setMessage(MessageUtils.message("user.login.success")); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + // 更新登录信息 + loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip); + log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次注销时触发 + */ + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被踢下线时触发 + */ + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被顶下线时触发 + */ + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被封禁时触发 + */ + @Override + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { + } + + /** + * 每次被解封时触发 + */ + @Override + public void doUntieDisable(String loginType, Object loginId, String service) { + } + + /** + * 每次打开二级认证时触发 + */ + @Override + public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCloseSafe(String loginType, String tokenValue, String service) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCreateSession(String id) { + } + + /** + * 每次注销Session时触发 + */ + @Override + public void doLogoutSession(String id) { + } + + /** + * 每次Token续期时触发 + */ + @Override + public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + } +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java new file mode 100644 index 0000000..a75b913 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java @@ -0,0 +1,46 @@ +package org.dromara.web.service; + + +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.web.domain.vo.LoginVo; + +/** + * 授权策略 + * + * @author Michelle.Chung + */ +public interface IAuthStrategy { + + String BASE_NAME = "AuthStrategy"; + + /** + * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @param grantType 授权类型 + * @return 登录验证信息 + */ + static LoginVo login(String body, SysClientVo client, String grantType) { + // 授权类型和客户端id + String beanName = grantType + BASE_NAME; + if (!SpringUtils.containsBean(beanName)) { + throw new ServiceException("授权类型不正确!"); + } + IAuthStrategy instance = SpringUtils.getBean(beanName); + return instance.login(body, client); + } + + /** + * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @return 登录验证信息 + */ + LoginVo login(String body, SysClientVo client); + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java new file mode 100644 index 0000000..41a802b --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -0,0 +1,251 @@ +package org.dromara.web.service; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Opt; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.lock.annotation.Lock4j; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthUser; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.dto.PostDTO; +import org.dromara.common.core.domain.dto.RoleDTO; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.*; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.exception.TenantException; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.*; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.Date; +import java.util.List; +import java.util.function.Supplier; + +/** + * 登录校验方法 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLoginService { + + @Value("${user.password.maxRetryCount}") + private Integer maxRetryCount; + + @Value("${user.password.lockTime}") + private Integer lockTime; + + private final ISysTenantService tenantService; + private final ISysPermissionService permissionService; + private final ISysSocialService sysSocialService; + private final ISysRoleService roleService; + private final ISysDeptService deptService; + private final ISysPostService postService; + private final SysUserMapper userMapper; + + + /** + * 绑定第三方用户 + * + * @param authUserData 授权响应实体 + */ + @Lock4j + public void socialRegister(AuthUser authUserData) { + String authId = authUserData.getSource() + authUserData.getUuid(); + // 第三方用户信息 + SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class); + BeanUtil.copyProperties(authUserData.getToken(), bo); + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + bo.setAuthId(authId); + bo.setOpenId(authUserData.getUuid()); + bo.setUserName(authUserData.getUsername()); + bo.setNickName(authUserData.getNickname()); + List checkList = sysSocialService.selectByAuthId(authId); + if (CollUtil.isNotEmpty(checkList)) { + throw new ServiceException("此三方账号已经被绑定!"); + } + // 查询是否已经绑定用户 + SysSocialBo params = new SysSocialBo(); + params.setUserId(userId); + params.setSource(bo.getSource()); + List list = sysSocialService.queryList(params); + if (CollUtil.isEmpty(list)) { + // 没有绑定用户, 新增用户信息 + sysSocialService.insertByBo(bo); + } else { + // 更新用户信息 + bo.setId(list.get(0).getId()); + sysSocialService.updateByBo(bo); + // 如果要绑定的平台账号已经被绑定过了 是否抛异常自行决断 + // throw new ServiceException("此平台账号已经被绑定!"); + } + } + + + /** + * 退出登录 + */ + public void logout() { + try { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + return; + } + if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { + // 超级管理员 登出清除动态租户 + TenantHelper.clearDynamic(); + } + recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + } catch (NotLoginException ignored) { + } finally { + try { + StpUtil.logout(); + } catch (NotLoginException ignored) { + } + } + } + + /** + * 记录登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + */ + public void recordLogininfor(String tenantId, String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + + /** + * 构建登录用户 + */ + public LoginUser buildLoginUser(SysUserVo user) { + LoginUser loginUser = new LoginUser(); + Long userId = user.getUserId(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(userId); + loginUser.setDeptId(user.getDeptId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setMenuPermission(permissionService.getMenuPermission(userId)); + loginUser.setRolePermission(permissionService.getRolePermission(userId)); + if (ObjectUtil.isNotNull(user.getDeptId())) { + Opt deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById); + loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); + loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); + } + List roles = roleService.selectRolesByUserId(userId); + List posts = postService.selectPostsByUserId(userId); + loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); + loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class)); + return loginUser; + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId, String ip) { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(ip); + sysUser.setLoginDate(DateUtils.getNowDate()); + sysUser.setUpdateBy(userId); + DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser)); + } + + /** + * 登录校验 + */ + public void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) { + String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; + String loginFail = Constants.LOGIN_FAIL; + + // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip) + int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); + // 锁定时间内登录 则踢出 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } + + if (supplier.get()) { + // 错误次数递增 + errorNumber++; + RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); + // 达到规定错误次数 则锁定登录 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } else { + // 未达到规定错误次数 + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); + throw new UserException(loginType.getRetryLimitCount(), errorNumber); + } + } + + // 登录成功 清空错误次数 + RedisUtils.deleteObject(errorKey); + } + + /** + * 校验租户 + * + * @param tenantId 租户ID + */ + public void checkTenant(String tenantId) { + if (!TenantHelper.isEnable()) { + return; + } + if (StringUtils.isBlank(tenantId)) { + throw new TenantException("tenant.number.not.blank"); + } + if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + return; + } + SysTenantVo tenant = tenantService.queryByTenantId(tenantId); + if (ObjectUtil.isNull(tenant)) { + log.info("登录租户:{} 不存在.", tenantId); + throw new TenantException("tenant.not.exists"); + } else if (SystemConstants.DISABLE.equals(tenant.getStatus())) { + log.info("登录租户:{} 已被停用.", tenantId); + throw new TenantException("tenant.blocked"); + } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) + && new Date().after(tenant.getExpireTime())) { + log.info("登录租户:{} 已超过有效期.", tenantId); + throw new TenantException("tenant.expired"); + } + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java new file mode 100644 index 0000000..c1e8300 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java @@ -0,0 +1,120 @@ +package org.dromara.web.service; + +import cn.dev33.satoken.secure.BCrypt; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.domain.model.RegisterBody; +import org.dromara.common.core.enums.UserType; +import org.dromara.common.core.exception.user.CaptchaException; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysUserService; +import org.springframework.stereotype.Service; + +/** + * 注册校验方法 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysRegisterService { + + private final ISysUserService userService; + private final SysUserMapper userMapper; + private final CaptchaProperties captchaProperties; + + /** + * 注册 + */ + public void register(RegisterBody registerBody) { + String tenantId = registerBody.getTenantId(); + String username = registerBody.getUsername(); + String password = registerBody.getPassword(); + // 校验用户类型是否存在 + String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); + // 校验密码是否符合要求 + String pattern = "^(?!.*\\s)(?!^[a-zA-Z]+$)(?!^[0-9]+$)(?!^[^a-zA-Z0-9]+$)(?!^[a-zA-Z0-9]+$).{8,18}$"; + boolean isValid = password.matches(pattern); + if (!isValid) { + throw new UserException("注册失败,密码需满足8–18位,包含大小写字母、数字、特殊字符中的至少三种组合"); + } + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); + } + SysUserBo sysUser = new SysUserBo(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPassword(BCrypt.hashpw(password)); + sysUser.setUserType(userType); + + boolean exist = TenantHelper.dynamic(tenantId, () -> { + return userMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getUserName, sysUser.getUserName())); + }); + if (exist) { + throw new UserException("user.register.save.error", username); + } + boolean regFlag = userService.registerUser(sysUser, tenantId); + if (!regFlag) { + throw new UserException("user.register.error"); + } + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + public void validateCaptcha(String tenantId, String username, String code, String uuid) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + /** + * 记录登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + * @return + */ + private void recordLogininfor(String tenantId, String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java new file mode 100644 index 0000000..1bed4f3 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.EmailLoginBody; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 邮件认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("email" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class EmailAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String email = loginBody.getEmail(); + String emailCode = loginBody.getEmailCode(); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByEmail(email); + loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验邮箱验证码 + */ + private boolean validateEmailCode(String tenantId, String email, String emailCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(emailCode); + } + + private SysUserVo loadUserByEmail(String email) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getEmail, email)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", email); + throw new UserException("user.not.exists", email); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", email); + throw new UserException("user.blocked", email); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java new file mode 100644 index 0000000..e8e60e1 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java @@ -0,0 +1,123 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.PasswordLoginBody; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaException; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 密码认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("password" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class PasswordAuthStrategy implements IAuthStrategy { + + private final CaptchaProperties captchaProperties; + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String username = loginBody.getUsername(); + String password = loginBody.getPassword(); + String code = loginBody.getCode(); + String uuid = loginBody.getUuid(); + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, code, uuid); + } + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByUsername(username); + loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); + // 此处可根据登录用户的数据不同 自行创建 loginUser + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + private void validateCaptcha(String tenantId, String username, String code, String uuid) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + private SysUserVo loadUserByUsername(String username) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, username)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", username); + throw new UserException("user.not.exists", username); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", username); + throw new UserException("user.blocked", username); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java new file mode 100644 index 0000000..2ffda35 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.SmsLoginBody; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 短信认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("sms" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SmsAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String phonenumber = loginBody.getPhonenumber(); + String smsCode = loginBody.getSmsCode(); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByPhonenumber(phonenumber); + loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验短信验证码 + */ + private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(smsCode); + } + + private SysUserVo loadUserByPhonenumber(String phonenumber) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getPhonenumber, phonenumber)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", phonenumber); + throw new UserException("user.not.exists", phonenumber); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", phonenumber); + throw new UserException("user.blocked", phonenumber); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java new file mode 100644 index 0000000..419dbd6 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java @@ -0,0 +1,131 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.http.Method; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.SocialLoginBody; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.social.config.properties.SocialProperties; +import org.dromara.common.social.utils.SocialUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysSocialService; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +/** + * 第三方授权策略 + * + * @author thiszhc is 三三 + */ +@Slf4j +@Service("social" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SocialAuthStrategy implements IAuthStrategy { + + private final SocialProperties socialProperties; + private final ISysSocialService sysSocialService; + private final SysUserMapper userMapper; + private final SysLoginService loginService; + + /** + * 登录-第三方授权登录 + * + * @param body 登录信息 + * @param client 客户端信息 + */ + @Override + public LoginVo login(String body, SysClientVo client) { + SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class); + ValidatorUtils.validate(loginBody); + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + if (!response.ok()) { + throw new ServiceException(response.getMsg()); + } + AuthUser authUserData = response.getData(); + if ("GITEE".equals(authUserData.getSource())) { + // 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖 + HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus") + .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) + .executeAsync(); + HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus") + .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) + .executeAsync(); + } + + List list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid()); + if (CollUtil.isEmpty(list)) { + throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!"); + } + SysSocialVo social; + if (TenantHelper.isEnable()) { + Optional opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId())); + if (opt.isEmpty()) { + throw new ServiceException("对不起,你没有权限登录当前租户!"); + } + social = opt.get(); + } else { + social = list.get(0); + } + LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> { + SysUserVo user = loadUser(social.getUserId()); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + private SysUserVo loadUser(Long userId) { + SysUserVo user = userMapper.selectVoById(userId); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", ""); + throw new UserException("user.not.exists", ""); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", ""); + throw new UserException("user.blocked", ""); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java new file mode 100644 index 0000000..fa9b618 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java @@ -0,0 +1,111 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.request.AuthWechatMiniProgramRequest; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.XcxLoginBody; +import org.dromara.common.core.domain.model.XcxLoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 小程序认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("xcx" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class XcxAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + + @Override + public LoginVo login(String body, SysClientVo client) { + XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class); + ValidatorUtils.validate(loginBody); + // xcxCode 为 小程序调用 wx.login 授权后获取 + String xcxCode = loginBody.getXcxCode(); + // 多个小程序识别使用 + String appid = loginBody.getAppid(); + + // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid + AuthRequest authRequest = new AuthWechatMiniProgramRequest(AuthConfig.builder() + .clientId(appid).clientSecret("自行填写密钥 可根据不同appid填入不同密钥") + .ignoreCheckRedirectUri(true).ignoreCheckState(true).build()); + AuthCallback authCallback = new AuthCallback(); + authCallback.setCode(xcxCode); + AuthResponse resp = authRequest.login(authCallback); + String openid, unionId; + if (resp.ok()) { + AuthToken token = resp.getData().getToken(); + openid = token.getOpenId(); + // 微信小程序只有关联到微信开放平台下之后才能获取到 unionId,因此unionId不一定能返回。 + unionId = token.getUnionId(); + } else { + throw new ServiceException(resp.getMsg()); + } + // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 + SysUserVo user = loadUserByOpenid(openid); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + XcxLoginUser loginUser = new XcxLoginUser(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(user.getUserId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + loginUser.setOpenid(openid); + + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + loginVo.setOpenid(openid); + return loginVo; + } + + private SysUserVo loadUserByOpenid(String openid) { + // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 + // todo 自行实现 userService.selectUserByOpenid(openid); + SysUserVo user = new SysUserVo(); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", openid); + // todo 用户不存在 业务逻辑自行实现 + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", openid); + // todo 用户已被停用 业务逻辑自行实现 + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml new file mode 100644 index 0000000..8dfb7a3 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -0,0 +1,290 @@ +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: false + url: http://192.168.110.119:9090/admin + instance: + service-host-type: IP + metadata: + username: ${spring.boot.admin.client.username} + userpassword: ${spring.boot.admin.client.password} + username: @monitor.username@ + password: @monitor.password@ + +--- # snail-job 配置 +snail-job: + enabled: false + # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group: "ruoyi_group" + # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表 + token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 192.168.110.119 + port: 17888 + # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 + namespace: ${spring.profiles.active} + # 随主应用端口漂移 + port: 2${server.port} + # 客户端ip指定 + host: + # RPC类型: netty, grpc + rpc-type: grpc + +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: true + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://192.168.110.2:13386/xinnengyuandev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: xinnengyuandev + password: StRWCZdZirysNSs2 + # # 从库数据源 + # slave: + # lazy: true + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: + # password: + # oracle: + # type: ${spring.datasource.type} + # driverClassName: oracle.jdbc.OracleDriver + # url: jdbc:oracle:thin:@//localhost:1521/XE + # username: ROOT + # password: root + # postgres: + # type: ${spring.datasource.type} + # driverClassName: org.postgresql.Driver + # url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true + # username: root + # password: root + # sqlserver: + # type: ${spring.datasource.type} + # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver + # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true + # username: SA + # password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 多久检查一次连接的活性 + keepaliveTime: 30000 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: 192.168.110.2 + # 端口,默认为6379 + port: 9287 + # 数据库索引 + database: 10 + # redis 密码必须配置 + password: syar23rdsaagdrsa + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: false + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true + # 发送方,遵循RFC-822标准 + from: xxx@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: xxx@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxxxxxxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 + +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 +sms: + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [ openid, email, phone, profile ] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab +# 和风天气 https://dev.qweather.com/ +weather: + key-id: T65EAABUXC + project-id: 2JTHPUQ5YY + private-key: MC4CAQAwBQYDK2VwBCIEIMAglX7IsxYiTeM+FXXnvCUsIggajeP4s8gAllewm6BN + api-host: n35rk53njv.re.qweatherapi.com +# dxf转 geojson 执行文件名 +dxf2GeoJson: + file-name: main.exe +ys7: + app-key: 3acf9f1a43dc4209841e0893003db0a2 + app-secret: 4bbf3e9394f55d3af6e3af27b2d3db36 +#ys7: +# app-key: 081b0d6d5f7f4de8bc5c7fa350fb26ec +# app-secret: caa37b9f60ef02deb57e563bc190e6db +# 斯巴达算法 +sparta: + url: http://119.3.204.120:8040 + client-id: test + client-secret: 115fcb08fa6742a1b086d9bb80a6ad59 +# 身份证加密密钥(32 位) +id-card: + encrypt-key: 7ae260d150a14027d2238a1cf80a48ef +recognizer: + url: http://192.168.110.5:50070 diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..7e1a9dc --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -0,0 +1,289 @@ +--- # 临时文件存储位置 避免临时文件被系统清理报错 +spring.servlet.multipart.location: /ruoyi/server/temp + +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: false + url: http://localhost:9090/admin + instance: + service-host-type: IP + metadata: + username: ${spring.boot.admin.client.username} + userpassword: ${spring.boot.admin.client.password} + username: @monitor.username@ + password: @monitor.password@ + +--- # snail-job 配置 +snail-job: + enabled: false + # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group: "ruoyi_group" + # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表 + token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 127.0.0.1 + port: 17888 + # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 + namespace: ${spring.profiles.active} + # 随主应用端口漂移 + port: 2${server.port} + # 客户端ip指定 + host: + # RPC类型: netty, grpc + rpc-type: grpc + +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: false + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://192.168.110.2:13386/xinnengyuan?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: xinnengyuan + password: mEZPC5Sdf3r2HENi + # # 从库数据源 + # slave: + # lazy: true + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: + # password: + # oracle: + # type: ${spring.datasource.type} + # driverClassName: oracle.jdbc.OracleDriver + # url: jdbc:oracle:thin:@//localhost:1521/XE + # username: ROOT + # password: root + # postgres: + # type: ${spring.datasource.type} + # driverClassName: org.postgresql.Driver + # url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true + # username: root + # password: root + # sqlserver: + # type: ${spring.datasource.type} + # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver + # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true + # username: SA + # password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 多久检查一次连接的活性 + keepaliveTime: 30000 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: 192.168.110.2 + # 端口,默认为6379 + port: 9287 + # 数据库索引 + database: 5 + # redis 密码必须配置 + password: syar23rdsaagdrsa + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: false + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true + # 发送方,遵循RFC-822标准 + from: xxx@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: xxx@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxxxxxxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 + +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 +sms: + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [ openid, email, phone, profile ] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab +# 和风天气 https://dev.qweather.com/ +weather: + key-id: T65EAABUXC + project-id: 2JTHPUQ5YY + private-key: MC4CAQAwBQYDK2VwBCIEIMAglX7IsxYiTeM+FXXnvCUsIggajeP4s8gAllewm6BN + api-host: n35rk53njv.re.qweatherapi.com +# dxf转 geojson 执行文件名 +dxf2GeoJson: + file-name: main +ys7: + app-key: 3acf9f1a43dc4209841e0893003db0a2 + app-secret: 4bbf3e9394f55d3af6e3af27b2d3db36 +# 斯巴达算法 +sparta: + url: http://119.3.204.120:8040 + client-id: test + client-secret: 115fcb08fa6742a1b086d9bb80a6ad59 +# 身份证加密密钥(32 位) +id-card: + encrypt-key: 7ae260d150a14027d2238a1cf80a48ef +recognizer: + url: http://192.168.110.5:50070 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml new file mode 100644 index 0000000..253717a --- /dev/null +++ b/ruoyi-admin/src/main/resources/application.yml @@ -0,0 +1,338 @@ +# 项目相关配置 +ruoyi: + # 名称 + name: RuoYi-Vue-Plus + # 版本 + version: ${revision} + # 版权年份 + copyrightYear: 2024 + +captcha: + enable: true + # 页面 <参数设置> 可开启关闭 验证码校验 + # 验证码类型 math 数组计算 char 字符验证 + type: MATH + # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 + category: CIRCLE + # 数字验证码位数 + numberLength: 1 + # 字符验证码长度 + charLength: 4 + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8899 + servlet: + # 应用的访问路径 + context-path: / + # undertow 配置 + undertow: + # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 + max-http-post-size: -1 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 + # 每块buffer的空间大小,越小的空间被利用越充分 + buffer-size: 512 + # 是否分配的直接内存 + direct-buffers: true + threads: + # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 + io: 8 + # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 + worker: 256 + +# 日志配置 +logging: + level: + org.dromara: @logging.level@ + org.springframework: warn + org.mybatis.spring.mapper: error + org.apache.fury: warn + config: classpath:logback-plus.xml + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 5 + # 密码锁定时间(默认10分钟) + lockTime: 10 + +# Spring配置 +spring: + application: + name: ${ruoyi.name} + threads: + # 开启虚拟线程 仅jdk21可用 + virtual: + enabled: false + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: @profiles.active@ + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 200MB + # 设置总上传的文件大小 + max-request-size: 200MB + mvc: + # 设置静态资源路径 防止所有请求都去查静态资源 + static-path-pattern: /static/** + format: + date-time: yyyy-MM-dd HH:mm:ss + jackson: + # 日期格式化 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + # 格式化输出 + indent_output: false + # 忽略无法转换的对象 + fail_on_empty_beans: false + deserialization: + # 允许对象忽略json中不存在的属性 + fail_on_unknown_properties: false + +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + +# security配置 +security: + # 排除路径 + excludes: + - /*.html + - /**/*.html + - /**/*.css + - /**/*.js + - /favicon.ico + - /error + - /*/api-docs + - /*/api-docs/** + - /warm-flow-ui/** + - /warm-flow/** + - /other/ys7Device/webhook + # todo 仅测试 + - /facility/matrix/** + - /**/changxie/callback/** + +# 多租户配置 +tenant: + # 是否开启 + enable: false + # 排除表 + excludes: + - sys_menu + - sys_tenant + - sys_tenant_package + - sys_role_dept + - sys_role_menu + - sys_user_post + - sys_user_role + - sys_client + - sys_oss_config + +# MyBatisPlus配置 +# https://baomidou.com/config/ +mybatis-plus: + # 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效 + enableLogicDelete: true + # 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper + mapperPackage: org.dromara.**.mapper,org.dromara.app.**.mapper + # 对应的 XML 文件位置 + mapperLocations: classpath*:mapper/**/*Mapper.xml,classpath*:mapper/app/**/*Mapper.xml + # 实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: org.dromara.**.domain,org.dromara.app.**.domain + global-config: + dbConfig: + # 主键类型 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID + # 如需改为自增 需要将数据库表全部设置为自增 + idType: ASSIGN_ID + +# 数据加密 +mybatis-encryptor: + # 是否开启加密 + enable: false + # 默认加密算法 + algorithm: BASE64 + # 编码方式 BASE64/HEX。默认BASE64 + encode: BASE64 + # 安全秘钥 对称算法的秘钥 如:AES,SM4 + password: + # 公私钥 非对称算法的公私钥 如:SM2,RSA + publicKey: + privateKey: + +# api接口加密 +api-decrypt: + # 是否开启全局接口加密 + enabled: true + # AES 加密头标识 + headerFlag: encrypt-key + # 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 + # 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= + publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ== + # 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 + # 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== + privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= + # cory 放行部分接口 + excluded-paths: + - /doc.html # 放行Swagger文档 + - /swagger-ui/** # 放行Swagger文档 + - /v3/api-docs/** # 放行OpenAPI文档 + - /actuator/** # 放行监控接口 + - /other/ys7Device/webhook # 放行萤石云设备回调接口 + - /auth/register # 放行注册接口 + +springdoc: + api-docs: + # 是否开启接口文档 + enabled: true + path: /v3/api-docs + info: + # 标题 + title: '标题:${ruoyi.name}多租户管理系统_接口文档' + # 描述 + description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' + # 版本 + version: '版本号: ${ruoyi.version}' + # 作者信息 + contact: + name: Lion Li + email: crazylionli@163.com + url: https://gitee.com/dromara/RuoYi-Vue-Plus + components: + # 鉴权方式配置 + security-schemes: + apiKey: + type: APIKEY + in: HEADER + name: ${sa-token.token-name} + #这里定义了两个分组,可定义多个,也可以不定义 + group-configs: + - group: 1.通用模块 + packages-to-scan: org.dromara.web + - group: 2.系统模块 + packages-to-scan: org.dromara.system + - group: 3.项目模块 + packages-to-scan: org.dromara.project + - group: 4.材料模块 + packages-to-scan: org.dromara.materials + - group: 5.机械模块 + packages-to-scan: org.dromara.machinery + - group: 6.安全模块 + packages-to-scan: org.dromara.safety + - group: 7.质量模块 + packages-to-scan: org.dromara.quality + - group: 8.设施模块 + packages-to-scan: org.dromara.facility + - group: 9.进度模块 + packages-to-scan: org.dromara.progress + - group: 10.其他模块 + packages-to-scan: org.dromara.other + - group: 11.分包模块 + packages-to-scan: org.dromara.contractor + - group: 12.设计模块 + packages-to-scan: org.dromara.design + - group: 13.工作流模块 + packages-to-scan: org.dromara.workflow + - group: 14.罗成模块 + packages-to-scan: org.dromara.cory + - group: 15.无人机模块 + packages-to-scan: org.dromara.drone + - group: 20.代码生成模块 + packages-to-scan: org.dromara.generator + - group: 16.app模块 + packages-to-scan: org.dromara.app +# knife4j的增强配置,不需要增强可以不配 +knife4j: + enable: true + setting: + language: zh_cn + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludeUrls: + - /system/notice + - /warm-flow/save-xml + +# 全局线程池相关配置 +# 如使用JDK21请直接使用虚拟线程 不要开启此配置 +thread-pool: + # 是否开启线程池 + enabled: false + # 队列最大长度 + queueCapacity: 128 + # 线程池维护线程所允许的空闲时间 + keepAliveSeconds: 300 + +--- # 分布式锁 lock4j 全局配置 +lock4j: + # 获取分布式锁超时时间,默认为 3000 毫秒 + acquire-timeout: 3000 + # 分布式锁的超时时间,默认为 30 秒 + expire: 30000 + +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: ALWAYS + logfile: + external-file: ./logs/sys-console.log + +--- # 默认/推荐使用sse推送 +sse: + enabled: true + path: /resource/sse + +--- # websocket +websocket: + # 如果关闭 需要和前端开关一起关闭 + enabled: false + # 路径 + path: /resource/websocket + # 设置访问源地址 + allowedOrigins: '*' + +--- # warm-flow工作流配置 +warm-flow: + # 是否开启工作流,默认true + enabled: true + # 是否开启设计器ui + ui: true + # 默认Authorization,如果有多个token,用逗号分隔 + token-name: ${sa-token.token-name},clientid + # 流程状态对应的三元色 + chart-status-color: + ## 未办理 + - 62,62,62 + ## 待办理 + - 255,205,23 + ## 已办理 + - 157,255,0 + + +--- # 百度云配置 +baidu: + client: + id: zSB7KdLgY7a1tIEx3eTy65TE + secret: 5nabjclW5BWGV8UwEueDgBDmOveRVkmD diff --git a/ruoyi-admin/src/main/resources/banner.txt b/ruoyi-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..21b1126 --- /dev/null +++ b/ruoyi-admin/src/main/resources/banner.txt @@ -0,0 +1,8 @@ +Application Version: ${revision} +Spring Boot Version: ${spring-boot.version} +__________ _____.___.__ ____ ____ __________.__ +\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______ + | _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/ + | | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \ + |____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ > + \/ \/ \/ \/ diff --git a/ruoyi-admin/src/main/resources/favicon.ico b/ruoyi-admin/src/main/resources/favicon.ico new file mode 100644 index 0000000..3f919d8 Binary files /dev/null and b/ruoyi-admin/src/main/resources/favicon.ico differ diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..cce11c8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,61 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +auth.grant.type.error=认证权限类型错误 +auth.grant.type.blocked=认证权限类型已禁用 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序[code]不能为空 +social.source.not.blank=第三方登录平台[source]不能为空 +social.code.not.blank=第三方登录平台[code]不能为空 +social.state.not.blank=第三方登录平台[state]不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..f948c4a --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,61 @@ +#错误消息 +not.null=* Required fill in +user.jcaptcha.error=Captcha error +user.jcaptcha.expire=Captcha invalid +user.not.exists=Sorry, your account: {0} does not exist +user.password.not.match=User does not exist/Password error +user.password.retry.limit.count=Password input error {0} times +user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes +user.password.delete=Sorry, your account:{0} has been deleted +user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator +role.blocked=Role disabled,please contact administrators +user.logout.success=Exit successful +length.not.valid=The length must be between {min} and {max} characters +user.username.not.blank=Username cannot be blank +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number +user.username.length.valid=Account length must be between {min} and {max} characters +user.password.not.blank=Password cannot be empty +user.password.length.valid=Password length must be between {min} and {max} characters +user.password.not.valid=* 5-50 characters +user.email.not.valid=Mailbox format error +user.email.not.blank=Mailbox cannot be blank +user.phonenumber.not.blank=Phone number cannot be blank +user.mobile.phone.number.not.valid=Phone number format error +user.login.success=Login successful +user.register.success=Register successful +user.register.save.error=Failed to save user {0}, The registered account already exists +user.register.error=Register failed, please contact system administrator +user.notfound=Please login again +user.forcelogout=The administrator is forced to exit,please login again +user.unknown.error=Unknown error, please login again +auth.grant.type.error=Auth grant type error +auth.grant.type.blocked=Auth grant type disabled +auth.grant.type.not.blank=Auth grant type cannot be blank +auth.clientid.not.blank=Auth clientid cannot be blank +##文件上传消息 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!
the maximum allowed file size is:{0}MB! +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters +##权限 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] +repeat.submit.message=Repeat submit is not allowed, please try again later +rate.limiter.message=Visit too frequently, please try again later +sms.code.not.blank=Sms code cannot be blank +sms.code.retry.limit.count=Sms code input error {0} times +sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes +email.code.not.blank=Email code cannot be blank +email.code.retry.limit.count=Email code input error {0} times +email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes +xcx.code.not.blank=Mini program [code] cannot be blank +social.source.not.blank=Social login platform [source] cannot be blank +social.code.not.blank=Social login platform [code] cannot be blank +social.state.not.blank=Social login platform [state] cannot be blank +##租户 +tenant.number.not.blank=Tenant number cannot be blank +tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator +tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator +tenant.expired=Sorry, your tenant has expired. Please contact the administrator. diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..cce11c8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,61 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +auth.grant.type.error=认证权限类型错误 +auth.grant.type.blocked=认证权限类型已禁用 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序[code]不能为空 +social.source.not.blank=第三方登录平台[source]不能为空 +social.code.not.blank=第三方登录平台[code]不能为空 +social.state.not.blank=第三方登录平台[state]不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-admin/src/main/resources/ip2region.xdb b/ruoyi-admin/src/main/resources/ip2region.xdb new file mode 100644 index 0000000..7052c05 Binary files /dev/null and b/ruoyi-admin/src/main/resources/ip2region.xdb differ diff --git a/ruoyi-admin/src/main/resources/logback-plus.xml b/ruoyi-admin/src/main/resources/logback-plus.xml new file mode 100644 index 0000000..b74289e --- /dev/null +++ b/ruoyi-admin/src/main/resources/logback-plus.xml @@ -0,0 +1,129 @@ + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + ${log.path}/sys-console.log + + + ${log.path}/sys-console.%d{yyyy-MM-dd}.log + + 1 + + + ${log.pattern} + utf-8 + + + + INFO + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + 0 + + 512 + + + + + + + + 0 + + 512 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/template/安全生产监督检查通知书模版.docx b/ruoyi-admin/src/main/resources/template/安全生产监督检查通知书模版.docx new file mode 100644 index 0000000..d46710a Binary files /dev/null and b/ruoyi-admin/src/main/resources/template/安全生产监督检查通知书模版.docx differ diff --git a/ruoyi-admin/src/main/resources/template/整改通知单模版.docx b/ruoyi-admin/src/main/resources/template/整改通知单模版.docx new file mode 100644 index 0000000..194fea9 Binary files /dev/null and b/ruoyi-admin/src/main/resources/template/整改通知单模版.docx differ diff --git a/ruoyi-admin/src/main/resources/template/施工日志模版.docx b/ruoyi-admin/src/main/resources/template/施工日志模版.docx new file mode 100644 index 0000000..ad16350 Binary files /dev/null and b/ruoyi-admin/src/main/resources/template/施工日志模版.docx differ diff --git a/ruoyi-admin/src/main/resources/template/物料接收单模版.docx b/ruoyi-admin/src/main/resources/template/物料接收单模版.docx new file mode 100644 index 0000000..5c54f75 Binary files /dev/null and b/ruoyi-admin/src/main/resources/template/物料接收单模版.docx differ diff --git a/ruoyi-admin/src/main/resources/template/物料领料单模版.docx b/ruoyi-admin/src/main/resources/template/物料领料单模版.docx new file mode 100644 index 0000000..0ff4f48 Binary files /dev/null and b/ruoyi-admin/src/main/resources/template/物料领料单模版.docx differ diff --git a/ruoyi-admin/src/main/resources/template/设计变更申请单模版.docx b/ruoyi-admin/src/main/resources/template/设计变更申请单模版.docx new file mode 100644 index 0000000..d41672e Binary files /dev/null and b/ruoyi-admin/src/main/resources/template/设计变更申请单模版.docx differ diff --git a/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java new file mode 100644 index 0000000..dba2323 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java @@ -0,0 +1,45 @@ +package org.dromara.test; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * 断言单元测试案例 + * + * @author Lion Li + */ +@DisplayName("断言单元测试案例") +public class AssertUnitTest { + + @DisplayName("测试 assertEquals 方法") + @Test + public void testAssertEquals() { + Assertions.assertEquals("666", new String("666")); + Assertions.assertNotEquals("666", new String("666")); + } + + @DisplayName("测试 assertSame 方法") + @Test + public void testAssertSame() { + Object obj = new Object(); + Object obj1 = obj; + Assertions.assertSame(obj, obj1); + Assertions.assertNotSame(obj, obj1); + } + + @DisplayName("测试 assertTrue 方法") + @Test + public void testAssertTrue() { + Assertions.assertTrue(true); + Assertions.assertFalse(true); + } + + @DisplayName("测试 assertNull 方法") + @Test + public void testAssertNull() { + Assertions.assertNull(null); + Assertions.assertNotNull(null); + } + +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/CmdTest.java b/ruoyi-admin/src/test/java/org/dromara/test/CmdTest.java new file mode 100644 index 0000000..ba0258c --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/CmdTest.java @@ -0,0 +1,64 @@ +package org.dromara.test; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/23 10:15 + */ +@SpringBootTest +public class CmdTest { + + @Test + public void test() { + // 获取当前项目根目录 + String projectRoot = System.getProperty("user.dir"); + // EXE 和参数 + String exePath = projectRoot + File.separator + "file" + File.separator + "resource" + File.separator + "dxf" + File.separator + "main.exe"; + String inputDXF = "file/resource/dxf/1897160897167638529/桩点图.dxf"; + String outputJSON = "file/resource/dxf/1897160897167638529/output.json"; + String sourceEPSG = "4524"; + String targetEPSG = "4326"; + + // 构造命令行 + List command = Arrays.asList( + exePath, + inputDXF, + outputJSON, + sourceEPSG, + targetEPSG + ); + + ProcessBuilder builder = new ProcessBuilder(command); + builder.redirectErrorStream(true); // 合并标准错误和输出 + + try { + Process process = builder.start(); + + // 读取输出 + BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream(), "GBK") + ); + String line; + System.out.println("程序输出:"); + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + + int exitCode = process.waitFor(); + System.out.println("程序退出码:" + exitCode); + + reader.close(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/DemoTest.java b/ruoyi-admin/src/test/java/org/dromara/test/DemoTest.java new file mode 100644 index 0000000..2de8ccb --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/DemoTest.java @@ -0,0 +1,92 @@ +package org.dromara.test; + +import cn.hutool.core.io.FileUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.design.service.IDesTechnicalStandardService; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.facility.service.IFacPhotovoltaicPanelPartsService; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.service.ISysDeptService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/30 9:48 + */ +@Slf4j +@SpringBootTest +public class DemoTest { + + @Resource + private IFacPhotovoltaicPanelPartsService photovoltaicPanelPartsService; + + @Resource + private IPgsProgressCategoryService progressCategoryService; + + @Resource + private IFacMatrixService matrixService; + + @Resource + private IBusProjectService projectService; + + @Resource + private IDesTechnicalStandardService desTechnicalStandardService; + + @Resource + private ISysDeptService deptService; + + @Test + void test() { + Boolean result = photovoltaicPanelPartsService + .updatePartsFinishStatus( + "14", + new Date(), + 1897160897167638529L, + 1927270270872109058L, + List.of("G01.01.01", "G01.08.06") + ); + } + + @Test + void testProjectSync() { + Long id = 1897160897167638529L; +/* projectService.insertProjectSyncThing(id) + .thenAccept(result -> log.info("项目异步执行数据同步成功")) + .exceptionally(ex -> { + log.error("项目异步执行数据同步失败", ex); + return null; + });*/ + Boolean saveTechnicalStandard = desTechnicalStandardService.insertFolderByTemplate(id); + if (!saveTechnicalStandard) { + log.error("同步数据失败,项目[{}]新增技术标准管理文件夹模版失败", id); + } + } + + @Test + void testMethod() { + String originalFilename = "test"; + String suffix = FileUtil.getSuffix(originalFilename); + System.out.println(suffix); + } + + @Test + void testTemple() { + List matrixList = matrixService.lambdaQuery() + .eq(FacMatrix::getProjectId, 1906557369562726402L) + .list(); + Boolean result = progressCategoryService.insertByTemplate(1906557369562726402L, matrixList, null); + } + + @Test + void testDeptProject() { + deptService.selectProjectIdById(100L); + deptService.selectProjectIdById(1937478258803171329L); + } +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java new file mode 100644 index 0000000..5b3dfdc --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java @@ -0,0 +1,70 @@ +package org.dromara.test; + +import org.dromara.common.core.config.RuoYiConfig; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.concurrent.TimeUnit; + +/** + * 单元测试案例 + * + * @author Lion Li + */ +@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件 +@DisplayName("单元测试案例") +public class DemoUnitTest { + + @Autowired + private RuoYiConfig ruoYiConfig; + + @DisplayName("测试 @SpringBootTest @Test @DisplayName 注解") + @Test + public void testTest() { + System.out.println(ruoYiConfig); + } + + @Disabled + @DisplayName("测试 @Disabled 注解") + @Test + public void testDisabled() { + System.out.println(ruoYiConfig); + } + + @Timeout(value = 2L, unit = TimeUnit.SECONDS) + @DisplayName("测试 @Timeout 注解") + @Test + public void testTimeout() throws InterruptedException { + Thread.sleep(3000); + System.out.println(ruoYiConfig); + } + + + @DisplayName("测试 @RepeatedTest 注解") + @RepeatedTest(3) + public void testRepeatedTest() { + System.out.println(666); + } + + @BeforeAll + public static void testBeforeAll() { + System.out.println("@BeforeAll =================="); + } + + @BeforeEach + public void testBeforeEach() { + System.out.println("@BeforeEach =================="); + } + + @AfterEach + public void testAfterEach() { + System.out.println("@AfterEach =================="); + } + + @AfterAll + public static void testAfterAll() { + System.out.println("@AfterAll =================="); + } + +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/PDFTest.java b/ruoyi-admin/src/test/java/org/dromara/test/PDFTest.java new file mode 100644 index 0000000..0316902 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/PDFTest.java @@ -0,0 +1,39 @@ +package org.dromara.test; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.utils.PdfBoxQrCodeGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/7/7 10:13 + */ +@Slf4j +@SpringBootTest +public class PDFTest { + + @Test + void test() { + String srcPdf = "http://58.17.134.85:9000/xinnengyuan-dev/2025/07/07/146cb913cb4841eb9944463b762cba53.pdf"; // 原始PDF + String destPdf = "output.pdf"; // 输出PDF + Map params = new HashMap<>(); + params.put("版本:", "1.0"); + params.put("文件名:", "绝对哦啊手机号丢啊"); + params.put("文件类型:", "蓝图"); + String qrText = "fdas:1.0 das:asd sad:dsa"; + String qrPath = "qrcode.png"; + + byte[] bytes = PdfBoxQrCodeGenerator.generateQRCodeBytes(qrText, 200, 200); + try { + PdfBoxQrCodeGenerator.addQRCodeToPDF(srcPdf, destPdf, bytes, 1, 1510, 900); // 页码从1开始,坐标单位是 pt(约1/72英寸) + } catch (Exception e) { + e.printStackTrace(); + } + + System.out.println("二维码添加成功!"); + } +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java new file mode 100644 index 0000000..1db51df --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java @@ -0,0 +1,72 @@ +package org.dromara.test; + +import org.dromara.common.core.enums.UserType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +/** + * 带参数单元测试案例 + * + * @author Lion Li + */ +@DisplayName("带参数单元测试案例") +public class ParamUnitTest { + + @DisplayName("测试 @ValueSource 注解") + @ParameterizedTest + @ValueSource(strings = {"t1", "t2", "t3"}) + public void testValueSource(String str) { + System.out.println(str); + } + + @DisplayName("测试 @NullSource 注解") + @ParameterizedTest + @NullSource + public void testNullSource(String str) { + System.out.println(str); + } + + @DisplayName("测试 @EnumSource 注解") + @ParameterizedTest + @EnumSource(UserType.class) + public void testEnumSource(UserType type) { + System.out.println(type.getUserType()); + } + + @DisplayName("测试 @MethodSource 注解") + @ParameterizedTest + @MethodSource("getParam") + public void testMethodSource(String str) { + System.out.println(str); + } + + public static Stream getParam() { + List list = new ArrayList<>(); + list.add("t1"); + list.add("t2"); + list.add("t3"); + return list.stream(); + } + + @BeforeEach + public void testBeforeEach() { + System.out.println("@BeforeEach =================="); + } + + @AfterEach + public void testAfterEach() { + System.out.println("@AfterEach =================="); + } + + +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/RecognizerTest.java b/ruoyi-admin/src/test/java/org/dromara/test/RecognizerTest.java new file mode 100644 index 0000000..fb8215e --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/RecognizerTest.java @@ -0,0 +1,29 @@ +package org.dromara.test; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.manager.recognizermanager.RecognizerManager; +import org.dromara.manager.recognizermanager.enums.RecognizerTypeEnum; +import org.dromara.manager.recognizermanager.vo.RecognizeVo; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/21 11:35 + */ +@Slf4j +@SpringBootTest +public class RecognizerTest { + + @Resource + private RecognizerManager recognizerManager; + + @Test + void test() { + RecognizeVo recognize = recognizerManager.recognize("http://xny.yj-3d.com:7363/file/tif/20250625160218orthophoto.png", List.of(RecognizerTypeEnum.PHO)); + log.info("recognize: {}", recognize); + } +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java new file mode 100644 index 0000000..b50afa6 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java @@ -0,0 +1,54 @@ +package org.dromara.test; + +import org.junit.jupiter.api.*; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * 标签单元测试案例 + * + * @author Lion Li + */ +@SpringBootTest +@DisplayName("标签单元测试案例") +public class TagUnitTest { + + @Tag("dev") + @DisplayName("测试 @Tag dev") + @Test + public void testTagDev() { + System.out.println("dev"); + } + + @Tag("prod") + @DisplayName("测试 @Tag prod") + @Test + public void testTagProd() { + System.out.println("prod"); + } + + @Tag("local") + @DisplayName("测试 @Tag local") + @Test + public void testTagLocal() { + System.out.println("local"); + } + + @Tag("exclude") + @DisplayName("测试 @Tag exclude") + @Test + public void testTagExclude() { + System.out.println("exclude"); + } + + @BeforeEach + public void testBeforeEach() { + System.out.println("@BeforeEach =================="); + } + + @AfterEach + public void testAfterEach() { + System.out.println("@AfterEach =================="); + } + + +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/ViolationRecordTest.java b/ruoyi-admin/src/test/java/org/dromara/test/ViolationRecordTest.java new file mode 100644 index 0000000..6d407e6 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/ViolationRecordTest.java @@ -0,0 +1,58 @@ +package org.dromara.test; + +import jakarta.annotation.Resource; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateDto; +import org.dromara.safety.service.IHseViolationRecordService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/22 15:36 + */ +@SpringBootTest +public class ViolationRecordTest { + + @Resource + private IHseViolationRecordService violationRecordService; + + @Test + void test() { + List list = new ArrayList<>(); + HseViolationRecordCreateDto dto1 = new HseViolationRecordCreateDto(); + dto1.setProjectId(1897160897167638529L); + dto1.setRecognizeId(1937451365735419905L); + dto1.setViolationType("3"); + dto1.setViolationTime(new Date()); + list.add(dto1); + HseViolationRecordCreateDto dto2 = new HseViolationRecordCreateDto(); + dto2.setProjectId(1897160897167638529L); + dto2.setRecognizeId(1937451365735419906L); + dto2.setViolationType("1,2,3"); + dto2.setViolationTime(new Date()); + list.add(dto2); + HseViolationRecordCreateDto dto3 = new HseViolationRecordCreateDto(); + dto3.setProjectId(1897160897167638529L); + dto3.setRecognizeId(1937451365735419907L); + dto3.setViolationType("2,7,8"); + dto3.setViolationTime(new Date()); + list.add(dto3); + HseViolationRecordCreateDto dto4 = new HseViolationRecordCreateDto(); + dto4.setProjectId(1897160897167638529L); + dto4.setRecognizeId(1937451365735419908L); + dto4.setViolationType("5,8"); + dto4.setViolationTime(new Date()); + list.add(dto4); + HseViolationRecordCreateDto dto5 = new HseViolationRecordCreateDto(); + dto5.setProjectId(1897160897167638529L); + dto5.setRecognizeId(1937451365735419909L); + dto5.setViolationType("3,9"); + dto5.setViolationTime(new Date()); + list.add(dto5); + violationRecordService.insertByMonitor(list); + } +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/Ys7Test.java b/ruoyi-admin/src/test/java/org/dromara/test/Ys7Test.java new file mode 100644 index 0000000..379b069 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/Ys7Test.java @@ -0,0 +1,37 @@ +package org.dromara.test; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.manager.ys7manager.Ys7Manager; +import org.dromara.manager.ys7manager.Ys7RequestUtils; +import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/12 17:06 + */ +@Slf4j +@SpringBootTest +public class Ys7Test { + + @Resource + private Ys7Manager ys7Manager; + + @Test + void test() { + String token = ys7Manager.getToken(); + List ys7QueryDeviceResponseVos = Ys7RequestUtils.queryDeviceVoList(token, 1, 20); + System.out.println(ys7QueryDeviceResponseVos); + } + + @Test + void testCaptureDevicePic() { + String pic = ys7Manager.getCaptureDevicePic("AE9470016", 1, 1); + System.out.println(pic); + } + +} diff --git a/ruoyi-admin/zhFonts/.uuid b/ruoyi-admin/zhFonts/.uuid new file mode 100644 index 0000000..cee5cdd --- /dev/null +++ b/ruoyi-admin/zhFonts/.uuid @@ -0,0 +1 @@ +3f2ee348-0303-40ca-bf03-03f48d2d2141 \ No newline at end of file diff --git a/ruoyi-admin/zhFonts/SIMSUN.TTC b/ruoyi-admin/zhFonts/SIMSUN.TTC new file mode 100644 index 0000000..6ca8de3 Binary files /dev/null and b/ruoyi-admin/zhFonts/SIMSUN.TTC differ diff --git a/ruoyi-admin/zhFonts/fonts.dir b/ruoyi-admin/zhFonts/fonts.dir new file mode 100644 index 0000000..fed9544 --- /dev/null +++ b/ruoyi-admin/zhFonts/fonts.dir @@ -0,0 +1,4 @@ +3 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r diff --git a/ruoyi-admin/zhFonts/fonts.scale b/ruoyi-admin/zhFonts/fonts.scale new file mode 100644 index 0000000..fed9544 --- /dev/null +++ b/ruoyi-admin/zhFonts/fonts.scale @@ -0,0 +1,4 @@ +3 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml new file mode 100644 index 0000000..a3b8bfb --- /dev/null +++ b/ruoyi-common/pom.xml @@ -0,0 +1,47 @@ + + + + xinnengyuan + org.dromara + ${revision} + + 4.0.0 + + + ruoyi-common-bom + ruoyi-common-social + ruoyi-common-core + ruoyi-common-doc + ruoyi-common-excel + ruoyi-common-idempotent + ruoyi-common-job + ruoyi-common-log + ruoyi-common-mail + ruoyi-common-mybatis + ruoyi-common-oss + ruoyi-common-ratelimiter + ruoyi-common-redis + ruoyi-common-satoken + ruoyi-common-security + ruoyi-common-sms + ruoyi-common-web + ruoyi-common-translation + ruoyi-common-sensitive + ruoyi-common-json + ruoyi-common-encrypt + ruoyi-common-tenant + ruoyi-common-websocket + ruoyi-common-sse + ruoyi-common-jts + + + ruoyi-common + pom + + + common 通用模块 + + + diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml new file mode 100644 index 0000000..547640f --- /dev/null +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -0,0 +1,192 @@ + + + 4.0.0 + + org.dromara + ruoyi-common-bom + ${revision} + pom + + + ruoyi-common-bom common依赖项 + + + + 5.3.0 + + + + + + + org.dromara + ruoyi-common-core + ${revision} + + + + + org.dromara + ruoyi-common-doc + ${revision} + + + + + org.dromara + ruoyi-common-excel + ${revision} + + + + + org.dromara + ruoyi-common-idempotent + ${revision} + + + + + org.dromara + ruoyi-common-job + ${revision} + + + + + org.dromara + ruoyi-common-log + ${revision} + + + + + org.dromara + ruoyi-common-mail + ${revision} + + + + + org.dromara + ruoyi-common-mybatis + ${revision} + + + + + org.dromara + ruoyi-common-oss + ${revision} + + + + + org.dromara + ruoyi-common-ratelimiter + ${revision} + + + + + org.dromara + ruoyi-common-redis + ${revision} + + + + + org.dromara + ruoyi-common-satoken + ${revision} + + + + + org.dromara + ruoyi-common-security + ${revision} + + + + + org.dromara + ruoyi-common-sms + ${revision} + + + + org.dromara + ruoyi-common-social + ${revision} + + + + + org.dromara + ruoyi-common-web + ${revision} + + + + + org.dromara + ruoyi-common-translation + ${revision} + + + + + org.dromara + ruoyi-common-sensitive + ${revision} + + + + + org.dromara + ruoyi-common-json + ${revision} + + + + + org.dromara + ruoyi-common-encrypt + ${revision} + + + + + org.dromara + ruoyi-common-tenant + ${revision} + + + + + org.dromara + ruoyi-common-websocket + ${revision} + + + + + org.dromara + ruoyi-common-sse + ${revision} + + + + + org.dromara + ruoyi-common-jts + ${revision} + + + + + + diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml new file mode 100644 index 0000000..ad37e90 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -0,0 +1,99 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-core + + + ruoyi-common-core 核心模块 + + + + + + org.springframework + spring-context-support + + + + + org.springframework + spring-web + + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.apache.commons + commons-lang3 + + + + + jakarta.servlet + jakarta.servlet-api + + + + cn.hutool + hutool-core + + + + cn.hutool + hutool-http + + + + cn.hutool + hutool-extra + + + + org.projectlombok + lombok + + + + + org.springframework.boot + spring-boot-configuration-processor + + + + org.springframework.boot + spring-boot-properties-migrator + runtime + + + + io.github.linpeilie + mapstruct-plus-spring-boot-starter + + + + + org.lionsoul + ip2region + + + + + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java new file mode 100644 index 0000000..d9f70e4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java @@ -0,0 +1,17 @@ +package org.dromara.common.core.config; + +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableAsync; + +/** + * 程序注解配置 + * + * @author Lion Li + */ +@AutoConfiguration +@EnableAspectJAutoProxy +@EnableAsync(proxyTargetClass = true) +public class ApplicationConfig { + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java new file mode 100644 index 0000000..cd01e33 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java @@ -0,0 +1,52 @@ +package org.dromara.common.core.config; + +import cn.hutool.core.util.ArrayUtil; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.core.task.VirtualThreadTaskExecutor; +import org.springframework.scheduling.annotation.AsyncConfigurer; + +import java.util.Arrays; +import java.util.concurrent.Executor; + +/** + * 异步配置 + *

+ * 如果未使用虚拟线程则生效 + * + * @author Lion Li + */ +@AutoConfiguration +public class AsyncConfig implements AsyncConfigurer { + + /** + * 自定义 @Async 注解使用系统线程池 + */ + @Override + public Executor getAsyncExecutor() { + if(SpringUtils.isVirtual()) { + return new VirtualThreadTaskExecutor("async-"); + } + return SpringUtils.getBean("scheduledExecutorService"); + } + + /** + * 异步执行异常处理 + */ + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + throwable.printStackTrace(); + StringBuilder sb = new StringBuilder(); + sb.append("Exception message - ").append(throwable.getMessage()) + .append(", Method name - ").append(method.getName()); + if (ArrayUtil.isNotEmpty(objects)) { + sb.append(", Parameter value - ").append(Arrays.toString(objects)); + } + throw new ServiceException(sb.toString()); + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java new file mode 100644 index 0000000..cc0d2df --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java @@ -0,0 +1,33 @@ +package org.dromara.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 读取项目相关配置 + * + * @author Lion Li + */ + +@Data +@Component +@ConfigurationProperties(prefix = "ruoyi") +public class RuoYiConfig { + + /** + * 项目名称 + */ + private String name; + + /** + * 版本 + */ + private String version; + + /** + * 版权年份 + */ + private String copyrightYear; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java new file mode 100644 index 0000000..2630485 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java @@ -0,0 +1,87 @@ +package org.dromara.common.core.config; + +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.dromara.common.core.config.properties.ThreadPoolProperties; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.Threads; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.core.task.VirtualThreadTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 线程池配置 + * + * @author Lion Li + **/ +@Slf4j +@AutoConfiguration +@EnableConfigurationProperties(ThreadPoolProperties.class) +public class ThreadPoolConfig { + + /** + * 核心线程数 = cpu 核心数 + 1 + */ + private final int core = Runtime.getRuntime().availableProcessors() + 1; + + private ScheduledExecutorService scheduledExecutorService; + + @Bean(name = "threadPoolTaskExecutor") + @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") + public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(core); + executor.setMaxPoolSize(core * 2); + executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); + executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() { + // daemon 必须为 true + BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder().daemon(true); + if (SpringUtils.isVirtual()) { + builder.namingPattern("virtual-schedule-pool-%d").wrappedFactory(new VirtualThreadTaskExecutor().getVirtualThreadFactory()); + } else { + builder.namingPattern("schedule-pool-%d"); + } + ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core, + builder.build(), + new ThreadPoolExecutor.CallerRunsPolicy()) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + Threads.printException(r, t); + } + }; + this.scheduledExecutorService = scheduledThreadPoolExecutor; + return scheduledThreadPoolExecutor; + } + + /** + * 销毁事件 + */ + @PreDestroy + public void destroy() { + try { + log.info("====关闭后台任务任务线程池===="); + Threads.shutdownAndAwaitTermination(scheduledExecutorService); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java new file mode 100644 index 0000000..45c5bd1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java @@ -0,0 +1,40 @@ +package org.dromara.common.core.config; + +import jakarta.validation.Validator; +import org.hibernate.validator.HibernateValidator; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; + +import java.util.Properties; + +/** + * 校验框架配置类 + * + * @author Lion Li + */ +@AutoConfiguration +public class ValidatorConfig { + + /** + * 配置校验框架 快速返回模式 + */ + @Bean + public Validator validator(MessageSource messageSource) { + try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) { + // 国际化 + factoryBean.setValidationMessageSource(messageSource); + // 设置使用 HibernateValidator 校验器 + factoryBean.setProviderClass(HibernateValidator.class); + Properties properties = new Properties(); + // 设置 快速异常返回 + properties.setProperty("hibernate.validator.fail_fast", "true"); + factoryBean.setValidationProperties(properties); + // 加载配置 + factoryBean.afterPropertiesSet(); + return factoryBean.getValidator(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java new file mode 100644 index 0000000..820564f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 线程池 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "thread-pool") +public class ThreadPoolProperties { + + /** + * 是否开启线程池 + */ + private boolean enabled; + + /** + * 队列最大长度 + */ + private int queueCapacity; + + /** + * 线程池维护线程所允许的空闲时间 + */ + private int keepAliveSeconds; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java new file mode 100644 index 0000000..ceb8370 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.constant; + +/** + * 缓存的key 常量 + * + * @author Lion Li + */ +public interface CacheConstants { + + /** + * 在线用户 redis key + */ + String ONLINE_TOKEN_KEY = "online_tokens:"; + + /** + * 参数管理 cache key + */ + String SYS_CONFIG_KEY = "sys_config:"; + + /** + * 字典管理 cache key + */ + String SYS_DICT_KEY = "sys_dict:"; + + /** + * 登录账户密码错误次数 redis key + */ + String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java new file mode 100644 index 0000000..bf8efc5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java @@ -0,0 +1,83 @@ +package org.dromara.common.core.constant; + +/** + * 缓存组名称常量 + *

+ * key 格式为 cacheNames#ttl#maxIdleTime#maxSize + *

+ * ttl 过期时间 如果设置为0则不过期 默认为0 + * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 + * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 + *

+ * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500 + * + * @author Lion Li + */ +public interface CacheNames { + + /** + * 演示案例 + */ + String DEMO_CACHE = "demo:cache#60s#10m#20"; + + /** + * 系统配置 + */ + String SYS_CONFIG = "sys_config"; + + /** + * 数据字典 + */ + String SYS_DICT = "sys_dict"; + + /** + * 租户 + */ + String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; + + /** + * 客户端 + */ + String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d"; + + /** + * 用户账户 + */ + String SYS_USER_NAME = "sys_user_name#30d"; + + /** + * 用户名称 + */ + String SYS_NICKNAME = "sys_nickname#30d"; + + /** + * 部门 + */ + String SYS_DEPT = "sys_dept#30d"; + + /** + * OSS内容 + */ + String SYS_OSS = "sys_oss#30d"; + + /** + * 角色自定义权限 + */ + String SYS_ROLE_CUSTOM = "sys_role_custom#30d"; + + /** + * 部门及以下权限 + */ + String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d"; + + /** + * OSS配置 + */ + String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config"; + + /** + * 在线用户 + */ + String ONLINE_TOKEN = "online_tokens"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java new file mode 100644 index 0000000..273c734 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java @@ -0,0 +1,76 @@ +package org.dromara.common.core.constant; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public interface Constants { + + /** + * UTF-8 字符集 + */ + String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + String GBK = "GBK"; + + /** + * www主域 + */ + String WWW = "www."; + + /** + * http请求 + */ + String HTTP = "http://"; + + /** + * https请求 + */ + String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + String FAIL = "1"; + + /** + * 登录成功 + */ + String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + String LOGOUT = "Logout"; + + /** + * 注册 + */ + String REGISTER = "Register"; + + /** + * 登录失败 + */ + String LOGIN_FAIL = "Error"; + + /** + * 验证码有效期(分钟) + */ + Integer CAPTCHA_EXPIRATION = 2; + + /** + * 顶级父级id + */ + Long TOP_PARENT_ID = 0L; + +} + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DateConstant.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DateConstant.java new file mode 100644 index 0000000..28c334e --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DateConstant.java @@ -0,0 +1,14 @@ +package org.dromara.common.core.constant; + +import java.util.regex.Pattern; + +/** + * @author lilemy + * @date 2025/4/7 17:12 + */ +public interface DateConstant { + + // 匹配 "yyyy-MM",年四位,月 01~12 + Pattern YEAR_MONTH_PATTERN = Pattern.compile("^\\d{4}-(0[1-9]|1[0-2])$"); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java new file mode 100644 index 0000000..5352b11 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java @@ -0,0 +1,34 @@ +package org.dromara.common.core.constant; + +/** + * 全局的key常量 (业务无关的key) + * + * @author Lion Li + */ +public interface GlobalConstants { + + /** + * 全局 redis key (业务无关的key) + */ + String GLOBAL_REDIS_KEY = "global:"; + + /** + * 验证码 redis key + */ + String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:"; + + /** + * 防重提交 redis key + */ + String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:"; + + /** + * 限流 redis key + */ + String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; + + /** + * 三方认证 redis key + */ + String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:"; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java new file mode 100644 index 0000000..85566e8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java @@ -0,0 +1,93 @@ +package org.dromara.common.core.constant; + +/** + * 返回状态码 + * + * @author Lion Li + */ +public interface HttpStatus { + /** + * 操作成功 + */ + int SUCCESS = 200; + + /** + * 对象创建成功 + */ + int CREATED = 201; + + /** + * 请求已经被接受 + */ + int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + int MOVED_PERM = 301; + + /** + * 重定向 + */ + int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + int BAD_REQUEST = 400; + + /** + * 未授权 + */ + int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + int ERROR = 500; + + /** + * 接口未实现 + */ + int NOT_IMPLEMENTED = 501; + + /** + * 系统警告消息 + */ + int WARN = 601; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java new file mode 100644 index 0000000..77eed8c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java @@ -0,0 +1,54 @@ +package org.dromara.common.core.constant; + +import cn.hutool.core.lang.RegexPool; + +/** + * 常用正则表达式字符串 + *

+ * 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/ + * + * @author Feng + */ +public interface RegexConstants extends RegexPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$"; + + /** + * 权限标识必须符合 tool:build:list 格式,或者空字符串 + */ + String PERMISSION_STRING = "^(|^[a-zA-Z0-9_]+:[a-zA-Z0-9_]+:[a-zA-Z0-9_]+)$"; + + /** + * 身份证号码(后6位) + */ + String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"; + + /** + * QQ号码 + */ + String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$"; + + /** + * 邮政编码 + */ + String POSTAL_CODE = "^[1-9]\\d{5}$"; + + /** + * 注册账号 + */ + String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$"; + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"; + + /** + * 通用状态(0表示正常,1表示停用) + */ + String STATUS = "^[01]$"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java new file mode 100644 index 0000000..55240bb --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java @@ -0,0 +1,75 @@ +package org.dromara.common.core.constant; + +/** + * 系统常量信息 + * + * @author Lion Li + */ +public interface SystemConstants { + + /** + * 正常状态 + */ + String NORMAL = "0"; + + /** + * 异常状态 + */ + String DISABLE = "1"; + + /** + * 是否为系统默认(是) + */ + String YES = "Y"; + + /** + * 是否为系统默认(否) + */ + String NO = "N"; + + /** + * 是否菜单外链(是) + */ + String YES_FRAME = "0"; + + /** + * 是否菜单外链(否) + */ + String NO_FRAME = "1"; + + /** + * 菜单类型(目录) + */ + String TYPE_DIR = "M"; + + /** + * 菜单类型(菜单) + */ + String TYPE_MENU = "C"; + + /** + * 菜单类型(按钮) + */ + String TYPE_BUTTON = "F"; + + /** + * Layout组件标识 + */ + String LAYOUT = "Layout"; + + /** + * ParentView组件标识 + */ + String PARENT_VIEW = "ParentView"; + + /** + * InnerLink组件标识 + */ + String INNER_LINK = "InnerLink"; + + /** + * 超级管理员ID + */ + Long SUPER_ADMIN_ID = 1L; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java new file mode 100644 index 0000000..33ce0cf --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java @@ -0,0 +1,35 @@ +package org.dromara.common.core.constant; + +/** + * 租户常量信息 + * + * @author Lion Li + */ +public interface TenantConstants { + + /** + * 超级管理员ID + */ + Long SUPER_ADMIN_ID = 1L; + + /** + * 超级管理员角色 roleKey + */ + String SUPER_ADMIN_ROLE_KEY = "superadmin"; + + /** + * 租户管理员角色 roleKey + */ + String TENANT_ADMIN_ROLE_KEY = "admin"; + + /** + * 租户管理员角色名称 + */ + String TENANT_ADMIN_ROLE_NAME = "管理员"; + + /** + * 默认租户ID + */ + String DEFAULT_TENANT_ID = "000000"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java new file mode 100644 index 0000000..be85805 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java @@ -0,0 +1,110 @@ +package org.dromara.common.core.domain; + +import org.dromara.common.core.constant.HttpStatus; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class R implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 成功 + */ + public static final int SUCCESS = 200; + + /** + * 失败 + */ + public static final int FAIL = 500; + + private int code; + + private String msg; + + private T data; + + public static R ok() { + return restResult(null, SUCCESS, "操作成功"); + } + + public static R ok(T data) { + return restResult(data, SUCCESS, "操作成功"); + } + + public static R ok(String msg) { + return restResult(null, SUCCESS, msg); + } + + public static R ok(String msg, T data) { + return restResult(data, SUCCESS, msg); + } + + public static R fail() { + return restResult(null, FAIL, "操作失败"); + } + + public static R fail(String msg) { + return restResult(null, FAIL, msg); + } + + public static R fail(T data) { + return restResult(data, FAIL, "操作失败"); + } + + public static R fail(String msg, T data) { + return restResult(data, FAIL, msg); + } + + public static R fail(int code, String msg) { + return restResult(null, code, msg); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static R warn(String msg) { + return restResult(null, HttpStatus.WARN, msg); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static R warn(String msg, T data) { + return restResult(data, HttpStatus.WARN, msg); + } + + private static R restResult(T data, int code, String msg) { + R r = new R<>(); + r.setCode(code); + r.setData(data); + r.setMsg(msg); + return r; + } + + public static Boolean isError(R ret) { + return !isSuccess(ret); + } + + public static Boolean isSuccess(R ret) { + return R.SUCCESS == ret.getCode(); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java new file mode 100644 index 0000000..2e63f8a --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java @@ -0,0 +1,71 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 办理任务请求对象 + * + * @author may + */ +@Data +public class CompleteTaskDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 抄送人员 + */ + private List flowCopyList; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 办理意见 + */ + private String message; + + /** + * 消息通知 + */ + private String notice; + + /** + * 流程变量 + */ + private Map variables; + + /** + * 扩展变量(此处为逗号分隔的ossId) + */ + private String ext; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java new file mode 100644 index 0000000..65c012f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 部门 + * + * @author AprilWind + */ + +@Data +@NoArgsConstructor +public class DeptDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 部门名称 + */ + private String deptName; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictDataDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictDataDTO.java new file mode 100644 index 0000000..dff1a75 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictDataDTO.java @@ -0,0 +1,41 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 字典数据DTO + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class DictDataDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典标签 + */ + private String dictLabel; + + /** + * 字典键值 + */ + private String dictValue; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictTypeDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictTypeDTO.java new file mode 100644 index 0000000..43ab142 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictTypeDTO.java @@ -0,0 +1,41 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 字典类型DTO + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class DictTypeDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典主键 + */ + private Long dictId; + + /** + * 字典名称 + */ + private String dictName; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java new file mode 100644 index 0000000..2f20b21 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 抄送 + * + * @author may + */ +@Data +public class FlowCopyDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户名称 + */ + private String userName; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java new file mode 100644 index 0000000..463821c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java @@ -0,0 +1,46 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * OSS对象 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class OssDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 对象存储主键 + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java new file mode 100644 index 0000000..7536ee3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java @@ -0,0 +1,46 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 岗位 + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class PostDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 岗位ID + */ + private Long postId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 岗位编码 + */ + private String postCode; + + /** + * 岗位名称 + */ + private String postName; + + /** + * 岗位类别编码 + */ + private String postCategory; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java new file mode 100644 index 0000000..aea8e7a --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java @@ -0,0 +1,42 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 角色 + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class RoleDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + private Long roleId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色权限 + */ + private String roleKey; + + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + private String dataScope; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java new file mode 100644 index 0000000..3934ada --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java @@ -0,0 +1,45 @@ +package org.dromara.common.core.domain.dto; + + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 启动流程对象 + * + * @author may + */ +@Data +public class StartProcessDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 业务唯一值id + */ + private String businessId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java new file mode 100644 index 0000000..9bcbd12 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.domain.dto; + + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 启动流程返回对象 + * + * @author Lion Li + */ +@Data +public class StartProcessReturnDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + private Long processInstanceId; + + /** + * 任务id + */ + private Long taskId; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java new file mode 100644 index 0000000..85893e1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java @@ -0,0 +1,101 @@ +package org.dromara.common.core.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 任务受让人 + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class TaskAssigneeDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 总大小 + */ + private Long total = 0L; + + /** + * + */ + private List list; + + public TaskAssigneeDTO(Long total, List list) { + this.total = total; + this.list = list; + } + + /** + * 将源列表转换为 TaskHandler 列表 + * + * @param 通用类型 + * @param sourceList 待转换的源列表 + * @param storageId 提取 storageId 的函数 + * @param handlerCode 提取 handlerCode 的函数 + * @param handlerName 提取 handlerName 的函数 + * @param groupName 提取 groupName 的函数 + * @param createTimeMapper 提取 createTime 的函数 + * @return 转换后的 TaskHandler 列表 + */ + public static List convertToHandlerList( + List sourceList, + Function storageId, + Function handlerCode, + Function handlerName, + Function groupName, + Function createTimeMapper) { + return sourceList.stream() + .map(item -> new TaskHandler( + String.valueOf(storageId.apply(item)), + handlerCode.apply(item), + handlerName.apply(item), + groupName != null ? String.valueOf(groupName.apply(item)) : null, + createTimeMapper.apply(item) + )).collect(Collectors.toList()); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class TaskHandler { + + /** + * 主键 + */ + private String storageId; + + /** + * 权限编码 + */ + private String handlerCode; + + /** + * 权限名称 + */ + private String handlerName; + + /** + * 权限分组 + */ + private String groupName; + + /** + * 创建时间 + */ + private Date createTime; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java new file mode 100644 index 0000000..cb5def9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java @@ -0,0 +1,73 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 用户 + * + * @author Michelle.Chung + */ +@Data +@NoArgsConstructor +public class UserDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + private String email; + + /** + * 手机号码 + */ + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java new file mode 100644 index 0000000..43d8c3c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java @@ -0,0 +1,72 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 当前在线会话 + * + * @author ruoyi + */ + +@Data +@NoArgsConstructor +public class UserOnlineDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 会话编号 + */ + private String tokenId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 用户名称 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地址 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java new file mode 100644 index 0000000..d570c31 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java @@ -0,0 +1,34 @@ +package org.dromara.common.core.domain.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 删除流程监听 + * + * @author AprilWind + */ +@Data +public class ProcessDeleteEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 业务id + */ + private String businessId; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java new file mode 100644 index 0000000..7b15b85 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java @@ -0,0 +1,65 @@ +package org.dromara.common.core.domain.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +/** + * 总体流程监听 + * + * @author may + */ +@Data +public class ProcessEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 业务id + */ + private String businessId; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 流程节点编码 + */ + private String nodeCode; + + /** + * 流程节点名称 + */ + private String nodeName; + + /** + * 流程状态 + */ + private String status; + + /** + * 办理参数 + */ + private Map params; + + /** + * 当为true时为申请人节点办理 + */ + private Boolean submit; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java new file mode 100644 index 0000000..67cf738 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java @@ -0,0 +1,59 @@ +package org.dromara.common.core.domain.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程办理监听 + * + * @author may + */ +@Data +public class ProcessTaskEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 流程节点编码 + */ + private String nodeCode; + + /** + * 流程节点名称 + */ + private String nodeName; + + /** + * 任务id + */ + private Long taskId; + + /** + * 业务id + */ + private String businessId; + + /** + * 流程状态 + */ + private String status; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java new file mode 100644 index 0000000..ffde8c6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 邮件登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class EmailLoginBody extends LoginBody { + + /** + * 邮箱 + */ + @NotBlank(message = "{user.email.not.blank}") + @Email(message = "{user.email.not.valid}") + private String email; + + /** + * 邮箱code + */ + @NotBlank(message = "{email.code.not.blank}") + private String emailCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java new file mode 100644 index 0000000..63bee0d --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java @@ -0,0 +1,48 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户登录对象 + * + * @author Lion Li + */ + +@Data +public class LoginBody implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 客户端id + */ + @NotBlank(message = "{auth.clientid.not.blank}") + private String clientId; + + /** + * 授权类型 + */ + @NotBlank(message = "{auth.grant.type.not.blank}") + private String grantType; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 验证码 + */ + private String code; + + /** + * 唯一标识 + */ + private String uuid; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java new file mode 100644 index 0000000..338d4d7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java @@ -0,0 +1,148 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.domain.dto.PostDTO; +import org.dromara.common.core.domain.dto.RoleDTO; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Set; + +/** + * 登录用户身份权限 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class LoginUser implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 部门类别编码 + */ + private String deptCategory; + + /** + * 部门名 + */ + private String deptName; + + /** + * 用户唯一标识 + */ + private String token; + + /** + * 用户类型 + */ + private String userType; + + /** + * 登录时间 + */ + private Long loginTime; + + /** + * 过期时间 + */ + private Long expireTime; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 菜单权限 + */ + private Set menuPermission; + + /** + * 角色权限 + */ + private Set rolePermission; + + /** + * 用户名 + */ + private String username; + + /** + * 用户昵称 + */ + private String nickname; + + /** + * 角色对象 + */ + private List roles; + + /** + * 岗位对象 + */ + private List posts; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 获取登录id + */ + public String getLoginId() { + if (userType == null) { + throw new IllegalArgumentException("用户类型不能为空"); + } + if (userId == null) { + throw new IllegalArgumentException("用户ID不能为空"); + } + return userType + ":" + userId; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java new file mode 100644 index 0000000..87d0e8e --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.validator.constraints.Length; + +/** + * 密码登录对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class PasswordLoginBody extends LoginBody { + + /** + * 用户名 + */ + @NotBlank(message = "{user.username.not.blank}") + @Length(min = 2, max = 20, message = "{user.username.length.valid}") + private String username; + + /** + * 用户密码 + */ + @NotBlank(message = "{user.password.not.blank}") + @Length(min = 5, max = 20, message = "{user.password.length.valid}") + private String password; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java new file mode 100644 index 0000000..6ea8a76 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java @@ -0,0 +1,33 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.validator.constraints.Length; + +/** + * 用户注册对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RegisterBody extends LoginBody { + + /** + * 用户名 + */ + @NotBlank(message = "{user.username.not.blank}") + @Length(min = 2, max = 20, message = "{user.username.length.valid}") + private String username; + + /** + * 用户密码 + */ + @NotBlank(message = "{user.password.not.blank}") + @Length(min = 5, max = 20, message = "{user.password.length.valid}") + private String password; + + private String userType; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java new file mode 100644 index 0000000..a878348 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java @@ -0,0 +1,29 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 短信登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class SmsLoginBody extends LoginBody { + + /** + * 手机号 + */ + @NotBlank(message = "{user.phonenumber.not.blank}") + private String phonenumber; + + /** + * 短信code + */ + @NotBlank(message = "{sms.code.not.blank}") + private String smsCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java new file mode 100644 index 0000000..0d1b121 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java @@ -0,0 +1,35 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 三方登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class SocialLoginBody extends LoginBody { + + /** + * 第三方登录平台 + */ + @NotBlank(message = "{social.source.not.blank}") + private String source; + + /** + * 第三方登录code + */ + @NotBlank(message = "{social.code.not.blank}") + private String socialCode; + + /** + * 第三方登录socialState + */ + @NotBlank(message = "{social.state.not.blank}") + private String socialState; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java new file mode 100644 index 0000000..0cbed2f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java @@ -0,0 +1,56 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 任务受让人 + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class TaskAssigneeBody implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 权限编码 + */ + private String handlerCode; + + /** + * 权限名称 + */ + private String handlerName; + + /** + * 权限分组 + */ + private String groupId; + + /** + * 开始时间 + */ + private String beginTime; + + /** + * 结束时间 + */ + private String endTime; + + /** + * 当前页 + */ + private Integer pageNum = 1; + + /** + * 每页显示条数 + */ + private Integer pageSize = 10; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java new file mode 100644 index 0000000..518fe2e --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java @@ -0,0 +1,28 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 三方登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class XcxLoginBody extends LoginBody { + + /** + * 小程序id(多个小程序时使用) + */ + private String appid; + + /** + * 小程序code + */ + @NotBlank(message = "{xcx.code.not.blank}") + private String xcxCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java new file mode 100644 index 0000000..e5f3d6c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java @@ -0,0 +1,27 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * 小程序登录用户身份权限 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class XcxLoginUser extends LoginUser { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * openid + */ + private String openid; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/vo/IdAndNameVO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/vo/IdAndNameVO.java new file mode 100644 index 0000000..a082d39 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/vo/IdAndNameVO.java @@ -0,0 +1,36 @@ +package org.dromara.common.core.domain.vo; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/3/19 11:40 + */ +@Data +public class IdAndNameVO { + + /** + * id + */ + private Long id; + + /** + * 名称 + */ + private String name; + + /** + * 构建 + * + * @param id id + * @param name 名称 + * @return {@link IdAndNameVO} + */ + public static IdAndNameVO build(Long id, String name) { + IdAndNameVO idAndNameVO = new IdAndNameVO(); + idAndNameVO.setId(id); + idAndNameVO.setName(name); + return idAndNameVO; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java new file mode 100644 index 0000000..c1660ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java @@ -0,0 +1,215 @@ +package org.dromara.common.core.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 业务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum BusinessStatusEnum { + + /** + * 已撤销 + */ + CANCEL("cancel", "已撤销"), + + /** + * 草稿 + */ + DRAFT("draft", "草稿"), + + /** + * 待审核 + */ + WAITING("waiting", "待审核"), + + /** + * 已完成 + */ + FINISH("finish", "已完成"), + + /** + * 已作废 + */ + INVALID("invalid", "已作废"), + + /** + * 已退回 + */ + BACK("back", "已退回"), + + /** + * 已终止 + */ + TERMINATION("termination", "已终止"); + + /** + * 状态 + */ + private final String status; + + /** + * 描述 + */ + private final String desc; + + private static final Map STATUS_MAP = Arrays.stream(BusinessStatusEnum.values()) + .collect(Collectors.toConcurrentMap(BusinessStatusEnum::getStatus, Function.identity())); + + /** + * 根据状态获取对应的 BusinessStatusEnum 枚举 + * + * @param status 业务状态码 + * @return 对应的 BusinessStatusEnum 枚举,如果找不到则返回 null + */ + public static BusinessStatusEnum getByStatus(String status) { + // 使用 STATUS_MAP 获取对应的枚举,若找不到则返回 null + return STATUS_MAP.get(status); + } + + /** + * 根据状态获取对应的业务状态描述信息 + * + * @param status 业务状态码 + * @return 返回业务状态描述,若状态码为空或未找到对应的枚举,返回空字符串 + */ + public static String findByStatus(String status) { + if (StringUtils.isBlank(status)) { + return StrUtil.EMPTY; + } + BusinessStatusEnum statusEnum = STATUS_MAP.get(status); + return (statusEnum != null) ? statusEnum.getDesc() : StrUtil.EMPTY; + } + + /** + * 判断是否为指定的状态之一:草稿、已撤销或已退回 + * + * @param status 要检查的状态 + * @return 如果状态为草稿、已撤销或已退回之一,则返回 true;否则返回 false + */ + public static boolean isDraftOrCancelOrBack(String status) { + return DRAFT.status.equals(status) || CANCEL.status.equals(status) || BACK.status.equals(status); + } + + /** + * 判断是否为撤销,退回,作废,终止 + * + * @param status status + * @return 结果 + */ + public static boolean initialState(String status) { + return CANCEL.status.equals(status) || BACK.status.equals(status) || INVALID.status.equals(status) || TERMINATION.status.equals(status); + } + + /** + * 获取运行中的实例状态列表 + * + * @return 包含运行中实例状态的不可变列表 + * (包含 DRAFT、WAITING、BACK 和 CANCEL 状态) + */ + public static List runningStatus() { + return Arrays.asList(DRAFT.status, WAITING.status, BACK.status, CANCEL.status); + } + + /** + * 获取结束实例的状态列表 + * + * @return 包含结束实例状态的不可变列表 + * (包含 FINISH、INVALID 和 TERMINATION 状态) + */ + public static List finishStatus() { + return Arrays.asList(FINISH.status, INVALID.status, TERMINATION.status); + } + + /** + * 启动流程校验 + * + * @param status 状态 + */ + public static void checkStartStatus(String status) { + if (WAITING.getStatus().equals(status)) { + throw new ServiceException("该单据已提交过申请,正在审批中!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 撤销流程校验 + * + * @param status 状态 + */ + public static void checkCancelStatus(String status) { + if (CANCEL.getStatus().equals(status)) { + throw new ServiceException("该单据已撤销!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (BACK.getStatus().equals(status)) { + throw new ServiceException("该单据已退回!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 驳回流程校验 + * + * @param status 状态 + */ + public static void checkBackStatus(String status) { + if (BACK.getStatus().equals(status)) { + throw new ServiceException("该单据已退回!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (CANCEL.getStatus().equals(status)) { + throw new ServiceException("该单据已撤销!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 作废,终止流程校验 + * + * @param status 状态 + */ + public static void checkInvalidStatus(String status) { + if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java new file mode 100644 index 0000000..dbadfc2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对一套 用户体系 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DeviceType { + + /** + * pc端 + */ + PC("pc"), + + /** + * app端 + */ + APP("app"), + + /** + * 小程序端 + */ + XCX("xcx"), + + /** + * social第三方端 + */ + SOCIAL("social"); + + private final String device; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java new file mode 100644 index 0000000..8d4b6d9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java @@ -0,0 +1,146 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.utils.StringUtils; + +/* + * 日期格式 + * "yyyy":4位数的年份,例如:2023年表示为"2023"。 + * "yy":2位数的年份,例如:2023年表示为"23"。 + * "MM":2位数的月份,取值范围为01到12,例如:7月表示为"07"。 + * "M":不带前导零的月份,取值范围为1到12,例如:7月表示为"7"。 + * "dd":2位数的日期,取值范围为01到31,例如:22日表示为"22"。 + * "d":不带前导零的日期,取值范围为1到31,例如:22日表示为"22"。 + * "EEEE":星期的全名,例如:星期三表示为"Wednesday"。 + * "E":星期的缩写,例如:星期三表示为"Wed"。 + * "DDD" 或 "D":一年中的第几天,取值范围为001到366,例如:第200天表示为"200"。 + * 时间格式 + * "HH":24小时制的小时数,取值范围为00到23,例如:下午5点表示为"17"。 + * "hh":12小时制的小时数,取值范围为01到12,例如:下午5点表示为"05"。 + * "mm":分钟数,取值范围为00到59,例如:30分钟表示为"30"。 + * "ss":秒数,取值范围为00到59,例如:45秒表示为"45"。 + * "SSS":毫秒数,取值范围为000到999,例如:123毫秒表示为"123"。 + */ + +/** + * 日期格式与时间格式枚举 + */ +@Getter +@AllArgsConstructor +public enum FormatsType { + + /** + * 例如:2023年表示为"23" + */ + YY("yy"), + + /** + * 例如:2023年表示为"2023" + */ + YYYY("yyyy"), + + /** + * 例例如,2023年7月可以表示为 "2023-07" + */ + YYYY_MM("yyyy-MM"), + + /** + * 例如,日期 "2023年7月22日" 可以表示为 "2023-07-22" + */ + YYYY_MM_DD("yyyy-MM-dd"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分",则可以表示为 "2023-07-22 15:30" + */ + YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023-07-22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"), + + /** + * 例如:下午3点30分45秒,表示为 "15:30:45" + */ + HH_MM_SS("HH:mm:ss"), + + /** + * 例例如,2023年7月可以表示为 "2023/07" + */ + YYYY_MM_SLASH("yyyy/MM"), + + /** + * 例如,日期 "2023年7月22日" 可以表示为 "2023/07/22" + */ + YYYY_MM_DD_SLASH("yyyy/MM/dd"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SLASH("yyyy/MM/dd HH:mm"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SS_SLASH("yyyy/MM/dd HH:mm:ss"), + + /** + * 例例如,2023年7月可以表示为 "2023.07" + */ + YYYY_MM_DOT("yyyy.MM"), + + /** + * 例如,日期 "2023年7月22日" 可以表示为 "2023.07.22" + */ + YYYY_MM_DD_DOT("yyyy.MM.dd"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分",则可以表示为 "2023.07.22 15:30" + */ + YYYY_MM_DD_HH_MM_DOT("yyyy.MM.dd HH:mm"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023.07.22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SS_DOT("yyyy.MM.dd HH:mm:ss"), + + /** + * 例如,2023年7月可以表示为 "202307" + */ + YYYYMM("yyyyMM"), + + /** + * 例如,2023年7月22日可以表示为 "20230722" + */ + YYYYMMDD("yyyyMMdd"), + + /** + * 例如,2023年7月22日下午3点可以表示为 "2023072215" + */ + YYYYMMDDHH("yyyyMMddHH"), + + /** + * 例如,2023年7月22日下午3点30分可以表示为 "202307221530" + */ + YYYYMMDDHHMM("yyyyMMddHHmm"), + + /** + * 例如,2023年7月22日下午3点30分45秒可以表示为 "20230722153045" + */ + YYYYMMDDHHMMSS("yyyyMMddHHmmss"); + + /** + * 时间格式 + */ + private final String timeFormat; + + public static FormatsType getFormatsType(String str) { + for (FormatsType value : values()) { + if (StringUtils.contains(str, value.getTimeFormat())) { + return value; + } + } + throw new RuntimeException("'FormatsType' not found By " + str); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java new file mode 100644 index 0000000..f9cac66 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java @@ -0,0 +1,44 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum LoginType { + + /** + * 密码登录 + */ + PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), + + /** + * 短信登录 + */ + SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), + + /** + * 邮箱登录 + */ + EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"), + + /** + * 小程序登录 + */ + XCX("", ""); + + /** + * 登录重试超出限制提示 + */ + final String retryLimitExceed; + + /** + * 登录重试限制计数提示 + */ + final String retryLimitCount; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java new file mode 100644 index 0000000..be7e44d --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 用户状态 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum UserStatus { + /** + * 正常 + */ + OK("0", "正常"), + /** + * 停用 + */ + DISABLE("1", "停用"), + /** + * 删除 + */ + DELETED("2", "删除"); + + private final String code; + private final String info; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java new file mode 100644 index 0000000..69e4753 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.enums; + +import org.dromara.common.core.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对多套 用户体系 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum UserType { + + /** + * pc端 + */ + SYS_USER("sys_user"), + + /** + * app端 + */ + APP_USER("app_user"); + + private final String userType; + + public static UserType getUserType(String str) { + for (UserType value : values()) { + if (StringUtils.contains(str, value.getUserType())) { + return value; + } + } + throw new RuntimeException("'UserType' not found By " + str); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java new file mode 100644 index 0000000..e9dc6ec --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java @@ -0,0 +1,59 @@ +package org.dromara.common.core.exception; + +import lombok.*; + +import java.io.Serial; + +/** + * 业务异常 + * + * @author ruoyi + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +public final class ServiceException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + */ + private String detailMessage; + + public ServiceException(String message) { + this.message = message; + } + + public ServiceException(String message, Integer code) { + this.message = message; + this.code = code; + } + + @Override + public String getMessage() { + return message; + } + + public ServiceException setMessage(String message) { + this.message = message; + return this; + } + + public ServiceException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java new file mode 100644 index 0000000..a76e16d --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java @@ -0,0 +1,62 @@ +package org.dromara.common.core.exception; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * sse 特制异常 + * + * @author LionLi + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +public final class SseException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + */ + private String detailMessage; + + public SseException(String message) { + this.message = message; + } + + public SseException(String message, Integer code) { + this.message = message; + this.code = code; + } + + @Override + public String getMessage() { + return message; + } + + public SseException setMessage(String message) { + this.message = message; + return this; + } + + public SseException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java new file mode 100644 index 0000000..40ce01b --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java @@ -0,0 +1,74 @@ +package org.dromara.common.core.exception.base; + +import lombok.AllArgsConstructor; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * 基础异常 + * + * @author ruoyi + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +public class BaseException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 所属模块 + */ + private String module; + + /** + * 错误码 + */ + private String code; + + /** + * 错误码对应的参数 + */ + private Object[] args; + + /** + * 错误消息 + */ + private String defaultMessage; + + public BaseException(String module, String code, Object[] args) { + this(module, code, args, null); + } + + public BaseException(String module, String defaultMessage) { + this(module, null, null, defaultMessage); + } + + public BaseException(String code, Object[] args) { + this(null, code, args, null); + } + + public BaseException(String defaultMessage) { + this(null, null, null, defaultMessage); + } + + @Override + public String getMessage() { + String message = null; + if (!StringUtils.isEmpty(code)) { + message = MessageUtils.message(code, args); + } + if (message == null) { + message = defaultMessage; + } + return message; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java new file mode 100644 index 0000000..d374fc0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java @@ -0,0 +1,21 @@ +package org.dromara.common.core.exception.file; + +import org.dromara.common.core.exception.base.BaseException; + +import java.io.Serial; + +/** + * 文件信息异常类 + * + * @author ruoyi + */ +public class FileException extends BaseException { + + @Serial + private static final long serialVersionUID = 1L; + + public FileException(String code, Object[] args) { + super("file", code, args, null); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java new file mode 100644 index 0000000..af98124 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.file; + +import java.io.Serial; + +/** + * 文件名称超长限制异常类 + * + * @author ruoyi + */ +public class FileNameLengthLimitExceededException extends FileException { + + @Serial + private static final long serialVersionUID = 1L; + + public FileNameLengthLimitExceededException(int defaultFileNameLength) { + super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java new file mode 100644 index 0000000..1eb8d40 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.file; + +import java.io.Serial; + +/** + * 文件名大小限制异常类 + * + * @author ruoyi + */ +public class FileSizeLimitExceededException extends FileException { + + @Serial + private static final long serialVersionUID = 1L; + + public FileSizeLimitExceededException(long defaultMaxSize) { + super("upload.exceed.maxSize", new Object[]{defaultMaxSize}); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java new file mode 100644 index 0000000..43824e0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.user; + +import java.io.Serial; + +/** + * 验证码错误异常类 + * + * @author ruoyi + */ +public class CaptchaException extends UserException { + + @Serial + private static final long serialVersionUID = 1L; + + public CaptchaException() { + super("user.jcaptcha.error"); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java new file mode 100644 index 0000000..f4b8cac --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.user; + +import java.io.Serial; + +/** + * 验证码失效异常类 + * + * @author ruoyi + */ +public class CaptchaExpireException extends UserException { + + @Serial + private static final long serialVersionUID = 1L; + + public CaptchaExpireException() { + super("user.jcaptcha.expire"); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java new file mode 100644 index 0000000..024fed6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java @@ -0,0 +1,20 @@ +package org.dromara.common.core.exception.user; + +import org.dromara.common.core.exception.base.BaseException; + +import java.io.Serial; + +/** + * 用户信息异常类 + * + * @author ruoyi + */ +public class UserException extends BaseException { + + @Serial + private static final long serialVersionUID = 1L; + + public UserException(String code, Object... args) { + super("user", code, args, null); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java new file mode 100644 index 0000000..fd907d2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java @@ -0,0 +1,52 @@ +package org.dromara.common.core.factory; + +import cn.hutool.core.lang.PatternPool; +import org.dromara.common.core.constant.RegexConstants; + +import java.util.regex.Pattern; + +/** + * 正则表达式模式池工厂 + *

初始化的时候将正则表达式加入缓存池当中

+ *

提高正则表达式的性能,避免重复编译相同的正则表达式

+ * + * @author 21001 + */ +public class RegexPatternPoolFactory extends PatternPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + public static final Pattern DICTIONARY_TYPE = get(RegexConstants.DICTIONARY_TYPE); + + /** + * 身份证号码(后6位) + */ + public static final Pattern ID_CARD_LAST_6 = get(RegexConstants.ID_CARD_LAST_6); + + /** + * QQ号码 + */ + public static final Pattern QQ_NUMBER = get(RegexConstants.QQ_NUMBER); + + /** + * 邮政编码 + */ + public static final Pattern POSTAL_CODE = get(RegexConstants.POSTAL_CODE); + + /** + * 注册账号 + */ + public static final Pattern ACCOUNT = get(RegexConstants.ACCOUNT); + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + public static final Pattern PASSWORD = get(RegexConstants.PASSWORD); + + /** + * 通用状态(0表示正常,1表示停用) + */ + public static final Pattern STATUS = get(RegexConstants.STATUS); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java new file mode 100644 index 0000000..af61b90 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.factory; + +import org.dromara.common.core.utils.StringUtils; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.DefaultPropertySourceFactory; +import org.springframework.core.io.support.EncodedResource; + +import java.io.IOException; + +/** + * yml 配置源工厂 + * + * @author Lion Li + */ +public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + String sourceName = resource.getResource().getFilename(); + if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(resource.getResource()); + factory.afterPropertiesSet(); + return new PropertiesPropertySource(sourceName, factory.getObject()); + } + return super.createPropertySource(name, resource); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java new file mode 100644 index 0000000..7328c69 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.service; + +/** + * 通用 参数配置服务 + * + * @author Lion Li + */ +public interface ConfigService { + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + String getConfigValue(String configKey); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java new file mode 100644 index 0000000..f93d177 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.DeptDTO; + +import java.util.List; + +/** + * 通用 部门服务 + * + * @author Lion Li + */ +public interface DeptService { + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + String selectDeptNameByIds(String deptIds); + + /** + * 根据部门ID查询部门负责人 + * + * @param deptId 部门ID,用于指定需要查询的部门 + * @return 返回该部门的负责人ID + */ + Long selectDeptLeaderById(Long deptId); + + /** + * 查询部门 + * + * @return 部门列表 + */ + List selectDeptsByList(); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java new file mode 100644 index 0000000..d80395c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java @@ -0,0 +1,87 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.DictDataDTO; +import org.dromara.common.core.domain.dto.DictTypeDTO; + +import java.util.List; +import java.util.Map; + +/** + * 通用 字典服务 + * + * @author Lion Li + */ +public interface DictService { + + /** + * 分隔符 + */ + String SEPARATOR = ","; + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + String getDictLabel(String dictType, String dictValue, String separator); + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + String getDictValue(String dictType, String dictLabel, String separator); + + /** + * 获取字典下所有的字典值与标签 + * + * @param dictType 字典类型 + * @return dictValue为key,dictLabel为值组成的Map + */ + Map getAllDictByDictType(String dictType); + + /** + * 根据字典类型查询详细信息 + * + * @param dictType 字典类型 + * @return 字典类型详细信息 + */ + DictTypeDTO getDictType(String dictType); + + /** + * 根据字典类型查询字典数据列表 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + List getDictData(String dictType); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java new file mode 100644 index 0000000..1a52de0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java @@ -0,0 +1,29 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.OssDTO; + +import java.util.List; + +/** + * 通用 OSS服务 + * + * @author Lion Li + */ +public interface OssService { + + /** + * 通过ossId查询对应的url + * + * @param ossIds ossId串逗号分隔 + * @return url串逗号分隔 + */ + String selectUrlByIds(String ossIds); + + /** + * 通过ossId查询列表 + * + * @param ossIds ossId串逗号分隔 + * @return 列表 + */ + List selectByIds(String ossIds); +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java new file mode 100644 index 0000000..41d4e83 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java @@ -0,0 +1,10 @@ +package org.dromara.common.core.service; + +/** + * 通用 岗位服务 + * + * @author AprilWind + */ +public interface PostService { + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java new file mode 100644 index 0000000..ba62c82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java @@ -0,0 +1,10 @@ +package org.dromara.common.core.service; + +/** + * 通用 角色服务 + * + * @author AprilWind + */ +public interface RoleService { + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java new file mode 100644 index 0000000..9af6691 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java @@ -0,0 +1,45 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.TaskAssigneeDTO; +import org.dromara.common.core.domain.model.TaskAssigneeBody; + +/** + * 工作流设计器获取任务执行人 + * + * @author Lion Li + */ +public interface TaskAssigneeService { + + /** + * 查询角色并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery); + + /** + * 查询岗位并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery); + + /** + * 查询部门并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery); + + /** + * 查询用户并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java new file mode 100644 index 0000000..4903c38 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java @@ -0,0 +1,127 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.UserDTO; + +import java.util.List; +import java.util.Map; + +/** + * 通用 用户服务 + * + * @author Lion Li + */ +public interface UserService { + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + String selectUserNameById(Long userId); + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户名称 + */ + String selectNicknameById(Long userId); + + /** + * 通过用户ID查询用户账户 + * + * @param userIds 用户ID 多个用逗号隔开 + * @return 用户名称 + */ + String selectNicknameByIds(String userIds); + + /** + * 通过用户ID查询用户手机号 + * + * @param userId 用户id + * @return 用户手机号 + */ + String selectPhonenumberById(Long userId); + + /** + * 通过用户ID查询用户邮箱 + * + * @param userId 用户id + * @return 用户邮箱 + */ + String selectEmailById(Long userId); + + /** + * 通过用户ID查询用户列表 + * + * @param userIds 用户ids + * @return 用户列表 + */ + List selectListByIds(List userIds); + + /** + * 通过角色ID查询用户ID + * + * @param roleIds 角色ids + * @return 用户ids + */ + List selectUserIdsByRoleIds(List roleIds); + + /** + * 通过角色ID查询用户 + * + * @param roleIds 角色ids + * @return 用户 + */ + List selectUsersByRoleIds(List roleIds); + + /** + * 通过部门ID查询用户 + * + * @param deptIds 部门ids + * @return 用户 + */ + List selectUsersByDeptIds(List deptIds); + + /** + * 通过岗位ID查询用户 + * + * @param postIds 岗位ids + * @return 用户 + */ + List selectUsersByPostIds(List postIds); + + /** + * 根据用户 ID 列表查询用户名称映射关系 + * + * @param userIds 用户 ID 列表 + * @return Map,其中 key 为用户 ID,value 为对应的用户名称 + */ + Map selectUserNamesByIds(List userIds); + + /** + * 根据角色 ID 列表查询角色名称映射关系 + * + * @param roleIds 角色 ID 列表 + * @return Map,其中 key 为角色 ID,value 为对应的角色名称 + */ + Map selectRoleNamesByIds(List roleIds); + + /** + * 根据部门 ID 列表查询部门名称映射关系 + * + * @param deptIds 部门 ID 列表 + * @return Map,其中 key 为部门 ID,value 为对应的部门名称 + */ + Map selectDeptNamesByIds(List deptIds); + + /** + * 根据岗位 ID 列表查询岗位名称映射关系 + * + * @param postIds 岗位 ID 列表 + * @return Map,其中 key 为岗位 ID,value 为对应的岗位名称 + */ + Map selectPostNamesByIds(List postIds); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java new file mode 100644 index 0000000..9d1a901 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java @@ -0,0 +1,95 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.CompleteTaskDTO; +import org.dromara.common.core.domain.dto.StartProcessDTO; +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; + +import java.util.List; +import java.util.Map; + +/** + * 通用 工作流服务 + * + * @author may + */ +public interface WorkflowService { + + /** + * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param businessIds 业务id + * @return 结果 + */ + boolean deleteInstance(List businessIds); + + /** + * 获取当前流程状态 + * + * @param taskId 任务id + * @return 状态 + */ + String getBusinessStatusByTaskId(Long taskId); + + /** + * 获取当前流程状态 + * + * @param businessId 业务id + * @return 状态 + */ + String getBusinessStatus(String businessId); + + /** + * 设置流程变量 + * + * @param instanceId 流程实例id + * @param variable 流程变量 + */ + void setVariable(Long instanceId, Map variable); + + /** + * 获取流程变量 + * + * @param instanceId 流程实例id + */ + Map instanceVariable(Long instanceId); + + /** + * 按照业务id查询流程实例id + * + * @param businessId 业务id + * @return 结果 + */ + Long getInstanceIdByBusinessId(String businessId); + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + void syncDef(String tenantId); + + /** + * 启动流程 + * + * @param startProcess 参数 + * @return 结果 + */ + StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess); + + /** + * 办理任务 + * 系统后台发起审批 无用户信息 需要忽略权限 + * completeTask.getVariables().put("ignore", true); + * + * @param completeTask 参数 + */ + boolean completeTask(CompleteTaskDTO completeTask); + + /** + * 办理任务 + * + * @param taskId 任务ID + * @param message 办理意见 + */ + boolean completeTask(Long taskId, String message); +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java new file mode 100644 index 0000000..250ed94 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java @@ -0,0 +1,312 @@ +package org.dromara.common.core.utils; + +import org.apache.commons.lang3.time.DateFormatUtils; +import org.dromara.common.core.enums.FormatsType; +import org.dromara.common.core.exception.ServiceException; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * 时间工具类 + * + * @author ruoyi + */ +public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + private static final String[] PARSE_PATTERNS = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + + @Deprecated + private DateUtils() { + } + + /** + * 获取当前日期和时间 + * + * @return 当前日期和时间的 Date 对象表示 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取当前日期的字符串表示,格式为YYYY-MM-DD + * + * @return 当前日期的字符串表示 + */ + public static String getDate() { + return dateTimeNow(FormatsType.YYYY_MM_DD); + } + + /** + * 获取当前日期的字符串表示,格式为yyyyMMdd + * + * @return 当前日期的字符串表示 + */ + public static String getCurrentDate() { + return DateFormatUtils.format(new Date(), FormatsType.YYYYMMDD.getTimeFormat()); + } + + /** + * 获取当前日期的路径格式字符串,格式为"yyyy/MM/dd" + * + * @return 当前日期的路径格式字符串 + */ + public static String datePath() { + Date now = new Date(); + return DateFormatUtils.format(now, FormatsType.YYYY_MM_DD_SLASH.getTimeFormat()); + } + + /** + * 获取当前时间的字符串表示,格式为YYYY-MM-DD HH:MM:SS + * + * @return 当前时间的字符串表示 + */ + public static String getTime() { + return dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS); + } + + /** + * 获取当前时间的字符串表示,格式为 "HH:MM:SS" + * + * @return 当前时间的字符串表示,格式为 "HH:MM:SS" + */ + public static String getTimeWithHourMinuteSecond() { + return dateTimeNow(FormatsType.HH_MM_SS); + } + + /** + * 获取当前日期和时间的字符串表示,格式为YYYYMMDDHHMMSS + * + * @return 当前日期和时间的字符串表示 + */ + public static String dateTimeNow() { + return dateTimeNow(FormatsType.YYYYMMDDHHMMSS); + } + + /** + * 获取当前日期和时间的指定格式的字符串表示 + * + * @param format 日期时间格式,例如"YYYY-MM-DD HH:MM:SS" + * @return 当前日期和时间的字符串表示 + */ + public static String dateTimeNow(final FormatsType format) { + return parseDateToStr(format, new Date()); + } + + /** + * 将指定日期格式化为 YYYY-MM-DD 格式的字符串 + * + * @param date 要格式化的日期对象 + * @return 格式化后的日期字符串 + */ + public static String formatDate(final Date date) { + return parseDateToStr(FormatsType.YYYY_MM_DD, date); + } + + /** + * 将指定日期格式化为 YYYY-MM-DD HH:MM:SS 格式的字符串 + * + * @param date 要格式化的日期对象 + * @return 格式化后的日期时间字符串 + */ + public static String formatDateTime(final Date date) { + return parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, date); + } + + /** + * 将指定日期按照指定格式进行格式化 + * + * @param format 要使用的日期时间格式,例如"YYYY-MM-DD HH:MM:SS" + * @param date 要格式化的日期对象 + * @return 格式化后的日期时间字符串 + */ + public static String parseDateToStr(final FormatsType format, final Date date) { + return new SimpleDateFormat(format.getTimeFormat()).format(date); + } + + /** + * 将指定格式的日期时间字符串转换为 Date 对象 + * + * @param format 要解析的日期时间格式,例如"YYYY-MM-DD HH:MM:SS" + * @param ts 要解析的日期时间字符串 + * @return 解析后的 Date 对象 + * @throws RuntimeException 如果解析过程中发生异常 + */ + public static Date parseDateTime(final FormatsType format, final String ts) { + try { + return new SimpleDateFormat(format.getTimeFormat()).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * 将对象转换为日期对象 + * + * @param str 要转换的对象,通常是字符串 + * @return 转换后的日期对象,如果转换失败或输入为null,则返回null + */ + public static Date parseDate(Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), PARSE_PATTERNS); + } catch (ParseException e) { + return null; + } + } + + /** + * 获取服务器启动时间 + * + * @return 服务器启动时间的 Date 对象表示 + */ + public static Date getServerStartDate() { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算两个日期之间的天数差(以毫秒为单位) + * + * @param date1 第一个日期 + * @param date2 第二个日期 + * @return 两个日期之间的天数差的绝对值 + */ + public static int differentDaysByMillisecond(Date date1, Date date2) { + return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); + } + + /** + * 计算两个日期之间的时间差,并以天、小时和分钟的格式返回 + * + * @param endDate 结束日期 + * @param nowDate 当前日期 + * @return 表示时间差的字符串,格式为"天 小时 分钟" + */ + public static String getDatePoor(Date endDate, Date nowDate) { + long diffInMillis = endDate.getTime() - nowDate.getTime(); + long day = TimeUnit.MILLISECONDS.toDays(diffInMillis); + long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24; + long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60; + return String.format("%d天 %d小时 %d分钟", day, hour, min); + } + + /** + * 计算两个时间点的差值(天、小时、分钟、秒),当值为0时不显示该单位 + * + * @param endDate 结束时间 + * @param nowDate 当前时间 + * @return 时间差字符串,格式为 "x天 x小时 x分钟 x秒",若为 0 则不显示 + */ + public static String getTimeDifference(Date endDate, Date nowDate) { + long diffInMillis = endDate.getTime() - nowDate.getTime(); + long day = TimeUnit.MILLISECONDS.toDays(diffInMillis); + long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24; + long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60; + long sec = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60; + // 构建时间差字符串,条件是值不为0才显示 + StringBuilder result = new StringBuilder(); + if (day > 0) { + result.append(String.format("%d天 ", day)); + } + if (hour > 0) { + result.append(String.format("%d小时 ", hour)); + } + if (min > 0) { + result.append(String.format("%d分钟 ", min)); + } + if (sec > 0) { + result.append(String.format("%d秒", sec)); + } + return result.length() > 0 ? result.toString().trim() : "0秒"; + } + + /** + * 将 LocalDateTime 对象转换为 Date 对象 + * + * @param temporalAccessor 要转换的 LocalDateTime 对象 + * @return 转换后的 Date 对象 + */ + public static Date toDate(LocalDateTime temporalAccessor) { + ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** + * 将 LocalDate 对象转换为 Date 对象 + * + * @param temporalAccessor 要转换的 LocalDate 对象 + * @return 转换后的 Date 对象 + */ + public static Date toDate(LocalDate temporalAccessor) { + LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0)); + ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** + * 校验日期范围 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @param maxValue 最大时间跨度的限制值 + * @param unit 时间跨度的单位,可选择 "DAYS"、"HOURS" 或 "MINUTES" + */ + public static void validateDateRange(Date startDate, Date endDate, int maxValue, TimeUnit unit) { + // 校验结束日期不能早于开始日期 + if (endDate.before(startDate)) { + throw new ServiceException("结束日期不能早于开始日期"); + } + + // 计算时间跨度 + long diffInMillis = endDate.getTime() - startDate.getTime(); + + // 根据单位转换时间跨度 + long diff = switch (unit) { + case DAYS -> TimeUnit.MILLISECONDS.toDays(diffInMillis); + case HOURS -> TimeUnit.MILLISECONDS.toHours(diffInMillis); + case MINUTES -> TimeUnit.MILLISECONDS.toMinutes(diffInMillis); + default -> throw new IllegalArgumentException("不支持的时间单位"); + }; + + // 校验时间跨度不超过最大限制 + if (diff > maxValue) { + throw new ServiceException("最大时间跨度为 " + maxValue + " " + unit.toString().toLowerCase()); + } + } + + /** + * 将包含年月日的 Date 对象和时分秒字符串合并生成一个新的 Date 对象 + * + * @param date 仅包含年月日部分的 Date 对象(时分秒默认为 00:00:00) + * @param timeStr 时分秒字符串,格式为 "HH:mm:ss"(例如 "15:00:00") + * @return 合并后的包含日期和时间的 Date 对象 + */ + public static Date combineDateAndTime(Date date, String timeStr) { + // 转换 Date 为 LocalDate(系统默认时区) + Instant dateInstant = date.toInstant(); + LocalDate localDate = dateInstant.atZone(ZoneId.systemDefault()).toLocalDate(); + + // 使用指定格式解析时间字符串为 LocalTime + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); + LocalTime localTime = LocalTime.parse(timeStr, timeFormatter); + + // 合并 LocalDate 和 LocalTime 成 LocalDateTime + LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime); + + // 将 LocalDateTime 转换为 Instant,再转换为 Date + Instant combinedInstant = localDateTime.atZone(ZoneId.systemDefault()).toInstant(); + return Date.from(combinedInstant); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java new file mode 100644 index 0000000..b6acff7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java @@ -0,0 +1,93 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import io.github.linpeilie.Converter; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * Mapstruct 工具类 + *

参考文档:mapstruct-plus

+ * + * + * @author Michelle.Chung + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MapstructUtils { + + private final static Converter CONVERTER = SpringUtils.getBean(Converter.class); + + /** + * 将 T 类型对象,转换为 desc 类型的对象并返回 + * + * @param source 数据来源实体 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static V convert(T source, Class desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + return CONVERTER.convert(source, desc); + } + + /** + * 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象 + * + * @param source 数据来源实体 + * @param desc 转换后的对象 + * @return desc + */ + public static V convert(T source, V desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + return CONVERTER.convert(source, desc); + } + + /** + * 将 T 类型的集合,转换为 desc 类型的集合并返回 + * + * @param sourceList 数据来源实体列表 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static List convert(List sourceList, Class desc) { + if (ObjectUtil.isNull(sourceList)) { + return null; + } + if (CollUtil.isEmpty(sourceList)) { + return CollUtil.newArrayList(); + } + return CONVERTER.convert(sourceList, desc); + } + + /** + * 将 Map 转换为 beanClass 类型的集合并返回 + * + * @param map 数据来源 + * @param beanClass bean类 + * @return bean对象 + */ + public static T convert(Map map, Class beanClass) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(beanClass)) { + return null; + } + return CONVERTER.convert(map, beanClass); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java new file mode 100644 index 0000000..48dfc08 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java @@ -0,0 +1,33 @@ +package org.dromara.common.core.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 获取i18n资源文件 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MessageUtils { + + private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class); + + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) { + try { + return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale()); + } catch (NoSuchMessageException e) { + return code; + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java new file mode 100644 index 0000000..199fd82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java @@ -0,0 +1,60 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.function.Function; + +/** + * 对象工具类 + * + * @author 秋辞未寒 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ObjectUtils extends ObjectUtil { + + /** + * 如果对象不为空,则获取对象中的某个字段 ObjectUtils.notNullGetter(user, User::getName); + * + * @param obj 对象 + * @param func 获取方法 + * @return 对象字段 + */ + public static E notNullGetter(T obj, Function func) { + if (isNotNull(obj) && isNotNull(func)) { + return func.apply(obj); + } + return null; + } + + /** + * 如果对象不为空,则获取对象中的某个字段,否则返回默认值 + * + * @param obj 对象 + * @param func 获取方法 + * @param defaultValue 默认值 + * @return 对象字段 + */ + public static E notNullGetter(T obj, Function func, E defaultValue) { + if (isNotNull(obj) && isNotNull(func)) { + return func.apply(obj); + } + return defaultValue; + } + + /** + * 如果值不为空,则返回值,否则返回默认值 + * + * @param obj 对象 + * @param defaultValue 默认值 + * @return 对象字段 + */ + public static T notNull(T obj, T defaultValue) { + if (isNotNull(obj)) { + return obj; + } + return defaultValue; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java new file mode 100644 index 0000000..bd1aab8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java @@ -0,0 +1,289 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.convert.Convert; +import cn.hutool.extra.servlet.JakartaServletUtil; +import cn.hutool.http.HttpStatus; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.io.IOException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * 客户端工具类,提供获取请求参数、响应处理、头部信息等常用操作 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ServletUtils extends JakartaServletUtil { + + /** + * 获取指定名称的 String 类型的请求参数 + * + * @param name 参数名 + * @return 参数值 + */ + public static String getParameter(String name) { + return getRequest().getParameter(name); + } + + /** + * 获取指定名称的 String 类型的请求参数,若参数不存在,则返回默认值 + * + * @param name 参数名 + * @param defaultValue 默认值 + * @return 参数值或默认值 + */ + public static String getParameter(String name, String defaultValue) { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取指定名称的 Integer 类型的请求参数 + * + * @param name 参数名 + * @return 参数值 + */ + public static Integer getParameterToInt(String name) { + return Convert.toInt(getRequest().getParameter(name)); + } + + /** + * 获取指定名称的 Integer 类型的请求参数,若参数不存在,则返回默认值 + * + * @param name 参数名 + * @param defaultValue 默认值 + * @return 参数值或默认值 + */ + public static Integer getParameterToInt(String name, Integer defaultValue) { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取指定名称的 Boolean 类型的请求参数 + * + * @param name 参数名 + * @return 参数值 + */ + public static Boolean getParameterToBool(String name) { + return Convert.toBool(getRequest().getParameter(name)); + } + + /** + * 获取指定名称的 Boolean 类型的请求参数,若参数不存在,则返回默认值 + * + * @param name 参数名 + * @param defaultValue 默认值 + * @return 参数值或默认值 + */ + public static Boolean getParameterToBool(String name, Boolean defaultValue) { + return Convert.toBool(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取所有请求参数(以 Map 的形式返回) + * + * @param request 请求对象{@link ServletRequest} + * @return 请求参数的 Map,键为参数名,值为参数值数组 + */ + public static Map getParams(ServletRequest request) { + final Map map = request.getParameterMap(); + return Collections.unmodifiableMap(map); + } + + /** + * 获取所有请求参数(以 Map 的形式返回,值为字符串形式的拼接) + * + * @param request 请求对象{@link ServletRequest} + * @return 请求参数的 Map,键为参数名,值为拼接后的字符串 + */ + public static Map getParamMap(ServletRequest request) { + Map params = new HashMap<>(); + for (Map.Entry entry : getParams(request).entrySet()) { + params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR)); + } + return params; + } + + /** + * 获取当前 HTTP 请求对象 + * + * @return 当前 HTTP 请求对象 + */ + public static HttpServletRequest getRequest() { + try { + return getRequestAttributes().getRequest(); + } catch (Exception e) { + return null; + } + } + + /** + * 获取当前 HTTP 响应对象 + * + * @return 当前 HTTP 响应对象 + */ + public static HttpServletResponse getResponse() { + try { + return getRequestAttributes().getResponse(); + } catch (Exception e) { + return null; + } + } + + /** + * 获取当前请求的 HttpSession 对象 + *

+ * 如果当前请求已经关联了一个会话(即已经存在有效的 session ID), + * 则返回该会话对象;如果没有关联会话,则会创建一个新的会话对象并返回。 + *

+ * HttpSession 用于存储会话级别的数据,如用户登录信息、购物车内容等, + * 可以在多个请求之间共享会话数据 + * + * @return 当前请求的 HttpSession 对象 + */ + public static HttpSession getSession() { + return getRequest().getSession(); + } + + /** + * 获取当前请求的请求属性 + * + * @return {@link ServletRequestAttributes} 请求属性对象 + */ + public static ServletRequestAttributes getRequestAttributes() { + try { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } catch (Exception e) { + return null; + } + } + + /** + * 获取指定请求头的值,如果头部为空则返回空字符串 + * + * @param request 请求对象 + * @param name 头部名称 + * @return 头部值 + */ + public static String getHeader(HttpServletRequest request, String name) { + String value = request.getHeader(name); + if (StringUtils.isEmpty(value)) { + return StringUtils.EMPTY; + } + return urlDecode(value); + } + + /** + * 获取所有请求头的 Map,键为头部名称,值为头部值 + * + * @param request 请求对象 + * @return 请求头的 Map + */ + public static Map getHeaders(HttpServletRequest request) { + Map map = new LinkedCaseInsensitiveMap<>(); + Enumeration enumeration = request.getHeaderNames(); + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + String key = enumeration.nextElement(); + String value = request.getHeader(key); + map.put(key, value); + } + } + return map; + } + + /** + * 将字符串渲染到客户端(以 JSON 格式返回) + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + */ + public static void renderString(HttpServletResponse response, String string) { + try { + response.setStatus(HttpStatus.HTTP_OK); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); + response.getWriter().print(string); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 判断当前请求是否为 Ajax 异步请求 + * + * @param request 请求对象 + * @return 是否为 Ajax 请求 + */ + public static boolean isAjaxRequest(HttpServletRequest request) { + + // 判断 Accept 头部是否包含 application/json + String accept = request.getHeader("accept"); + if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) { + return true; + } + + // 判断 X-Requested-With 头部是否包含 XMLHttpRequest + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) { + return true; + } + + // 判断 URI 后缀是否为 .json 或 .xml + String uri = request.getRequestURI(); + if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) { + return true; + } + + // 判断请求参数 __ajax 是否为 json 或 xml + String ajax = request.getParameter("__ajax"); + return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml"); + } + + /** + * 获取客户端 IP 地址 + * + * @return 客户端 IP 地址 + */ + public static String getClientIP() { + return getClientIP(getRequest()); + } + + /** + * 对内容进行 URL 编码 + * + * @param str 内容 + * @return 编码后的内容 + */ + public static String urlEncode(String str) { + return URLEncoder.encode(str, StandardCharsets.UTF_8); + } + + /** + * 对内容进行 URL 解码 + * + * @param str 内容 + * @return 解码后的内容 + */ + public static String urlDecode(String str) { + return URLDecoder.decode(str, StandardCharsets.UTF_8); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java new file mode 100644 index 0000000..169c6e2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java @@ -0,0 +1,67 @@ +package org.dromara.common.core.utils; + +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.thread.Threading; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * spring工具类 + * + * @author Lion Li + */ +@Component +public final class SpringUtils extends SpringUtil { + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + */ + public static boolean containsBean(String name) { + return getBeanFactory().containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 + * 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().isSingleton(name); + } + + /** + * @return Class 注册对象的类型 + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getAliases(name); + } + + /** + * 获取aop代理对象 + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) getBean(invoker.getClass()); + } + + + /** + * 获取spring上下文 + */ + public static ApplicationContext context() { + return getApplicationContext(); + } + + public static boolean isVirtual() { + return Threading.VIRTUAL.isActive(getBean(Environment.class)); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java new file mode 100644 index 0000000..1342deb --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java @@ -0,0 +1,283 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * stream 流工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StreamUtils { + + /** + * 将collection过滤 + * + * @param collection 需要转化的集合 + * @param function 过滤方法 + * @return 过滤后的list + */ + public static List filter(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + return collection.stream().filter(function).collect(Collectors.toList()); + } + + /** + * 找到流中满足条件的第一个元素 + * + * @param collection 需要查询的集合 + * @param function 过滤方法 + * @return 找到符合条件的第一个元素,没有则返回null + */ + public static E findFirst(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return null; + } + return collection.stream().filter(function).findFirst().orElse(null); + } + + /** + * 找到流中任意一个满足条件的元素 + * + * @param collection 需要查询的集合 + * @param function 过滤方法 + * @return 找到符合条件的任意一个元素,没有则返回null + */ + public static Optional findAny(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return Optional.empty(); + } + return collection.stream().filter(function).findAny(); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function) { + return join(collection, function, StringUtils.SEPARATOR); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @param delimiter 拼接符 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function, CharSequence delimiter) { + if (CollUtil.isEmpty(collection)) { + return StringUtils.EMPTY; + } + return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); + } + + /** + * 将collection排序 + * + * @param collection 需要转化的集合 + * @param comparing 排序方法 + * @return 排序后的list + */ + public static List sorted(Collection collection, Comparator comparing) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList()); + } + + /** + * 将collection转化为类型不变的map
+ * {@code Collection ----> Map} + * + * @param collection 需要转化的集合 + * @param key V类型转化为K类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @return 转化后的map + */ + public static Map toIdentityMap(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l)); + } + + /** + * 将Collection转化为map(value类型与collection的泛型不同)
+ * {@code Collection -----> Map } + * + * @param collection 需要转化的集合 + * @param key E类型转化为K类型的lambda方法 + * @param value E类型转化为V类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @param map中的value类型 + * @return 转化后的map + */ + public static Map toMap(Collection collection, Function key, Function value) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l)); + } + + /** + * 将collection按照规则(比如有相同的班级id)分类成map
+ * {@code Collection -------> Map> } + * + * @param collection 需要分类的集合 + * @param key 分类的规则 + * @param collection中的泛型 + * @param map中的key类型 + * @return 分类后的map + */ + public static Map> groupByKey(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map>> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 集合元素类型 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @return 分类后的map + */ + public static Map>> groupBy2Key(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @param collection中的泛型 + * @return 分类后的map + */ + public static Map> group2Map(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); + } + + /** + * 将collection转化为List集合,但是两者的泛型不同
+ * {@code Collection ------> List } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为list泛型的lambda表达式 + * @param collection中的泛型 + * @param List中的泛型 + * @return 转化后的list + */ + public static List toList(Collection collection, Function function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + .collect(Collectors.toList()); + } + + /** + * 将collection转化为Set集合,但是两者的泛型不同
+ * {@code Collection ------> Set } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为set泛型的lambda表达式 + * @param collection中的泛型 + * @param Set中的泛型 + * @return 转化后的Set + */ + public static Set toSet(Collection collection, Function function) { + if (CollUtil.isEmpty(collection) || function == null) { + return CollUtil.newHashSet(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + + /** + * 合并两个相同key类型的map + * + * @param map1 第一个需要合并的 map + * @param map2 第二个需要合并的 map + * @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况 + * @param map中的key类型 + * @param 第一个 map的value类型 + * @param 第二个 map的value类型 + * @param 最终map的value类型 + * @return 合并后的map + */ + public static Map merge(Map map1, Map map2, BiFunction merge) { + if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) { + return MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map1)) { + map1 = MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map2)) { + map2 = MapUtil.newHashMap(); + } + Set key = new HashSet<>(); + key.addAll(map1.keySet()); + key.addAll(map2.keySet()); + Map map = new HashMap<>(); + for (K t : key) { + X x = map1.get(t); + Y y = map2.get(t); + V z = merge.apply(x, y); + if (z != null) { + map.put(t, z); + } + } + return map; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java new file mode 100644 index 0000000..0363ad4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java @@ -0,0 +1,342 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import org.springframework.util.AntPathMatcher; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 字符串工具类 + * + * @author Lion Li + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + public static final String SEPARATOR = ","; + + public static final String SLASH = "/"; + + @Deprecated + private StringUtils() { + } + + /** + * 获取参数不为空值 + * + * @param str defaultValue 要判断的value + * @return value 返回值 + */ + public static String blankToDefault(String str, String defaultValue) { + return StrUtil.blankToDefault(str, defaultValue); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return StrUtil.isEmpty(str); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return StrUtil.trim(str); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + return substring(str, start, str.length()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + return StrUtil.sub(str, start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is {} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + return StrUtil.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) { + return Validator.isUrl(link); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static Set str2Set(String str, String sep) { + return new HashSet<>(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList<>(); + if (isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && isBlank(string)) { + continue; + } + if (trim) { + string = trim(string); + } + list.add(string); + } + + return list; + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences); + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) { + return StrUtil.toUnderlineCase(str); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + return StrUtil.equalsAnyIgnoreCase(str, strs); + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + return StrUtil.upperFirst(StrUtil.toCamelCase(name)); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + return StrUtil.toCamelCase(s); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || CollUtil.isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static String padl(final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static String padl(final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + sb.append(String.valueOf(c).repeat(size - len)); + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + sb.append(String.valueOf(c).repeat(Math.max(0, size))); + } + return sb.toString(); + } + + /** + * 切分字符串(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @return 分割后的数据列表 + */ + public static List splitList(String str) { + return splitTo(str, Convert::toStr); + } + + /** + * 切分字符串 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @return 分割后的数据列表 + */ + public static List splitList(String str, String separator) { + return splitTo(str, separator, Convert::toStr); + } + + /** + * 切分字符串自定义转换(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, Function mapper) { + return splitTo(str, SEPARATOR, mapper); + } + + /** + * 切分字符串自定义转换 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, String separator, Function mapper) { + if (isBlank(str)) { + return new ArrayList<>(0); + } + return StrUtil.split(str, separator) + .stream() + .filter(Objects::nonNull) + .map(mapper) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + /** + * 不区分大小写检查 CharSequence 是否以指定的前缀开头。 + * + * @param str 要检查的 CharSequence 可能为 null + * @param prefixs 要查找的前缀可能为 null + * @return 是否包含 + */ + public static boolean startWithAnyIgnoreCase(CharSequence str, CharSequence... prefixs) { + // 判断是否是以指定字符串开头 + for (CharSequence prefix : prefixs) { + if (StringUtils.startsWithIgnoreCase(str, prefix)) { + return true; + } + } + return false; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java new file mode 100644 index 0000000..82ea5ca --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java @@ -0,0 +1,63 @@ +package org.dromara.common.core.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.*; + +/** + * 线程相关工具类. + * + * @author ruoyi + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Threads { + /** + * 停止线程池 + * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. + * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. + * 如果仍然超時,則強制退出. + * 另对在shutdown时线程本身被调用中断做了处理. + */ + public static void shutdownAndAwaitTermination(ExecutorService pool) { + if (pool != null && !pool.isShutdown()) { + pool.shutdown(); + try { + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + log.info("Pool did not terminate"); + } + } + } catch (InterruptedException ie) { + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + + /** + * 打印线程异常信息 + */ + public static void printException(Runnable r, Throwable t) { + if (t == null && r instanceof Future) { + try { + Future future = (Future) r; + if (future.isDone()) { + future.get(); + } + } catch (CancellationException ce) { + t = ce; + } catch (ExecutionException ee) { + t = ee.getCause(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (t != null) { + log.error(t.getMessage(), t); + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java new file mode 100644 index 0000000..5f60ebf --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java @@ -0,0 +1,123 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.parser.NodeParser; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.reflect.ReflectUtils; + +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 扩展 hutool TreeUtil 封装系统树构建 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TreeBuildUtils extends TreeUtil { + + /** + * 根据前端定制差异化字段 + */ + public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); + + /** + * 构建树形结构 + * + * @param 输入节点的类型 + * @param 节点ID的类型 + * @param list 节点列表,其中包含了要构建树形结构的所有节点 + * @param nodeParser 解析器,用于将输入节点转换为树节点 + * @return 构建好的树形结构列表 + */ + public static List> build(List list, NodeParser nodeParser) { + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + K k = ReflectUtils.invokeGetter(list.get(0), "parentId"); + return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser); + } + + /** + * 构建树形结构 + * + * @param 输入节点的类型 + * @param 节点ID的类型 + * @param parentId 顶级节点 + * @param list 节点列表,其中包含了要构建树形结构的所有节点 + * @param nodeParser 解析器,用于将输入节点转换为树节点 + * @return 构建好的树形结构列表 + */ + public static List> build(List list, K parentId, NodeParser nodeParser) { + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser); + } + + /** + * 构建多根节点的树结构(支持多个顶级节点) + * + * @param list 原始数据列表 + * @param getId 获取节点 ID 的方法引用,例如:node -> node.getId() + * @param getParentId 获取节点父级 ID 的方法引用,例如:node -> node.getParentId() + * @param parser 树节点属性映射器,用于将原始节点 T 转为 Tree 节点 + * @param 原始数据类型(如实体类、DTO 等) + * @param 节点 ID 类型(如 Long、String) + * @return 构建完成的树形结构(可能包含多个顶级根节点) + */ + public static List> buildMultiRoot(List list, Function getId, Function getParentId, NodeParser parser) { + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + + Set rootParentIds = StreamUtils.toSet(list, getParentId); + rootParentIds.removeAll(StreamUtils.toSet(list, getId)); + + // 构建每一个根 parentId 下的树,并合并成最终结果列表 + return rootParentIds.stream() + .flatMap(rootParentId -> TreeUtil.build(list, rootParentId, parser).stream()) + .collect(Collectors.toList()); + } + + /** + * 获取节点列表中所有节点的叶子节点 + * + * @param 节点ID的类型 + * @param nodes 节点列表 + * @return 包含所有叶子节点的列表 + */ + public static List> getLeafNodes(List> nodes) { + if (CollUtil.isEmpty(nodes)) { + return CollUtil.newArrayList(); + } + return nodes.stream() + .flatMap(TreeBuildUtils::extractLeafNodes) + .collect(Collectors.toList()); + } + + /** + * 获取指定节点下的所有叶子节点 + * + * @param 节点ID的类型 + * @param node 要查找叶子节点的根节点 + * @return 包含所有叶子节点的列表 + */ + private static Stream> extractLeafNodes(Tree node) { + if (!node.hasChild()) { + return Stream.of(node); + } else { + // 递归调用,获取所有子节点的叶子节点 + return node.getChildren().stream() + .flatMap(TreeBuildUtils::extractLeafNodes); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java new file mode 100644 index 0000000..06b8fd6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java @@ -0,0 +1,35 @@ +package org.dromara.common.core.utils; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Set; + +/** + * Validator 校验框架工具 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ValidatorUtils { + + private static final Validator VALID = SpringUtils.getBean(Validator.class); + + /** + * 对给定对象进行参数校验,并根据指定的校验组进行校验 + * + * @param object 要进行校验的对象 + * @param groups 校验组 + * @throws ConstraintViolationException 如果校验不通过,则抛出参数校验异常 + */ + public static void validate(T object, Class... groups) { + Set> validate = VALID.validate(object, groups); + if (!validate.isEmpty()) { + throw new ConstraintViolationException("参数校验异常", validate); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java new file mode 100644 index 0000000..1e5d160 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java @@ -0,0 +1,74 @@ +package org.dromara.common.core.utils.file; + +import cn.hutool.core.io.FileUtil; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +/** + * 文件处理工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class FileUtils extends FileUtil { + + /** + * 下载文件名重新编码 + * + * @param response 响应对象 + * @param realFileName 真实文件名 + */ + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) { + String percentEncodedFileName = percentEncode(realFileName); + String contentDispositionValue = "attachment; filename=%s;filename*=utf-8''%s".formatted(percentEncodedFileName, percentEncodedFileName); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); + response.setHeader("Content-disposition", contentDispositionValue); + response.setHeader("download-filename", percentEncodedFileName); + } + + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * @return 百分号编码后的字符串 + */ + public static String percentEncode(String s) { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8); + return encode.replaceAll("\\+", "%20"); + } + + /** + * 删除目录 + * + * @param path 路径 + * @throws IOException I/O异常 + */ + public static void deleteDirectory(Path path) throws IOException { + // walkFileTree会递归遍历path下所有文件和文件夹 + Files.walkFileTree(path, new SimpleFileVisitor<>() { + // 先删除文件 + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + // 然后删除目录 + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java new file mode 100644 index 0000000..23fa2cf --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java @@ -0,0 +1,40 @@ +package org.dromara.common.core.utils.file; + +/** + * 媒体类型工具类 + * + * @author ruoyi + */ +public class MimeTypeUtils { + public static final String IMAGE_PNG = "image/png"; + + public static final String IMAGE_JPG = "image/jpg"; + + public static final String IMAGE_JPEG = "image/jpeg"; + + public static final String IMAGE_BMP = "image/bmp"; + + public static final String IMAGE_GIF = "image/gif"; + + public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"}; + + public static final String[] FLASH_EXTENSION = {"swf", "flv"}; + + public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb"}; + + public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"}; + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + // 图片 + "bmp", "gif", "jpg", "jpeg", "png", + // word excel powerpoint + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + // 压缩文件 + "rar", "zip", "gz", "bz2", + // 视频格式 + "mp4", "avi", "rmvb", + // pdf + "pdf"}; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java new file mode 100644 index 0000000..3f7cd57 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java @@ -0,0 +1,33 @@ +package org.dromara.common.core.utils.ip; + +import cn.hutool.core.net.NetUtil; +import cn.hutool.http.HtmlUtil; +import org.dromara.common.core.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * 获取地址类 + * + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AddressUtils { + + // 未知地址 + public static final String UNKNOWN = "XX XX"; + + public static String getRealAddressByIP(String ip) { + if (StringUtils.isBlank(ip)) { + return UNKNOWN; + } + // 内网不查询 + ip = StringUtils.contains(ip, "0:0:0:0:0:0:0:1") ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip); + if (NetUtil.isInnerIP(ip)) { + return "内网IP"; + } + return RegionUtils.getCityInfo(ip); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java new file mode 100644 index 0000000..6e2a44e --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java @@ -0,0 +1,67 @@ +package org.dromara.common.core.utils.ip; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.ObjectUtil; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.file.FileUtils; +import lombok.extern.slf4j.Slf4j; +import org.lionsoul.ip2region.xdb.Searcher; + +import java.io.File; + +/** + * 根据ip地址定位工具类,离线方式 + * 参考地址:集成 ip2region 实现离线IP地址定位库 + * + * @author lishuyan + */ +@Slf4j +public class RegionUtils { + + private static final Searcher SEARCHER; + + static { + String fileName = "/ip2region.xdb"; + File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName); + if (!FileUtils.exist(existFile)) { + ClassPathResource fileStream = new ClassPathResource(fileName); + if (ObjectUtil.isEmpty(fileStream.getStream())) { + throw new ServiceException("RegionUtils初始化失败,原因:IP地址库数据不存在!"); + } + FileUtils.writeFromStream(fileStream.getStream(), existFile); + } + + String dbPath = existFile.getPath(); + + // 1、从 dbPath 加载整个 xdb 到内存。 + byte[] cBuff; + try { + cBuff = Searcher.loadContentFromFile(dbPath); + } catch (Exception e) { + throw new ServiceException("RegionUtils初始化失败,原因:从ip2region.xdb文件加载内容失败!" + e.getMessage()); + } + // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。 + try { + SEARCHER = Searcher.newWithBuffer(cBuff); + } catch (Exception e) { + throw new ServiceException("RegionUtils初始化失败,原因:" + e.getMessage()); + } + } + + /** + * 根据IP地址离线获取城市 + */ + public static String getCityInfo(String ip) { + try { + ip = ip.trim(); + // 3、执行查询 + String region = SEARCHER.search(ip); + return region.replace("0|", "").replace("|0", ""); + } catch (Exception e) { + log.error("IP地址离线获取城市异常 {}", ip); + return "未知"; + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000..367e8c9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java @@ -0,0 +1,56 @@ +package org.dromara.common.core.utils.reflect; + +import cn.hutool.core.util.ReflectUtil; +import org.dromara.common.core.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.lang.reflect.Method; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author Lion Li + */ +@SuppressWarnings("rawtypes") +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ReflectUtils extends ReflectUtil { + + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invoke(object, getterMethodName); + } + return (E) object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, E value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) { + if (i < names.length - 1) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invoke(object, getterMethodName); + } else { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + Method method = getMethodByName(object.getClass(), setterMethodName); + invoke(object, method, value); + } + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java new file mode 100644 index 0000000..6dde129 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.utils.regex; + + +import cn.hutool.core.util.ReUtil; +import org.dromara.common.core.constant.RegexConstants; + +/** + * 正则相关工具类 + * + * @author Feng + */ +public final class RegexUtils extends ReUtil { + + /** + * 从输入字符串中提取匹配的部分,如果没有匹配则返回默认值 + * + * @param input 要提取的输入字符串 + * @param regex 用于匹配的正则表达式,可以使用 {@link RegexConstants} 中定义的常量 + * @param defaultInput 如果没有匹配时返回的默认值 + * @return 如果找到匹配的部分,则返回匹配的部分,否则返回默认值 + */ + public static String extractFromString(String input, String regex, String defaultInput) { + try { + String str = ReUtil.get(regex, input, 1); + return str == null ? defaultInput : str; + } catch (Exception e) { + return defaultInput; + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java new file mode 100644 index 0000000..c0dda20 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java @@ -0,0 +1,105 @@ +package org.dromara.common.core.utils.regex; + +import cn.hutool.core.exceptions.ValidateException; +import cn.hutool.core.lang.Validator; +import org.dromara.common.core.factory.RegexPatternPoolFactory; + +import java.util.regex.Pattern; + +/** + * 正则字段校验器 + * 主要验证字段非空、是否为满足指定格式等 + * + * @author Feng + */ +public class RegexValidator extends Validator { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + public static final Pattern DICTIONARY_TYPE = RegexPatternPoolFactory.DICTIONARY_TYPE; + + /** + * 身份证号码(后6位) + */ + public static final Pattern ID_CARD_LAST_6 = RegexPatternPoolFactory.ID_CARD_LAST_6; + + /** + * QQ号码 + */ + public static final Pattern QQ_NUMBER = RegexPatternPoolFactory.QQ_NUMBER; + + /** + * 邮政编码 + */ + public static final Pattern POSTAL_CODE = RegexPatternPoolFactory.POSTAL_CODE; + + /** + * 注册账号 + */ + public static final Pattern ACCOUNT = RegexPatternPoolFactory.ACCOUNT; + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + public static final Pattern PASSWORD = RegexPatternPoolFactory.PASSWORD; + + /** + * 通用状态(0表示正常,1表示停用) + */ + public static final Pattern STATUS = RegexPatternPoolFactory.STATUS; + + + /** + * 检查输入的账号是否匹配预定义的规则 + * + * @param value 要验证的账号 + * @return 如果账号符合规则,返回 true;否则,返回 false。 + */ + public static boolean isAccount(CharSequence value) { + return isMatchRegex(ACCOUNT, value); + } + + /** + * 验证输入的账号是否符合规则,如果不符合,则抛出 ValidateException 异常 + * + * @param value 要验证的账号 + * @param errorMsg 验证失败时抛出的异常消息 + * @param CharSequence 的子类型 + * @return 如果验证通过,返回输入的账号 + * @throws ValidateException 如果验证失败 + */ + public static T validateAccount(T value, String errorMsg) throws ValidateException { + if (!isAccount(value)) { + throw new ValidateException(errorMsg); + } + return value; + } + + /** + * 检查输入的状态是否匹配预定义的规则 + * + * @param value 要验证的状态 + * @return 如果状态符合规则,返回 true;否则,返回 false。 + */ + public static boolean isStatus(CharSequence value) { + return isMatchRegex(STATUS, value); + } + + /** + * 验证输入的状态是否符合规则,如果不符合,则抛出 ValidateException 异常 + * + * @param value 要验证的状态 + * @param errorMsg 验证失败时抛出的异常消息 + * @param CharSequence 的子类型 + * @return 如果验证通过,返回输入的状态 + * @throws ValidateException 如果验证失败 + */ + public static T validateStatus(T value, String errorMsg) throws ValidateException { + if (!isStatus(value)) { + throw new ValidateException(errorMsg); + } + return value; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java new file mode 100644 index 0000000..ba737b6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java @@ -0,0 +1,69 @@ +package org.dromara.common.core.utils.sql; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.StringUtils; + +/** + * sql操作工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SqlUtil { + + /** + * 定义常用的 sql关键字 + */ + public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()"; + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new IllegalArgumentException("参数不符合规范,不能进行查询"); + } + return value; + } + + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } + + /** + * SQL关键字检查 + */ + public static void filterKeyword(String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new IllegalArgumentException("参数存在SQL注入风险"); + } + } + } + + /** + * 校验排序字段是否合法(防止 SQL 注入) + * + * @param sortField 排序字段 + * @return 是否存在 SQL 注入 + */ + public static boolean validSortField(String sortField) { + if (StringUtils.isBlank(sortField)) { + return false; + } + return !StringUtils.containsAny(sortField, "=", "(", ")", " "); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java new file mode 100644 index 0000000..0275899 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java @@ -0,0 +1,9 @@ +package org.dromara.common.core.validate; + +/** + * 校验分组 add + * + * @author Lion Li + */ +public interface AddGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java new file mode 100644 index 0000000..77c5040 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java @@ -0,0 +1,9 @@ +package org.dromara.common.core.validate; + +/** + * 校验分组 edit + * + * @author Lion Li + */ +public interface EditGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java new file mode 100644 index 0000000..02a0ac2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java @@ -0,0 +1,9 @@ +package org.dromara.common.core.validate; + +/** + * 校验分组 query + * + * @author Lion Li + */ +public interface QueryGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java new file mode 100644 index 0000000..3d4adb9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java @@ -0,0 +1,48 @@ +package org.dromara.common.core.validate.enumd; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.*; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 自定义枚举校验 + * + * @author 秋辞未寒 + * @date 2024-12-09 + */ +@Documented +@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) +@Retention(RUNTIME) +@Repeatable(EnumPattern.List.class) // 允许在同一元素上多次使用该注解 +@Constraint(validatedBy = {EnumPatternValidator.class}) +public @interface EnumPattern { + + /** + * 需要校验的枚举类型 + */ + Class> type(); + + /** + * 枚举类型校验值字段名称 + * 需确保该字段实现了 getter 方法 + */ + String fieldName(); + + String message() default "输入值不在枚举范围内"; + + Class[] groups() default {}; + + Class[] payload() default {}; + + @Documented + @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) + @Retention(RUNTIME) + @interface List { + EnumPattern[] value(); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java new file mode 100644 index 0000000..923c423 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.validate.enumd; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; + +/** + * 自定义枚举校验注解实现 + * + * @author 秋辞未寒 + * @date 2024-12-09 + */ +public class EnumPatternValidator implements ConstraintValidator { + + private EnumPattern annotation;; + + @Override + public void initialize(EnumPattern annotation) { + ConstraintValidator.super.initialize(annotation); + this.annotation = annotation; + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + if (StringUtils.isNotBlank(value)) { + String fieldName = annotation.fieldName(); + for (Object e : annotation.type().getEnumConstants()) { + if (value.equals(ReflectUtils.invokeGetter(e, fieldName))) { + return true; + } + } + } + return false; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java new file mode 100644 index 0000000..eed495f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java @@ -0,0 +1,26 @@ +package org.dromara.common.core.xss; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义xss校验注解 + * + * @author Lion Li + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) +@Constraint(validatedBy = {XssValidator.class}) +public @interface Xss { + + String message() default "不允许任何脚本运行"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java new file mode 100644 index 0000000..9c32563 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java @@ -0,0 +1,21 @@ +package org.dromara.common.core.xss; + +import cn.hutool.core.util.ReUtil; +import cn.hutool.http.HtmlUtil; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +/** + * 自定义xss校验注解实现 + * + * @author Lion Li + */ +public class XssValidator implements ConstraintValidator { + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..3395e73 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,6 @@ +org.dromara.common.core.config.ApplicationConfig +org.dromara.common.core.config.AsyncConfig +org.dromara.common.core.config.RuoYiConfig +org.dromara.common.core.config.ThreadPoolConfig +org.dromara.common.core.config.ValidatorConfig +org.dromara.common.core.utils.SpringUtils diff --git a/ruoyi-common/ruoyi-common-doc/pom.xml b/ruoyi-common/ruoyi-common-doc/pom.xml new file mode 100644 index 0000000..2f0b583 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/pom.xml @@ -0,0 +1,52 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-doc + + + ruoyi-common-doc 系统接口 + + + + + org.dromara + ruoyi-common-core + + + + org.springdoc + springdoc-openapi-starter-webmvc-api + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + + com.github.therapi + therapi-runtime-javadoc + + + + com.fasterxml.jackson.module + jackson-module-kotlin + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + 4.4.0 + + + + + diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java new file mode 100644 index 0000000..069ef9a --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java @@ -0,0 +1,126 @@ +package org.dromara.common.doc.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.doc.config.properties.SpringDocProperties; +import org.dromara.common.doc.handler.OpenApiHandler; +import org.springdoc.core.configuration.SpringDocConfiguration; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.OpenApiCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.properties.SpringDocConfigProperties; +import org.springdoc.core.providers.JavadocProvider; +import org.springdoc.core.service.OpenAPIService; +import org.springdoc.core.service.SecurityService; +import org.springdoc.core.utils.PropertyResolverUtils; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Swagger 文档配置 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@AutoConfiguration(before = SpringDocConfiguration.class) +@EnableConfigurationProperties(SpringDocProperties.class) +@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true) +public class SpringDocConfig { + + private final ServerProperties serverProperties; + + @Bean + @ConditionalOnMissingBean(OpenAPI.class) + public OpenAPI openApi(SpringDocProperties properties) { + OpenAPI openApi = new OpenAPI(); + // 文档基本信息 + SpringDocProperties.InfoProperties infoProperties = properties.getInfo(); + Info info = convertInfo(infoProperties); + openApi.info(info); + // 扩展文档信息 + openApi.externalDocs(properties.getExternalDocs()); + openApi.tags(properties.getTags()); + openApi.paths(properties.getPaths()); + openApi.components(properties.getComponents()); + Set keySet = properties.getComponents().getSecuritySchemes().keySet(); + List list = new ArrayList<>(); + SecurityRequirement securityRequirement = new SecurityRequirement(); + keySet.forEach(securityRequirement::addList); + list.add(securityRequirement); + openApi.security(list); + + return openApi; + } + + private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) { + Info info = new Info(); + info.setTitle(infoProperties.getTitle()); + info.setDescription(infoProperties.getDescription()); + info.setContact(infoProperties.getContact()); + info.setLicense(infoProperties.getLicense()); + info.setVersion(infoProperties.getVersion()); + return info; + } + + /** + * 自定义 openapi 处理器 + */ + @Bean + public OpenAPIService openApiBuilder(Optional openAPI, + SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomisers, + Optional> serverBaseUrlCustomisers, Optional javadocProvider) { + return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); + } + + /** + * 对已经生成好的 OpenApi 进行自定义操作 + */ + @Bean + public OpenApiCustomizer openApiCustomizer() { + String contextPath = serverProperties.getServlet().getContextPath(); + String finalContextPath; + if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) { + finalContextPath = ""; + } else { + finalContextPath = contextPath; + } + // 对所有路径增加前置上下文路径 + return openApi -> { + Paths oldPaths = openApi.getPaths(); + if (oldPaths instanceof PlusPaths) { + return; + } + PlusPaths newPaths = new PlusPaths(); + oldPaths.forEach((k, v) -> newPaths.addPathItem(finalContextPath + k, v)); + openApi.setPaths(newPaths); + }; + } + + /** + * 单独使用一个类便于判断 解决springdoc路径拼接重复问题 + * + * @author Lion Li + */ + static class PlusPaths extends Paths { + + public PlusPaths() { + super(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java new file mode 100644 index 0000000..eae3b4c --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java @@ -0,0 +1,94 @@ +package org.dromara.common.doc.config.properties; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.ExternalDocumentation; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.tags.Tag; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; + +import java.util.List; + +/** + * swagger 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "springdoc") +public class SpringDocProperties { + + /** + * 文档基本信息 + */ + @NestedConfigurationProperty + private InfoProperties info = new InfoProperties(); + + /** + * 扩展文档地址 + */ + @NestedConfigurationProperty + private ExternalDocumentation externalDocs; + + /** + * 标签 + */ + private List tags = null; + + /** + * 路径 + */ + @NestedConfigurationProperty + private Paths paths = null; + + /** + * 组件 + */ + @NestedConfigurationProperty + private Components components = null; + + /** + *

+ * 文档的基础属性信息 + *

+ * + * @see io.swagger.v3.oas.models.info.Info + * + * 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来 + */ + @Data + public static class InfoProperties { + + /** + * 标题 + */ + private String title = null; + + /** + * 描述 + */ + private String description = null; + + /** + * 联系人信息 + */ + @NestedConfigurationProperty + private Contact contact = null; + + /** + * 许可证 + */ + @NestedConfigurationProperty + private License license = null; + + /** + * 版本 + */ + private String version = null; + + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java new file mode 100644 index 0000000..56b7369 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java @@ -0,0 +1,253 @@ +package org.dromara.common.doc.handler; + +import cn.hutool.core.io.IoUtil; +import io.swagger.v3.core.jackson.TypeNameResolver; +import io.swagger.v3.core.util.AnnotationsUtils; +import io.swagger.v3.oas.annotations.tags.Tags; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.properties.SpringDocConfigProperties; +import org.springdoc.core.providers.JavadocProvider; +import org.springdoc.core.service.OpenAPIService; +import org.springdoc.core.service.SecurityService; +import org.springdoc.core.utils.PropertyResolverUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.method.HandlerMethod; + +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 自定义 openapi 处理器 + * 对源码功能进行修改 增强使用 + */ +@Slf4j +@SuppressWarnings("all") +public class OpenApiHandler extends OpenAPIService { + + /** + * The Basic error controller. + */ + private static Class basicErrorController; + + /** + * The Security parser. + */ + private final SecurityService securityParser; + + /** + * The Mappings map. + */ + private final Map mappingsMap = new HashMap<>(); + + /** + * The Springdoc tags. + */ + private final Map springdocTags = new HashMap<>(); + + /** + * The Open api builder customisers. + */ + private final Optional> openApiBuilderCustomisers; + + /** + * The server base URL customisers. + */ + private final Optional> serverBaseUrlCustomizers; + + /** + * The Spring doc config properties. + */ + private final SpringDocConfigProperties springDocConfigProperties; + + /** + * The Cached open api map. + */ + private final Map cachedOpenAPI = new HashMap<>(); + + /** + * The Property resolver utils. + */ + private final PropertyResolverUtils propertyResolverUtils; + + /** + * The javadoc provider. + */ + private final Optional javadocProvider; + + /** + * The Context. + */ + private ApplicationContext context; + + /** + * The Open api. + */ + private OpenAPI openAPI; + + /** + * The Is servers present. + */ + private boolean isServersPresent; + + /** + * The Server base url. + */ + private String serverBaseUrl; + + /** + * Instantiates a new Open api builder. + * + * @param openAPI the open api + * @param securityParser the security parser + * @param springDocConfigProperties the spring doc config properties + * @param propertyResolverUtils the property resolver utils + * @param openApiBuilderCustomizers the open api builder customisers + * @param serverBaseUrlCustomizers the server base url customizers + * @param javadocProvider the javadoc provider + */ + public OpenApiHandler(Optional openAPI, SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomizers, + Optional> serverBaseUrlCustomizers, + Optional javadocProvider) { + super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); + if (openAPI.isPresent()) { + this.openAPI = openAPI.get(); + if (this.openAPI.getComponents() == null) + this.openAPI.setComponents(new Components()); + if (this.openAPI.getPaths() == null) + this.openAPI.setPaths(new Paths()); + if (!CollectionUtils.isEmpty(this.openAPI.getServers())) + this.isServersPresent = true; + } + this.propertyResolverUtils = propertyResolverUtils; + this.securityParser = securityParser; + this.springDocConfigProperties = springDocConfigProperties; + this.openApiBuilderCustomisers = openApiBuilderCustomizers; + this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; + this.javadocProvider = javadocProvider; + if (springDocConfigProperties.isUseFqn()) + TypeNameResolver.std.setUseFqn(true); + } + + @Override + public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) { + + Set tags = new HashSet<>(); + Set tagsStr = new HashSet<>(); + + buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale); + buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale); + + if (!CollectionUtils.isEmpty(tagsStr)) + tagsStr = tagsStr.stream() + .map(str -> propertyResolverUtils.resolve(str, locale)) + .collect(Collectors.toSet()); + + if (springdocTags.containsKey(handlerMethod)) { + io.swagger.v3.oas.models.tags.Tag tag = springdocTags.get(handlerMethod); + tagsStr.add(tag.getName()); + if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { + openAPI.addTagsItem(tag); + } + } + + if (!CollectionUtils.isEmpty(tagsStr)) { + if (CollectionUtils.isEmpty(operation.getTags())) + operation.setTags(new ArrayList<>(tagsStr)); + else { + Set operationTagsSet = new HashSet<>(operation.getTags()); + operationTagsSet.addAll(tagsStr); + operation.getTags().clear(); + operation.getTags().addAll(operationTagsSet); + } + } + + if (isAutoTagClasses(operation)) { + + + if (javadocProvider.isPresent()) { + String description = javadocProvider.get().getClassJavadoc(handlerMethod.getBeanType()); + if (StringUtils.isNotBlank(description)) { + io.swagger.v3.oas.models.tags.Tag tag = new io.swagger.v3.oas.models.tags.Tag(); + + // 自定义部分 修改使用java注释当tag名 + List list = IoUtil.readLines(new StringReader(description), new ArrayList<>()); + // tag.setName(tagAutoName); + tag.setName(list.get(0)); + operation.addTagsItem(list.get(0)); + + tag.setDescription(description); + if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { + openAPI.addTagsItem(tag); + } + } + } else { + String tagAutoName = splitCamelCase(handlerMethod.getBeanType().getSimpleName()); + operation.addTagsItem(tagAutoName); + } + } + + if (!CollectionUtils.isEmpty(tags)) { + // Existing tags + List openApiTags = openAPI.getTags(); + if (!CollectionUtils.isEmpty(openApiTags)) + tags.addAll(openApiTags); + openAPI.setTags(new ArrayList<>(tags)); + } + + // Handle SecurityRequirement at operation level + io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser + .getSecurityRequirements(handlerMethod); + if (securityRequirements != null) { + if (securityRequirements.length == 0) + operation.setSecurity(Collections.emptyList()); + else + securityParser.buildSecurityRequirement(securityRequirements, operation); + } + + return operation; + } + + private void buildTagsFromMethod(Method method, Set tags, Set tagsStr, Locale locale) { + // method tags + Set tagsSet = AnnotatedElementUtils + .findAllMergedAnnotations(method, Tags.class); + Set methodTags = tagsSet.stream() + .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet()); + methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class)); + if (!CollectionUtils.isEmpty(methodTags)) { + tagsStr.addAll(StreamUtils.toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale))); + List allTags = new ArrayList<>(methodTags); + addTags(allTags, tags, locale); + } + } + + private void addTags(List sourceTags, Set tags, Locale locale) { + Optional> optionalTagSet = AnnotationsUtils + .getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true); + optionalTagSet.ifPresent(tagsSet -> { + tagsSet.forEach(tag -> { + tag.name(propertyResolverUtils.resolve(tag.getName(), locale)); + tag.description(propertyResolverUtils.resolve(tag.getDescription(), locale)); + if (tags.stream().noneMatch(t -> t.getName().equals(tag.getName()))) + tags.add(tag); + }); + }); + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..fe11e76 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.doc.config.SpringDocConfig diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml new file mode 100644 index 0000000..ed4910e --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -0,0 +1,54 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-encrypt + + + ruoyi-common-encrypt 数据加解密模块 + + + + + + org.dromara + ruoyi-common-core + + + + org.bouncycastle + bcprov-jdk15to18 + + + + cn.hutool + hutool-crypto + + + + org.springframework + spring-webmvc + + + + com.baomidou + mybatis-plus-spring-boot3-starter + true + + + org.mybatis + mybatis-spring + + + + + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java new file mode 100644 index 0000000..7f52de8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java @@ -0,0 +1,20 @@ +package org.dromara.common.encrypt.annotation; + +import java.lang.annotation.*; + +/** + * 强制加密注解 + * + * @author Michelle.Chung + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiEncrypt { + + /** + * 响应加密忽略,默认不加密,为 true 时加密 + */ + boolean response() default false; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java new file mode 100644 index 0000000..d357d72 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java @@ -0,0 +1,44 @@ +package org.dromara.common.encrypt.annotation; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; + +import java.lang.annotation.*; + +/** + * 字段加密注解 + * + * @author 老马 + */ +@Documented +@Inherited +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface EncryptField { + + /** + * 加密算法 + */ + AlgorithmType algorithm() default AlgorithmType.DEFAULT; + + /** + * 秘钥。AES、SM4需要 + */ + String password() default ""; + + /** + * 公钥。RSA、SM2需要 + */ + String publicKey() default ""; + + /** + * 私钥。RSA、SM2需要 + */ + String privateKey() default ""; + + /** + * 编码方式。对加密算法为BASE64的不起作用 + */ + EncodeType encode() default EncodeType.DEFAULT; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java new file mode 100644 index 0000000..4f6ac1f --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java @@ -0,0 +1,33 @@ +package org.dromara.common.encrypt.config; + +import jakarta.servlet.DispatcherType; +import org.dromara.common.encrypt.filter.CryptoFilter; +import org.dromara.common.encrypt.properties.ApiDecryptProperties; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.util.PathMatcher; + +/** + * api 解密自动配置 + * + * @author wdhcr + */ +@AutoConfiguration +@EnableConfigurationProperties(ApiDecryptProperties.class) +@ConditionalOnProperty(value = "api-decrypt.enabled", havingValue = "true") +public class ApiDecryptAutoConfiguration { + + @Bean + public FilterRegistrationBean cryptoFilterRegistration(ApiDecryptProperties properties, PathMatcher pathMatcher) { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new CryptoFilter(properties,pathMatcher)); + registration.addUrlPatterns("/*"); + registration.setName("cryptoFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + return registration; + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java new file mode 100644 index 0000000..fbc4e52 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java @@ -0,0 +1,49 @@ +package org.dromara.common.encrypt.config; + +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.encrypt.core.EncryptorManager; +import org.dromara.common.encrypt.interceptor.MybatisDecryptInterceptor; +import org.dromara.common.encrypt.interceptor.MybatisEncryptInterceptor; +import org.dromara.common.encrypt.properties.EncryptorProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * 加解密配置 + * + * @author 老马 + * @version 4.6.0 + */ +@AutoConfiguration(after = MybatisPlusAutoConfiguration.class) +@EnableConfigurationProperties(EncryptorProperties.class) +@ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true") +@Slf4j +public class EncryptorAutoConfiguration { + + @Autowired + private EncryptorProperties properties; + + @Bean + public EncryptorManager encryptorManager(MybatisPlusProperties mybatisPlusProperties) { + return new EncryptorManager(mybatisPlusProperties.getTypeAliasesPackage()); + } + + @Bean + public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisEncryptInterceptor(encryptorManager, properties); + } + + @Bean + public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisDecryptInterceptor(encryptorManager, properties); + } + +} + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java new file mode 100644 index 0000000..2f02eaf --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java @@ -0,0 +1,41 @@ +package org.dromara.common.encrypt.core; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import lombok.Data; + +/** + * 加密上下文 用于encryptor传递必要的参数。 + * + * @author 老马 + * @version 4.6.0 + */ +@Data +public class EncryptContext { + + /** + * 默认算法 + */ + private AlgorithmType algorithm; + + /** + * 安全秘钥 + */ + private String password; + + /** + * 公钥 + */ + private String publicKey; + + /** + * 私钥 + */ + private String privateKey; + + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java new file mode 100644 index 0000000..b5f194d --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java @@ -0,0 +1,159 @@ +package org.dromara.common.encrypt.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.io.Resources; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.EncryptField; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.util.ClassUtils; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 加密管理类 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@NoArgsConstructor +public class EncryptorManager { + + /** + * 缓存加密器 + */ + Map encryptorMap = new ConcurrentHashMap<>(); + + /** + * 类加密字段缓存 + */ + Map, Set> fieldCache = new ConcurrentHashMap<>(); + + /** + * 构造方法传入类加密字段缓存 + * + * @param typeAliasesPackage 实体类包 + */ + public EncryptorManager(String typeAliasesPackage) { + scanEncryptClasses(typeAliasesPackage); + } + + + /** + * 获取类加密字段缓存 + */ + public Set getFieldCache(Class sourceClazz) { + return ObjectUtils.notNullGetter(fieldCache, f -> f.get(sourceClazz)); + } + + /** + * 注册加密执行者到缓存 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) { + int key = encryptContext.hashCode(); + if (encryptorMap.containsKey(key)) { + return encryptorMap.get(key); + } + IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext); + encryptorMap.put(key, encryptor); + return encryptor; + } + + /** + * 移除缓存中的加密执行者 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public void removeEncryptor(EncryptContext encryptContext) { + this.encryptorMap.remove(encryptContext.hashCode()); + } + + /** + * 根据配置进行加密。会进行本地缓存对应的算法和对应的秘钥信息。 + * + * @param value 待加密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String encrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.encrypt(value, encryptContext.getEncode()); + } + + /** + * 根据配置进行解密 + * + * @param value 待解密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String decrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.decrypt(value); + } + + /** + * 通过 typeAliasesPackage 设置的扫描包 扫描缓存实体 + */ + private void scanEncryptClasses(String typeAliasesPackage) { + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); + String[] packagePatternArray = StringUtils.splitPreserveAllTokens(typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; + try { + for (String packagePattern : packagePatternArray) { + String path = ClassUtils.convertClassNameToResourcePath(packagePattern); + Resource[] resources = resolver.getResources(classpath + path + "/*.class"); + for (Resource resource : resources) { + ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); + Class clazz = Resources.classForName(classMetadata.getClassName()); + Set encryptFieldSet = getEncryptFieldSetFromClazz(clazz); + if (CollUtil.isNotEmpty(encryptFieldSet)) { + fieldCache.put(clazz, encryptFieldSet); + } + } + } + } catch (Exception e) { + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); + } + } + + /** + * 获得一个类的加密字段集合 + */ + private Set getEncryptFieldSetFromClazz(Class clazz) { + Set fieldSet = new HashSet<>(); + // 判断clazz如果是接口,内部类,匿名类就直接返回 + if (clazz.isInterface() || clazz.isMemberClass() || clazz.isAnonymousClass()) { + return fieldSet; + } + while (clazz != null) { + Field[] fields = clazz.getDeclaredFields(); + fieldSet.addAll(Arrays.asList(fields)); + clazz = clazz.getSuperclass(); + } + fieldSet = fieldSet.stream().filter(field -> + field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) + .collect(Collectors.toSet()); + for (Field field : fieldSet) { + field.setAccessible(true); + } + return fieldSet; + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java new file mode 100644 index 0000000..dbc4420 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java @@ -0,0 +1,35 @@ +package org.dromara.common.encrypt.core; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; + +/** + * 加解者 + * + * @author 老马 + * @version 4.6.0 + */ +public interface IEncryptor { + + /** + * 获得当前算法 + */ + AlgorithmType algorithm(); + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + * @return 加密后的字符串 + */ + String encrypt(String value, EncodeType encodeType); + + /** + * 解密 + * + * @param value 待加密字符串 + * @return 解密后的字符串 + */ + String decrypt(String value); +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java new file mode 100644 index 0000000..858d229 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java @@ -0,0 +1,18 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.core.IEncryptor; + +/** + * 所有加密执行者的基类 + * + * @author 老马 + * @version 4.6.0 + */ +public abstract class AbstractEncryptor implements IEncryptor { + + public AbstractEncryptor(EncryptContext context) { + // 用户配置校验与配置注入 + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java new file mode 100644 index 0000000..e4dc597 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java @@ -0,0 +1,55 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + +/** + * AES算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class AesEncryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public AesEncryptor(EncryptContext context) { + super(context); + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.AES; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptByAesHex(value, context.getPassword()); + } else { + return EncryptUtils.encryptByAes(value, context.getPassword()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptByAes(value, context.getPassword()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java new file mode 100644 index 0000000..0028548 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java @@ -0,0 +1,48 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + +/** + * Base64算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Base64Encryptor extends AbstractEncryptor { + + public Base64Encryptor(EncryptContext context) { + super(context); + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.BASE64; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + return EncryptUtils.encryptByBase64(value); + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptByBase64(value); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java new file mode 100644 index 0000000..5f03a4b --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java @@ -0,0 +1,62 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + + +/** + * RSA算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class RsaEncryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public RsaEncryptor(EncryptContext context) { + super(context); + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。"); + } + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.RSA; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptByRsaHex(value, context.getPublicKey()); + } else { + return EncryptUtils.encryptByRsa(value, context.getPublicKey()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptByRsa(value, context.getPrivateKey()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java new file mode 100644 index 0000000..aec5d82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java @@ -0,0 +1,61 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + +/** + * sm2算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Sm2Encryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public Sm2Encryptor(EncryptContext context) { + super(context); + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("SM2公私钥均需要提供,公钥加密,私钥解密。"); + } + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM2; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptBySm2Hex(value, context.getPublicKey()); + } else { + return EncryptUtils.encryptBySm2(value, context.getPublicKey()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptBySm2(value, context.getPrivateKey()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java new file mode 100644 index 0000000..adaf674 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java @@ -0,0 +1,55 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + +/** + * sm4算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Sm4Encryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public Sm4Encryptor(EncryptContext context) { + super(context); + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM4; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptBySm4Hex(value, context.getPassword()); + } else { + return EncryptUtils.encryptBySm4(value, context.getPassword()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptBySm4(value, context.getPassword()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java new file mode 100644 index 0000000..26ee1ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java @@ -0,0 +1,48 @@ +package org.dromara.common.encrypt.enumd; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.encrypt.core.encryptor.*; + +/** + * 算法名称 + * + * @author 老马 + * @version 4.6.0 + */ +@Getter +@AllArgsConstructor +public enum AlgorithmType { + + /** + * 默认走yml配置 + */ + DEFAULT(null), + + /** + * base64 + */ + BASE64(Base64Encryptor.class), + + /** + * aes + */ + AES(AesEncryptor.class), + + /** + * rsa + */ + RSA(RsaEncryptor.class), + + /** + * sm2 + */ + SM2(Sm2Encryptor.class), + + /** + * sm4 + */ + SM4(Sm4Encryptor.class); + + private final Class clazz; +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java new file mode 100644 index 0000000..f471221 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java @@ -0,0 +1,26 @@ +package org.dromara.common.encrypt.enumd; + +/** + * 编码类型 + * + * @author 老马 + * @version 4.6.0 + */ +public enum EncodeType { + + /** + * 默认使用yml配置 + */ + DEFAULT, + + /** + * base64编码 + */ + BASE64, + + /** + * 16进制编码 + */ + HEX; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java new file mode 100644 index 0000000..39dbc5c --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java @@ -0,0 +1,149 @@ +package org.dromara.common.encrypt.filter; + +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.encrypt.properties.ApiDecryptProperties; +import org.springframework.http.HttpMethod; +import org.springframework.util.CollectionUtils; +import org.springframework.util.PathMatcher; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import java.io.IOException; +import java.util.List; + + +/** + * Crypto 过滤器 + * + * @author wdhcr + */ +public class CryptoFilter implements Filter { + private final ApiDecryptProperties properties; + private final PathMatcher pathMatcher; + + public CryptoFilter(ApiDecryptProperties properties, PathMatcher pathMatcher) { + this.properties = properties; + this.pathMatcher = pathMatcher; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest servletRequest = (HttpServletRequest) request; + HttpServletResponse servletResponse = (HttpServletResponse) response; + + // 获取加密注解 + //ApiEncrypt apiEncrypt = this.getApiEncryptAnnotation(servletRequest); + //boolean responseFlag = apiEncrypt != null && apiEncrypt.response(); + + //直接全局加密 + boolean responseFlag = false; + + // 检查请求是否被排除 + if (isExcludedPath(servletRequest.getRequestURI())) { + chain.doFilter(request, response); + return; + } + if ("OPTIONS".equalsIgnoreCase(servletRequest.getMethod())) { + chain.doFilter(request, response); + return; + } + + ServletRequest requestWrapper = null; + ServletResponse responseWrapper = null; + EncryptResponseBodyWrapper responseBodyWrapper = null; + + // 是否为 put 或者 post 请求 + if (HttpMethod.PUT.matches(servletRequest.getMethod()) || HttpMethod.POST.matches(servletRequest.getMethod())) { + // 是否存在加密标头 + String headerValue = servletRequest.getHeader(properties.getHeaderFlag()); + if (StringUtils.isNotBlank(headerValue)) { + // 请求解密 + requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPrivateKey(), properties.getHeaderFlag()); + } else { +// // 是否有注解,有就报错,没有放行 +// if (ObjectUtil.isNotNull(apiEncrypt)) { +// HandlerExceptionResolver exceptionResolver = SpringUtils.getBean("handlerExceptionResolver", HandlerExceptionResolver.class); +// exceptionResolver.resolveException( +// servletRequest, servletResponse, null, +// new ServiceException("没有访问权限,请联系管理员授权", HttpStatus.FORBIDDEN)); +// return; +// } + throw new ServiceException("无权访问接口", HttpStatus.BAD_METHOD); + } + } + + // 判断是否响应加密 + if (responseFlag) { + responseBodyWrapper = new EncryptResponseBodyWrapper(servletResponse); + responseWrapper = responseBodyWrapper; + } + + chain.doFilter( + ObjectUtil.defaultIfNull(requestWrapper, request), + ObjectUtil.defaultIfNull(responseWrapper, response)); + + if (responseFlag) { + servletResponse.reset(); + // 对原始内容加密 + String encryptContent = responseBodyWrapper.getEncryptContent( + servletResponse, properties.getPublicKey(), properties.getHeaderFlag()); + // 对加密后的内容写出 + servletResponse.getWriter().write(encryptContent); + } + } + + private boolean isExcludedPath(String requestUri) { + // 从配置中获取放行的URL列表 + List excludedPaths = properties.getExcludedPaths(); + + if (CollectionUtils.isEmpty(excludedPaths)) { + return false; + } + + // 检查请求URI是否匹配任何一个放行路径 + for (String excludedPath : excludedPaths) { + // 支持简单的Ant风格路径匹配(如 /api/public/**) + if (pathMatcher.match(excludedPath, requestUri)) { + return true; + } + } + + return false; + } + + /** + * 获取 ApiEncrypt 注解 + */ + private ApiEncrypt getApiEncryptAnnotation(HttpServletRequest servletRequest) { + RequestMappingHandlerMapping handlerMapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); + // 获取注解 + try { + HandlerExecutionChain mappingHandler = handlerMapping.getHandler(servletRequest); + if (ObjectUtil.isNotNull(mappingHandler)) { + Object handler = mappingHandler.getHandler(); + if (ObjectUtil.isNotNull(handler)) { + // 从handler获取注解 + if (handler instanceof HandlerMethod handlerMethod) { + return handlerMethod.getMethodAnnotation(ApiEncrypt.class); + } + } + } + } catch (Exception e) { + return null; + } + return null; + } + + @Override + public void destroy() { + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java new file mode 100644 index 0000000..98f4bc7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java @@ -0,0 +1,94 @@ +package org.dromara.common.encrypt.filter; + +import cn.hutool.core.io.IoUtil; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.encrypt.utils.EncryptUtils; +import org.springframework.http.MediaType; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +/** + * 解密请求参数工具类 + * + * @author wdhcr + */ +public class DecryptRequestBodyWrapper extends HttpServletRequestWrapper { + + private final byte[] body; + + public DecryptRequestBodyWrapper(HttpServletRequest request, String privateKey, String headerFlag) throws IOException { + super(request); + // 获取 AES 密码 采用 RSA 加密 + String headerRsa = request.getHeader(headerFlag); + String decryptAes = EncryptUtils.decryptByRsa(headerRsa, privateKey); + // 解密 AES 密码 + String aesPassword = EncryptUtils.decryptByBase64(decryptAes); + request.setCharacterEncoding(Constants.UTF8); + byte[] readBytes = IoUtil.readBytes(request.getInputStream(), false); + String requestBody = new String(readBytes, StandardCharsets.UTF_8); + // 解密 body 采用 AES 加密 + String decryptBody = EncryptUtils.decryptByAes(requestBody, aesPassword); + body = decryptBody.getBytes(StandardCharsets.UTF_8); + } + + @Override + public BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + + @Override + public int getContentLength() { + return body.length; + } + + @Override + public long getContentLengthLong() { + return body.length; + } + + @Override + public String getContentType() { + return MediaType.APPLICATION_JSON_VALUE; + } + + + @Override + public ServletInputStream getInputStream() { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + return new ServletInputStream() { + @Override + public int read() { + return bais.read(); + } + + @Override + public int available() { + return body.length; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java new file mode 100644 index 0000000..c0af232 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java @@ -0,0 +1,121 @@ +package org.dromara.common.encrypt.filter; + +import cn.hutool.core.util.RandomUtil; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; +import org.dromara.common.encrypt.utils.EncryptUtils; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +/** + * 加密响应参数包装类 + * + * @author Michelle.Chung + */ +public class EncryptResponseBodyWrapper extends HttpServletResponseWrapper { + + private final ByteArrayOutputStream byteArrayOutputStream; + private final ServletOutputStream servletOutputStream; + private final PrintWriter printWriter; + + public EncryptResponseBodyWrapper(HttpServletResponse response) throws IOException { + super(response); + this.byteArrayOutputStream = new ByteArrayOutputStream(); + this.servletOutputStream = this.getOutputStream(); + this.printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream)); + } + + @Override + public PrintWriter getWriter() { + return printWriter; + } + + @Override + public void flushBuffer() throws IOException { + if (servletOutputStream != null) { + servletOutputStream.flush(); + } + if (printWriter != null) { + printWriter.flush(); + } + } + + @Override + public void reset() { + byteArrayOutputStream.reset(); + } + + public byte[] getResponseData() throws IOException { + flushBuffer(); + return byteArrayOutputStream.toByteArray(); + } + + public String getContent() throws IOException { + flushBuffer(); + return byteArrayOutputStream.toString(); + } + + /** + * 获取加密内容 + * + * @param servletResponse response + * @param publicKey RSA公钥 (用于加密 AES 秘钥) + * @param headerFlag 请求头标志 + * @return 加密内容 + * @throws IOException + */ + public String getEncryptContent(HttpServletResponse servletResponse, String publicKey, String headerFlag) throws IOException { + // 生成秘钥 + String aesPassword = RandomUtil.randomString(32); + // 秘钥使用 Base64 编码 + String encryptAes = EncryptUtils.encryptByBase64(aesPassword); + // Rsa 公钥加密 Base64 编码 + String encryptPassword = EncryptUtils.encryptByRsa(encryptAes, publicKey); + + // 设置响应头 + servletResponse.addHeader("Access-Control-Expose-Headers", headerFlag); + servletResponse.setHeader(headerFlag, encryptPassword); + servletResponse.setHeader("Access-Control-Allow-Origin", "*"); + servletResponse.setHeader("Access-Control-Allow-Methods", "*"); + servletResponse.setCharacterEncoding(StandardCharsets.UTF_8.toString()); + + // 获取原始内容 + String originalBody = this.getContent(); + // 对内容进行加密 + return EncryptUtils.encryptByAes(originalBody, aesPassword); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return new ServletOutputStream() { + @Override + public boolean isReady() { + return false; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + + } + + @Override + public void write(int b) throws IOException { + byteArrayOutputStream.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + byteArrayOutputStream.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + byteArrayOutputStream.write(b, off, len); + } + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java new file mode 100644 index 0000000..460aa36 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java @@ -0,0 +1,120 @@ +package org.dromara.common.encrypt.interceptor; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.resultset.ResultSetHandler; +import org.apache.ibatis.plugin.*; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.EncryptField; +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.core.EncryptorManager; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.properties.EncryptorProperties; + +import java.lang.reflect.Field; +import java.sql.Statement; +import java.util.*; + +/** + * 出参解密拦截器 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ResultSetHandler.class, + method = "handleResultSets", + args = {Statement.class}) +}) +@AllArgsConstructor +public class MybatisDecryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 获取执行mysql执行结果 + Object result = invocation.proceed(); + if (result == null) { + return null; + } + decryptHandler(result); + return result; + } + + /** + * 解密对象 + * + * @param sourceObject 待加密对象 + */ + private void decryptHandler(Object sourceObject) { + if (ObjectUtil.isNull(sourceObject)) { + return; + } + if (sourceObject instanceof Map map) { + new HashSet<>(map.values()).forEach(this::decryptHandler); + return; + } + if (sourceObject instanceof List list) { + if(CollUtil.isEmpty(list)) { + return; + } + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = list.get(0); + if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + list.forEach(this::decryptHandler); + return; + } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } + try { + for (Field field : fields) { + field.set(sourceObject, this.decryptField(Convert.toStr(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理解密字段时出错", e); + } + } + + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String decryptField(String value, Field field) { + if (ObjectUtil.isNull(value)) { + return null; + } + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.decrypt(value, encryptContext); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java new file mode 100644 index 0000000..bcc2f4c --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -0,0 +1,124 @@ +package org.dromara.common.encrypt.interceptor; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.parameter.ParameterHandler; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.EncryptField; +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.core.EncryptorManager; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.properties.EncryptorProperties; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.util.*; + +/** + * 入参加密拦截器 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ParameterHandler.class, + method = "setParameters", + args = {PreparedStatement.class}) +}) +@AllArgsConstructor +public class MybatisEncryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + return invocation; + } + + @Override + public Object plugin(Object target) { + if (target instanceof ParameterHandler parameterHandler) { + // 进行加密操作 + Object parameterObject = parameterHandler.getParameterObject(); + if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { + this.encryptHandler(parameterObject); + } + } + return target; + } + + /** + * 加密对象 + * + * @param sourceObject 待加密对象 + */ + private void encryptHandler(Object sourceObject) { + if (ObjectUtil.isNull(sourceObject)) { + return; + } + if (sourceObject instanceof Map map) { + new HashSet<>(map.values()).forEach(this::encryptHandler); + return; + } + if (sourceObject instanceof List list) { + if(CollUtil.isEmpty(list)) { + return; + } + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = list.get(0); + if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + list.forEach(this::encryptHandler); + return; + } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } + try { + for (Field field : fields) { + field.set(sourceObject, this.encryptField(Convert.toStr(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理加密字段时出错", e); + } + } + + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String encryptField(String value, Field field) { + if (ObjectUtil.isNull(value)) { + return null; + } + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.encrypt(value, encryptContext); + } + + + @Override + public void setProperties(Properties properties) { + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java new file mode 100644 index 0000000..548a7a0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java @@ -0,0 +1,43 @@ +package org.dromara.common.encrypt.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.ArrayList; +import java.util.List; + +/** + * api解密属性配置类 + * @author wdhcr + */ +@Data +@ConfigurationProperties(prefix = "api-decrypt") +public class ApiDecryptProperties { + + /** + * 加密开关 + */ + private Boolean enabled; + + /** + * 头部标识 + */ + private String headerFlag; + + /** + * 响应加密公钥 + */ + private String publicKey; + + /** + * 请求解密私钥 + */ + private String privateKey; + + /** + * cory + * 需要放行的接口路径列表(支持Ant风格路径匹配) + */ + private List excludedPaths = new ArrayList<>(); + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java new file mode 100644 index 0000000..ba445c1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java @@ -0,0 +1,48 @@ +package org.dromara.common.encrypt.properties; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 加解密属性配置类 + * + * @author 老马 + * @version 4.6.0 + */ +@Data +@ConfigurationProperties(prefix = "mybatis-encryptor") +public class EncryptorProperties { + + /** + * 过滤开关 + */ + private Boolean enable; + + /** + * 默认算法 + */ + private AlgorithmType algorithm; + + /** + * 安全秘钥 + */ + private String password; + + /** + * 公钥 + */ + private String publicKey; + + /** + * 私钥 + */ + private String privateKey; + + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java new file mode 100644 index 0000000..2a096ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java @@ -0,0 +1,313 @@ +package org.dromara.common.encrypt.utils; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.asymmetric.SM2; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * 安全相关工具类 + * + * @author 老马 + */ +public class EncryptUtils { + + /** + * 公钥 + */ + public static final String PUBLIC_KEY = "publicKey"; + + /** + * 私钥 + */ + public static final String PRIVATE_KEY = "privateKey"; + + /** + * Base64加密 + * + * @param data 待加密数据 + * @return 加密后字符串 + */ + public static String encryptByBase64(String data) { + return Base64.encode(data, StandardCharsets.UTF_8); + } + + /** + * Base64解密 + * + * @param data 待解密数据 + * @return 解密后字符串 + */ + public static String decryptByBase64(String data) { + return Base64.decodeStr(data, StandardCharsets.UTF_8); + } + + /** + * AES加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptByAes(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8); + } + + /** + * AES加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptByAesHex(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8); + } + + /** + * AES解密 + * + * @param data 待解密数据 + * @param password 秘钥字符串 + * @return 解密后字符串 + */ + public static String decryptByAes(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8); + } + + /** + * sm4加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm4(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8); + } + + /** + * sm4加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm4Hex(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8); + } + + /** + * sm4解密 + * + * @param data 待解密数据 + * @param password 秘钥字符串 + * @return 解密后字符串 + */ + public static String decryptBySm4(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8); + } + + /** + * 产生sm2加解密需要的公钥和私钥 + * + * @return 公私钥Map + */ + public static Map generateSm2Key() { + Map keyMap = new HashMap<>(2); + SM2 sm2 = SmUtil.sm2(); + keyMap.put(PRIVATE_KEY, sm2.getPrivateKeyBase64()); + keyMap.put(PUBLIC_KEY, sm2.getPublicKeyBase64()); + return keyMap; + } + + /** + * sm2公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm2(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("SM2需要传入公钥进行加密"); + } + SM2 sm2 = SmUtil.sm2(null, publicKey); + return sm2.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * sm2公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySm2Hex(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("SM2需要传入公钥进行加密"); + } + SM2 sm2 = SmUtil.sm2(null, publicKey); + return sm2.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * sm2私钥解密 + * + * @param data 待解密数据 + * @param privateKey 私钥 + * @return 解密后字符串 + */ + public static String decryptBySm2(String data, String privateKey) { + if (StrUtil.isBlank(privateKey)) { + throw new IllegalArgumentException("SM2需要传入私钥进行解密"); + } + SM2 sm2 = SmUtil.sm2(privateKey, null); + return sm2.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8); + } + + /** + * 产生RSA加解密需要的公钥和私钥 + * + * @return 公私钥Map + */ + public static Map generateRsaKey() { + Map keyMap = new HashMap<>(2); + RSA rsa = SecureUtil.rsa(); + keyMap.put(PRIVATE_KEY, rsa.getPrivateKeyBase64()); + keyMap.put(PUBLIC_KEY, rsa.getPublicKeyBase64()); + return keyMap; + } + + /** + * rsa公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptByRsa(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("RSA需要传入公钥进行加密"); + } + RSA rsa = SecureUtil.rsa(null, publicKey); + return rsa.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * rsa公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptByRsaHex(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("RSA需要传入公钥进行加密"); + } + RSA rsa = SecureUtil.rsa(null, publicKey); + return rsa.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * rsa私钥解密 + * + * @param data 待解密数据 + * @param privateKey 私钥 + * @return 解密后字符串 + */ + public static String decryptByRsa(String data, String privateKey) { + if (StrUtil.isBlank(privateKey)) { + throw new IllegalArgumentException("RSA需要传入私钥进行解密"); + } + RSA rsa = SecureUtil.rsa(privateKey, null); + return rsa.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8); + } + + /** + * md5加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptByMd5(String data) { + return SecureUtil.md5(data); + } + + /** + * sha256加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySha256(String data) { + return SecureUtil.sha256(data); + } + + /** + * sm3加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySm3(String data) { + return SmUtil.sm3(data); + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..132cf29 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +org.dromara.common.encrypt.config.EncryptorAutoConfiguration +org.dromara.common.encrypt.config.ApiDecryptAutoConfiguration + diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml new file mode 100644 index 0000000..dd4a5ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/pom.xml @@ -0,0 +1,30 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-excel + + + ruoyi-common-excel + + + + + org.dromara + ruoyi-common-json + + + + com.alibaba + easyexcel + + + + diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java new file mode 100644 index 0000000..6b9211b --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java @@ -0,0 +1,29 @@ +package org.dromara.common.excel.annotation; + +import org.dromara.common.excel.core.CellMergeStrategy; + +import java.lang.annotation.*; + +/** + * excel 列单元格合并(合并列相同项) + * + * 需搭配 {@link CellMergeStrategy} 策略使用 + * + * @author Lion Li + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CellMerge { + + /** + * col index + */ + int index() default -1; + + /** + * 合并需要依赖的其他字段名称 + */ + String[] mergeBy() default {}; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java new file mode 100644 index 0000000..5c51842 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java @@ -0,0 +1,32 @@ +package org.dromara.common.excel.annotation; + +import org.dromara.common.core.utils.StringUtils; + +import java.lang.annotation.*; + +/** + * 字典格式化 + * + * @author Lion Li + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDictFormat { + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + String separator() default StringUtils.SEPARATOR; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java new file mode 100644 index 0000000..290379d --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java @@ -0,0 +1,30 @@ +package org.dromara.common.excel.annotation; + +import java.lang.annotation.*; + +/** + * 枚举格式化 + * + * @author Liang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelEnumFormat { + + /** + * 字典枚举类型 + */ + Class> enumClass(); + + /** + * 字典枚举类中对应的code属性名称,默认为code + */ + String codeField() default "code"; + + /** + * 字典枚举类中对应的text属性名称,默认为text + */ + String textField() default "text"; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java new file mode 100644 index 0000000..f358afc --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java @@ -0,0 +1,24 @@ +package org.dromara.common.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 批注 + * @author guzhouyanyu + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelNotation { + + /** + * col index + */ + int index() default -1; + /** + * 批注内容 + */ + String value() default ""; +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java new file mode 100644 index 0000000..15784e1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java @@ -0,0 +1,26 @@ +package org.dromara.common.excel.annotation; + +import org.apache.poi.ss.usermodel.IndexedColors; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 是否必填 + * @author guzhouyanyu + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelRequired { + + /** + * col index + */ + int index() default -1; + /** + * 字体颜色 + */ + IndexedColors fontColor() default IndexedColors.RED; +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java new file mode 100644 index 0000000..07cc4c4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java @@ -0,0 +1,52 @@ +package org.dromara.common.excel.convert; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +/** + * 大数值转换 + * Excel 数值长度位15位 大于15位的数值转换位字符串 + * + * @author Lion Li + */ +@Slf4j +public class ExcelBigNumberConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return Convert.toLong(cellData.getData()); + } + + @Override + public WriteCellData convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNotNull(object)) { + String str = Convert.toStr(object); + if (str.length() > 15) { + return new WriteCellData<>(str); + } + } + WriteCellData cellData = new WriteCellData<>(new BigDecimal(object)); + cellData.setType(CellDataTypeEnum.NUMBER); + return cellData; + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java new file mode 100644 index 0000000..61eeabf --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java @@ -0,0 +1,73 @@ +package org.dromara.common.excel.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.excel.utils.ExcelUtil; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; + +/** + * 字典格式化转换处理 + * + * @author Lion Li + */ +@Slf4j +public class ExcelDictConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String label = cellData.getStringValue(); + String value; + if (StringUtils.isBlank(type)) { + value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator()); + } else { + value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator()); + } + return Convert.convert(contentProperty.getField().getType(), value); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String value = Convert.toStr(object); + String label; + if (StringUtils.isBlank(type)) { + label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator()); + } else { + label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator()); + } + return new WriteCellData<>(label); + } + + private ExcelDictFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class); + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java new file mode 100644 index 0000000..b948ea7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java @@ -0,0 +1,87 @@ +package org.dromara.common.excel.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.excel.annotation.ExcelEnumFormat; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 枚举格式化转换处理 + * + * @author Liang + */ +@Slf4j +public class ExcelEnumConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + cellData.checkEmpty(); + // Excel中填入的是枚举中指定的描述 + Object textValue = switch (cellData.getType()) { + case STRING, DIRECT_STRING, RICH_TEXT_STRING -> cellData.getStringValue(); + case NUMBER -> cellData.getNumberValue(); + case BOOLEAN -> cellData.getBooleanValue(); + default -> throw new IllegalArgumentException("单元格类型异常!"); + }; + // 如果是空值 + if (ObjectUtil.isNull(textValue)) { + return null; + } + Map enumCodeToTextMap = beforeConvert(contentProperty); + // 从Java输出至Excel是code转text + // 因此从Excel转Java应该将text与code对调 + Map enumTextToCodeMap = new HashMap<>(); + enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key)); + // 应该从text -> code中查找 + Object codeValue = enumTextToCodeMap.get(textValue); + return Convert.convert(contentProperty.getField().getType(), codeValue); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + Map enumValueMap = beforeConvert(contentProperty); + String value = Convert.toStr(enumValueMap.get(object), ""); + return new WriteCellData<>(value); + } + + private Map beforeConvert(ExcelContentProperty contentProperty) { + ExcelEnumFormat anno = getAnnotation(contentProperty.getField()); + Map enumValueMap = new HashMap<>(); + Enum[] enumConstants = anno.enumClass().getEnumConstants(); + for (Enum enumConstant : enumConstants) { + Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); + String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); + enumValueMap.put(codeValue, textValue); + } + return enumValueMap; + } + + private ExcelEnumFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class); + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java new file mode 100644 index 0000000..7c7721c --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java @@ -0,0 +1,157 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.handler.context.WorkbookWriteHandlerContext; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.excel.annotation.CellMerge; + +import java.lang.reflect.Field; +import java.util.*; + +/** + * 列值重复合并策略 + * + * @author Lion Li + */ +@Slf4j +public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler { + + private final List cellList; + private final boolean hasTitle; + private int rowIndex; + + public CellMergeStrategy(List list, boolean hasTitle) { + this.hasTitle = hasTitle; + // 行合并开始下标 + this.rowIndex = hasTitle ? 1 : 0; + this.cellList = handle(list, hasTitle); + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + //单元格写入了,遍历合并区域,如果该Cell在区域内,但非首行,则清空 + final int rowIndex = cell.getRowIndex(); + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress cellAddresses : cellList) { + final int firstRow = cellAddresses.getFirstRow(); + if (cellAddresses.isInRange(cell) && rowIndex != firstRow){ + cell.setBlank(); + } + } + } + } + + @Override + public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) { + //当前表格写完后,统一写入 + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress item : cellList) { + context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item); + } + } + } + + @SneakyThrows + private List handle(List list, boolean hasTitle) { + List cellList = new ArrayList<>(); + if (CollUtil.isEmpty(list)) { + return cellList; + } + Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName())); + + // 有注解的字段 + List mergeFields = new ArrayList<>(); + List mergeFieldsIndex = new ArrayList<>(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); + mergeFields.add(field); + mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); + if (hasTitle) { + ExcelProperty property = field.getAnnotation(ExcelProperty.class); + rowIndex = Math.max(rowIndex, property.value().length); + } + } + } + + Map map = new HashMap<>(); + // 生成两两合并单元格 + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < mergeFields.size(); j++) { + Field field = mergeFields.get(j); + Object val = ReflectUtils.invokeGetter(list.get(i), field.getName()); + + int colNum = mergeFieldsIndex.get(j); + if (!map.containsKey(field)) { + map.put(field, new RepeatCell(val, i)); + } else { + RepeatCell repeatCell = map.get(field); + Object cellValue = repeatCell.getValue(); + if (cellValue == null || "".equals(cellValue)) { + // 空值跳过不合并 + continue; + } + + if (!cellValue.equals(val)) { + if ((i - repeatCell.getCurrent() > 1)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } else if (i == list.size() - 1) { + if (i > repeatCell.getCurrent() && isMerge(list, i, field)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); + } + } else if (!isMerge(list, i, field)) { + if ((i - repeatCell.getCurrent() > 1)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } + } + } + } + return cellList; + } + + private boolean isMerge(List list, int i, Field field) { + boolean isMerge = true; + CellMerge cm = field.getAnnotation(CellMerge.class); + final String[] mergeBy = cm.mergeBy(); + if (StrUtil.isAllNotBlank(mergeBy)) { + //比对当前list(i)和list(i - 1)的各个属性值一一比对 如果全为真 则为真 + for (String fieldName : mergeBy) { + final Object valCurrent = ReflectUtil.getFieldValue(list.get(i), fieldName); + final Object valPre = ReflectUtil.getFieldValue(list.get(i - 1), fieldName); + if (!Objects.equals(valPre, valCurrent)) { + //依赖字段如有任一不等值,则标记为不可合并 + isMerge = false; + } + } + } + return isMerge; + } + + @Data + @AllArgsConstructor + static class RepeatCell { + + private Object value; + + private int current; + + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java new file mode 100644 index 0000000..b6fa0b4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java @@ -0,0 +1,104 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; +import java.util.Set; + +/** + * Excel 导入监听 + * + * @author Yjoioooo + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor +public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener { + + /** + * 是否Validator检验,默认为是 + */ + private Boolean isValidate = Boolean.TRUE; + + /** + * excel 表头数据 + */ + private Map headMap; + + /** + * 导入回执 + */ + private ExcelResult excelResult; + + public DefaultExcelListener(boolean isValidate) { + this.excelResult = new DefaultExcelResult<>(); + this.isValidate = isValidate; + } + + /** + * 处理异常 + * + * @param exception ExcelDataConvertException + * @param context Excel 上下文 + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + String errMsg = null; + if (exception instanceof ExcelDataConvertException excelDataConvertException) { + // 如果是某一个单元格的转换异常 能获取到具体行号 + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + if (exception instanceof ConstraintViolationException constraintViolationException) { + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); + errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + excelResult.getList().add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.debug("所有数据解析完成!"); + } + + @Override + public ExcelResult getExcelResult() { + return excelResult; + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java new file mode 100644 index 0000000..7373e12 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java @@ -0,0 +1,73 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 默认excel返回对象 + * + * @author Yjoioooo + * @author Lion Li + */ +public class DefaultExcelResult implements ExcelResult { + + /** + * 数据对象list + */ + @Setter + private List list; + + /** + * 错误信息列表 + */ + @Setter + private List errorList; + + public DefaultExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefaultExcelResult(List list, List errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefaultExcelResult(ExcelResult excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return errorList; + } + + /** + * 获取导入回执 + * + * @return 导入回执 + */ + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorCount == 0) { + return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); + } else { + return ""; + } + } + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java new file mode 100644 index 0000000..8b53a0c --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java @@ -0,0 +1,149 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.exception.ServiceException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + *

Excel下拉可选项

+ * 注意:为确保下拉框解析正确,传值务必使用createOptionValue()做为值的拼接 + * + * @author Emil.Zhang + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuppressWarnings("unused") +public class DropDownOptions { + /** + * 一级下拉所在列index,从0开始算 + */ + private int index = 0; + /** + * 二级下拉所在的index,从0开始算,不能与一级相同 + */ + private int nextIndex = 0; + /** + * 一级下拉所包含的数据 + */ + private List options = new ArrayList<>(); + /** + * 二级下拉所包含的数据Map + *

以每一个一级选项值为Key,每个一级选项对应的二级数据为Value

+ */ + private Map> nextOptions = new HashMap<>(); + /** + * 分隔符 + */ + private static final String DELIMITER = "_"; + + /** + * 创建只有一级的下拉选 + */ + public DropDownOptions(int index, List options) { + this.index = index; + this.options = options; + } + + /** + *

创建每个选项可选值

+ *

注意:不能以数字,特殊符号开头,选项中不可以包含任何运算符号

+ * + * @param vars 可选值内包含的参数 + * @return 合规的可选值 + */ + public static String createOptionValue(Object... vars) { + StringBuilder stringBuffer = new StringBuilder(); + String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$"; + for (int i = 0; i < vars.length; i++) { + String var = StrUtil.trimToEmpty(String.valueOf(vars[i])); + if (!var.matches(regex)) { + throw new ServiceException("选项数据不符合规则,仅允许使用中英文字符以及数字"); + } + stringBuffer.append(var); + if (i < vars.length - 1) { + // 直至最后一个前,都以_作为切割线 + stringBuffer.append(DELIMITER); + } + } + if (stringBuffer.toString().matches("^\\d_*$")) { + throw new ServiceException("禁止以数字开头"); + } + return stringBuffer.toString(); + } + + /** + * 将处理后合理的可选值解析为原始的参数 + * + * @param option 经过处理后的合理的可选项 + * @return 原始的参数 + */ + public static List analyzeOptionValue(String option) { + return StrUtil.split(option, DELIMITER, true, true); + } + + /** + * 创建级联下拉选项 + * + * @param parentList 父实体可选项原始数据 + * @param parentIndex 父下拉选位置 + * @param sonList 子实体可选项原始数据 + * @param sonIndex 子下拉选位置 + * @param parentHowToGetIdFunction 父类如何获取唯一标识 + * @param sonHowToGetParentIdFunction 子类如何获取父类的唯一标识 + * @param howToBuildEveryOption 如何生成下拉选内容 + * @return 级联下拉选项 + */ + public static DropDownOptions buildLinkedOptions(List parentList, + int parentIndex, + List sonList, + int sonIndex, + Function parentHowToGetIdFunction, + Function sonHowToGetParentIdFunction, + Function howToBuildEveryOption) { + DropDownOptions parentLinkSonOptions = new DropDownOptions(); + // 先创建父类的下拉 + parentLinkSonOptions.setIndex(parentIndex); + parentLinkSonOptions.setOptions( + parentList.stream() + .map(howToBuildEveryOption) + .collect(Collectors.toList()) + ); + // 提取父-子级联下拉 + Map> sonOptions = new HashMap<>(); + // 父级依据自己的ID分组 + Map> parentGroupByIdMap = + parentList.stream().collect(Collectors.groupingBy(parentHowToGetIdFunction)); + // 遍历每个子集,提取到Map中 + sonList.forEach(everySon -> { + if (parentGroupByIdMap.containsKey(sonHowToGetParentIdFunction.apply(everySon))) { + // 找到对应的上级 + T parentObj = parentGroupByIdMap.get(sonHowToGetParentIdFunction.apply(everySon)).get(0); + // 提取名称和ID作为Key + String key = howToBuildEveryOption.apply(parentObj); + // Key对应的Value + List thisParentSonOptionList; + if (sonOptions.containsKey(key)) { + thisParentSonOptionList = sonOptions.get(key); + } else { + thisParentSonOptionList = new ArrayList<>(); + sonOptions.put(key, thisParentSonOptionList); + } + // 往Value中添加当前子集选项 + thisParentSonOptionList.add(howToBuildEveryOption.apply(everySon)); + } + }); + parentLinkSonOptions.setNextIndex(sonIndex); + parentLinkSonOptions.setNextOptions(sonOptions); + return parentLinkSonOptions; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java new file mode 100644 index 0000000..32fee7a --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java @@ -0,0 +1,399 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.EnumUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.metadata.FieldCache; +import com.alibaba.excel.metadata.FieldWrapper; +import com.alibaba.excel.util.ClassUtils; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.ss.util.WorkbookUtil; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.annotation.ExcelEnumFormat; + +import java.lang.reflect.Field; +import java.util.*; + +/** + *

Excel表格下拉选操作

+ * 考虑到下拉选过多可能导致Excel打开缓慢的问题,只校验前1000行 + *

+ * 即只有前1000行的数据可以用下拉框,超出的自行通过限制数据量的形式,第二次输出 + * + * @author Emil.Zhang + */ +@Slf4j +public class ExcelDownHandler implements SheetWriteHandler { + + /** + * Excel表格中的列名英文 + * 仅为了解析列英文,禁止修改 + */ + private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** + * 单选数据Sheet名 + */ + private static final String OPTIONS_SHEET_NAME = "options"; + /** + * 联动选择数据Sheet名的头 + */ + private static final String LINKED_OPTIONS_SHEET_NAME = "linkedOptions"; + /** + * 下拉可选项 + */ + private final List dropDownOptions; + private final DictService dictService; + /** + * 当前单选进度 + */ + private int currentOptionsColumnIndex; + /** + * 当前联动选择进度 + */ + private int currentLinkedOptionsSheetIndex; + + public ExcelDownHandler(List options) { + this.dropDownOptions = options; + this.currentOptionsColumnIndex = 0; + this.currentLinkedOptionsSheetIndex = 0; + this.dictService = SpringUtils.getBean(DictService.class); + } + + /** + *

开始创建下拉数据

+ * 1.通过解析传入的@ExcelProperty同级是否标注有@DropDown选项 + * 如果有且设置了value值,则将其直接置为下拉可选项 + *

+ * 2.或者在调用ExcelUtil时指定了可选项,将依据传入的可选项做下拉 + *

+ * 3.二者并存,注意调用方式 + */ + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Sheet sheet = writeSheetHolder.getSheet(); + // 开始设置下拉框 HSSFWorkbook + DataValidationHelper helper = sheet.getDataValidationHelper(); + Workbook workbook = writeWorkbookHolder.getWorkbook(); + FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder); + for (Map.Entry entry : fieldCache.getSortedFieldMap().entrySet()) { + Integer index = entry.getKey(); + FieldWrapper wrapper = entry.getValue(); + Field field = wrapper.getField(); + // 循环实体中的每个属性 + // 可选的下拉值 + List options = new ArrayList<>(); + if (field.isAnnotationPresent(ExcelDictFormat.class)) { + // 如果指定了@ExcelDictFormat,则使用字典的逻辑 + ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class); + String dictType = format.dictType(); + String converterExp = format.readConverterExp(); + if (StringUtils.isNotBlank(dictType)) { + // 如果传递了字典名,则依据字典建立下拉 + Collection values = Optional.ofNullable(dictService.getAllDictByDictType(dictType)) + .orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType))) + .values(); + options = new ArrayList<>(values); + } else if (StringUtils.isNotBlank(converterExp)) { + // 如果指定了确切的值,则直接解析确切的值 + List strList = StringUtils.splitList(converterExp, format.separator()); + options = StreamUtils.toList(strList, s -> StringUtils.split(s, "=")[1]); + } + } else if (field.isAnnotationPresent(ExcelEnumFormat.class)) { + // 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑 + ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class); + List values = EnumUtil.getFieldValues(format.enumClass(), format.textField()); + options = StreamUtils.toList(values, String::valueOf); + } + if (ObjectUtil.isNotEmpty(options)) { + // 仅当下拉可选项不为空时执行 + if (options.size() > 20) { + // 这里限制如果可选项大于20,则使用额外表形式 + dropDownWithSheet(helper, workbook, sheet, index, options); + } else { + // 否则使用固定值形式 + dropDownWithSimple(helper, sheet, index, options); + } + } + } + if (CollUtil.isEmpty(dropDownOptions)) { + return; + } + dropDownOptions.forEach(everyOptions -> { + // 如果传递了下拉框选择器参数 + if (!everyOptions.getNextOptions().isEmpty()) { + // 当二级选项不为空时,使用额外关联表的形式 + dropDownLinkedOptions(helper, workbook, sheet, everyOptions); + } else if (everyOptions.getOptions().size() > 10) { + // 当一级选项参数个数大于10,使用额外表的形式 + dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } else { + // 否则使用默认形式 + dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } + }); + } + + /** + *

简单下拉框

+ * 直接将可选项拼接为指定列的数据校验值 + * + * @param celIndex 列index + * @param value 下拉选可选值 + */ + private void dropDownWithSimple(DataValidationHelper helper, Sheet sheet, Integer celIndex, List value) { + if (ObjectUtil.isEmpty(value)) { + return; + } + this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(ArrayUtil.toArray(value, String.class))); + } + + /** + *

额外表格形式的级联下拉框

+ * + * @param options 额外表格形式存储的下拉可选项 + */ + private void dropDownLinkedOptions(DataValidationHelper helper, Workbook workbook, Sheet sheet, DropDownOptions options) { + String linkedOptionsSheetName = String.format("%s_%d", LINKED_OPTIONS_SHEET_NAME, currentLinkedOptionsSheetIndex); + // 创建联动下拉数据表 + Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName)); + // 将下拉表隐藏 + workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true); + // 选项数据 + List firstOptions = options.getOptions(); + Map> secoundOptionsMap = options.getNextOptions(); + + // 采用按行填充数据的方式,避免EasyExcel出现数据无法写入的问题 + // Attempting to write a row in the range that is already written to disk + + // 使用ArrayList记载数据,防止乱序 + List columnNames = new ArrayList<>(); + // 写入第一行,即第一级的数据 + Row firstRow = linkedOptionsDataSheet.createRow(0); + for (int columnIndex = 0; columnIndex < firstOptions.size(); columnIndex++) { + String columnName = firstOptions.get(columnIndex); + firstRow.createCell(columnIndex) + .setCellValue(columnName); + columnNames.add(columnName); + } + + // 创建名称管理器 + Name name = workbook.createName(); + // 设置名称管理器的别名 + name.setNameName(linkedOptionsSheetName); + // 以横向第一行创建一级下拉拼接引用位置 + String firstOptionsFunction = String.format("%s!$%s$1:$%s$1", + linkedOptionsSheetName, + getExcelColumnName(0), + getExcelColumnName(firstOptions.size()) + ); + // 设置名称管理器的引用位置 + name.setRefersToFormula(firstOptionsFunction); + // 设置数据校验为序列模式,引用的是名称管理器中的别名 + this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName)); + + // 创建二级选项的名称管理器 + for (int columIndex = 0; columIndex < columnNames.size(); columIndex++) { + // 列名 + String firstOptionsColumnName = getExcelColumnName(columIndex); + // 对应的一级值 + String thisFirstOptionsValue = columnNames.get(columIndex); + + // 以该一级选项值创建子名称管理器 + Name sonName = workbook.createName(); + // 设置名称管理器的别名 + sonName.setNameName(thisFirstOptionsValue); + // 以第二行该列数据拼接引用位置 + String sonFunction = String.format("%s!$%s$2:$%s$%d", + linkedOptionsSheetName, + firstOptionsColumnName, + firstOptionsColumnName, + // 二级选项存在则设置为(选项个数+1)行,否则设置为2行 + Math.max(Optional.ofNullable(secoundOptionsMap.get(thisFirstOptionsValue)) + .orElseGet(ArrayList::new).size(), 1) + 1 + ); + // 设置名称管理器的引用位置 + sonName.setRefersToFormula(sonFunction); + // 数据验证为序列模式,引用到每一个主表中的二级选项位置 + // 创建子项的名称管理器,只是为了使得Excel可以识别到数据 + String mainSheetFirstOptionsColumnName = getExcelColumnName(options.getIndex()); + for (int i = 0; i < 100; i++) { + // 以一级选项对应的主体所在位置创建二级下拉 + String secondOptionsFunction = String.format("=INDIRECT(%s%d)", mainSheetFirstOptionsColumnName, i + 1); + // 二级只能主表每一行的每一列添加二级校验 + markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction)); + } + } + + // 将二级数据处理为按行区分 + Map> columnValueMap = new HashMap<>(); + int currentRow = 1; + while (currentRow >= 0) { + boolean flag = false; + List rowData = new ArrayList<>(); + for (String columnName : columnNames) { + List data = secoundOptionsMap.get(columnName); + if (CollUtil.isEmpty(data)) { + // 添加空字符串填充位置 + rowData.add(" "); + continue; + } + // 取第一个 + String str = data.get(0); + rowData.add(str); + // 通过移除的方式避免重复 + data.remove(0); + // 设置可以继续 + flag = true; + } + columnValueMap.put(currentRow, rowData); + // 可以继续,则增加行数,否则置为负数跳出循环 + if (flag) { + currentRow++; + } else { + currentRow = -1; + } + } + + // 填充第二级选项数据 + columnValueMap.forEach((rowIndex, rowValues) -> { + Row row = linkedOptionsDataSheet.createRow(rowIndex); + for (int columnIndex = 0; columnIndex < rowValues.size(); columnIndex++) { + String rowValue = rowValues.get(columnIndex); + // 填充位置的部分不渲染 + if (StrUtil.isNotBlank(rowValue)) { + row.createCell(columnIndex) + .setCellValue(rowValue); + } + } + }); + + currentLinkedOptionsSheetIndex++; + } + + /** + *

额外表格形式的普通下拉框

+ * 由于下拉框可选值数量过多,为提升Excel打开效率,使用额外表格形式做下拉 + * + * @param celIndex 下拉选 + * @param value 下拉选可选值 + */ + private void dropDownWithSheet(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer celIndex, List value) { + // 创建下拉数据表 + Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))) + .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))); + // 将下拉表隐藏 + workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true); + // 完善纵向的一级选项数据表 + for (int i = 0; i < value.size(); i++) { + int finalI = i; + // 获取每一选项行,如果没有则创建 + Row row = Optional.ofNullable(simpleDataSheet.getRow(i)) + .orElseGet(() -> simpleDataSheet.createRow(finalI)); + // 获取本级选项对应的选项列,如果没有则创建 + Cell cell = Optional.ofNullable(row.getCell(currentOptionsColumnIndex)) + .orElseGet(() -> row.createCell(currentOptionsColumnIndex)); + // 设置值 + cell.setCellValue(value.get(i)); + } + + // 创建名称管理器 + Name name = workbook.createName(); + // 设置名称管理器的别名 + String nameName = String.format("%s_%d", OPTIONS_SHEET_NAME, celIndex); + name.setNameName(nameName); + // 以纵向第一列创建一级下拉拼接引用位置 + String function = String.format("%s!$%s$1:$%s$%d", + OPTIONS_SHEET_NAME, + getExcelColumnName(currentOptionsColumnIndex), + getExcelColumnName(currentOptionsColumnIndex), + value.size()); + // 设置名称管理器的引用位置 + name.setRefersToFormula(function); + // 设置数据校验为序列模式,引用的是名称管理器中的别名 + this.markOptionsToSheet(helper, sheet, celIndex, helper.createFormulaListConstraint(nameName)); + currentOptionsColumnIndex++; + } + + /** + * 挂载下拉的列,仅限一级选项 + */ + private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex, + DataValidationConstraint constraint) { + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 挂载下拉的列,仅限二级选项 + */ + private void markLinkedOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer rowIndex, + Integer celIndex, DataValidationConstraint constraint) { + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, rowIndex, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 应用数据校验 + */ + private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet, + DataValidationConstraint constraint, CellRangeAddressList addressList) { + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, addressList); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + //数据校验 + dataValidation.setSuppressDropDownArrow(true); + //错误提示 + dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP); + dataValidation.createErrorBox("提示", "此值与单元格定义数据不一致"); + dataValidation.setShowErrorBox(true); + //选定提示 + dataValidation.createPromptBox("填写说明:", "填写内容只能为下拉中数据,其他数据将导致导入失败"); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + *

依据列index获取列名英文

+ * 依据列index转换为Excel中的列名英文 + *

例如第1列,index为0,解析出来为A列

+ * 第27列,index为26,解析为AA列 + *

第28列,index为27,解析为AB列

+ * + * @param columnIndex 列index + * @return 列index所在得英文名 + */ + private String getExcelColumnName(int columnIndex) { + // 26一循环的次数 + int columnCircleCount = columnIndex / 26; + // 26一循环内的位置 + int thisCircleColumnIndex = columnIndex % 26; + // 26一循环的次数大于0,则视为栏名至少两位 + String columnPrefix = columnCircleCount == 0 + ? StrUtil.EMPTY + : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1); + // 从26一循环内取对应的栏位名 + String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1); + // 将二者拼接即为最终的栏位名 + return columnPrefix + columnNext; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java new file mode 100644 index 0000000..2d0340f --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java @@ -0,0 +1,14 @@ +package org.dromara.common.excel.core; + +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Excel 导入监听 + * + * @author Lion Li + */ +public interface ExcelListener extends ReadListener { + + ExcelResult getExcelResult(); + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java new file mode 100644 index 0000000..0c2a418 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java @@ -0,0 +1,26 @@ +package org.dromara.common.excel.core; + +import java.util.List; + +/** + * excel返回对象 + * + * @author Lion Li + */ +public interface ExcelResult { + + /** + * 对象列表 + */ + List getList(); + + /** + * 错误列表 + */ + List getErrorList(); + + /** + * 导入回执 + */ + String getAnalysis(); +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java new file mode 100644 index 0000000..a2aa495 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java @@ -0,0 +1,135 @@ +package org.dromara.common.excel.handler; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.excel.metadata.data.DataFormatData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.excel.annotation.ExcelNotation; +import org.dromara.common.excel.annotation.ExcelRequired; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 批注、必填 + * + * @author guzhouyanyu + */ +public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler { + + /** + * 批注 + */ + private final Map notationMap; + + /** + * 头列字体颜色 + */ + private final Map headColumnMap; + + + public DataWriteHandler(Class clazz) { + notationMap = getNotationMap(clazz); + headColumnMap = getRequiredMap(clazz); + } + + @Override + public void afterCellDispose(CellWriteHandlerContext context) { + if (CollUtil.isEmpty(notationMap) && CollUtil.isEmpty(headColumnMap)) { + return; + } + WriteCellData cellData = context.getFirstCellData(); + WriteCellStyle writeCellStyle = cellData.getOrCreateStyle(); + + DataFormatData dataFormatData = new DataFormatData(); + // 单元格设置为文本格式 + dataFormatData.setIndex((short) 49); + writeCellStyle.setDataFormatData(dataFormatData); + + if (context.getHead()) { + Cell cell = context.getCell(); + WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder(); + Sheet sheet = writeSheetHolder.getSheet(); + Workbook workbook = writeSheetHolder.getSheet().getWorkbook(); + Drawing drawing = sheet.createDrawingPatriarch(); + // 设置标题字体样式 + WriteFont headWriteFont = new WriteFont(); + // 加粗 + headWriteFont.setBold(true); + if (CollUtil.isNotEmpty(headColumnMap) && headColumnMap.containsKey(cell.getColumnIndex())) { + // 设置字体颜色 + headWriteFont.setColor(headColumnMap.get(cell.getColumnIndex())); + } + writeCellStyle.setWriteFont(headWriteFont); + CellStyle cellStyle = StyleUtil.buildCellStyle(workbook, null, writeCellStyle); + cell.setCellStyle(cellStyle); + + if (CollUtil.isNotEmpty(notationMap) && notationMap.containsKey(cell.getColumnIndex())) { + // 批注内容 + String notationContext = notationMap.get(cell.getColumnIndex()); + // 创建绘图对象 + Comment comment = drawing.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), 0, (short) 5, 5)); + comment.setString(new XSSFRichTextString(notationContext)); + cell.setCellComment(comment); + } + } + } + + /** + * 获取必填列 + */ + private static Map getRequiredMap(Class clazz) { + Map requiredMap = new HashMap<>(); + Field[] fields = clazz.getDeclaredFields(); + // 检查 fields 数组是否为空 + if (fields.length == 0) { + return requiredMap; + } + Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName())); + + for (int i = 0; i < filteredFields.length; i++) { + Field field = filteredFields[i]; + if (!field.isAnnotationPresent(ExcelRequired.class)) { + continue; + } + ExcelRequired excelRequired = field.getAnnotation(ExcelRequired.class); + int columnIndex = excelRequired.index() == -1 ? i : excelRequired.index(); + requiredMap.put(columnIndex, excelRequired.fontColor().getIndex()); + } + return requiredMap; + } + + /** + * 获取批注 + */ + private static Map getNotationMap(Class clazz) { + Map notationMap = new HashMap<>(); + Field[] fields = clazz.getDeclaredFields(); + // 检查 fields 数组是否为空 + if (fields.length == 0) { + return notationMap; + } + Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName())); + for (int i = 0; i < filteredFields.length; i++) { + Field field = filteredFields[i]; + if (!field.isAnnotationPresent(ExcelNotation.class)) { + continue; + } + ExcelNotation excelNotation = field.getAnnotation(ExcelNotation.class); + int columnIndex = excelNotation.index() == -1 ? i : excelNotation.index(); + notationMap.put(columnIndex, excelNotation.value()); + } + return notationMap; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java new file mode 100644 index 0000000..b22e6f9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java @@ -0,0 +1,439 @@ +package org.dromara.common.excel.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.excel.convert.ExcelBigNumberConvert; +import org.dromara.common.excel.core.*; +import org.dromara.common.excel.handler.DataWriteHandler; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Excel相关处理 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ExcelUtil { + + /** + * 同步导入(适用于小数据量) + * + * @param is 输入流 + * @return 转换后集合 + */ + public static List importExcel(InputStream is, Class clazz) { + return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); + } + + + /** + * 使用校验监听器 异步导入 同步返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param isValidate 是否 Validator 检验 默认为是 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate) { + DefaultExcelListener listener = new DefaultExcelListener<>(isValidate); + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 使用自定义监听器 异步导入 自定义返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param listener 自定义监听器 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, ExcelListener listener) { + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, false, os, null); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + * @param options 级联下拉选 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response, List options) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, false, os, options); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, merge, os, null); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + * @param options 级联下拉选 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response, List options) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, merge, os, options); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os) { + exportExcel(list, sheetName, clazz, false, os, null); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param os 输出流 + * @param options 级联下拉选内容 + */ + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os, List options) { + exportExcel(list, sheetName, clazz, false, os, options); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, + OutputStream os, List options) { + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new DataWriteHandler(clazz)) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(list, true)); + } + // 添加下拉框操作 + builder.registerWriteHandler(new ExcelDownHandler(options)); + builder.doWrite(list); + } + + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplate(List data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplate(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplate(List data, String templatePath, OutputStream os) { + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new DataWriteHandler(data.get(0).getClass())) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + // 单表多数据导出 模板格式为 {.属性} + for (T d : data) { + excelWriter.fill(d, writeSheet); + } + excelWriter.finish(); + } + + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplateMultiList(Map data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplateMultiList(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 多sheet模板导出 模板格式为 {key.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplateMultiSheet(List> data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplateMultiSheet(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplateMultiList(Map data, String templatePath, OutputStream os) { + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + for (Map.Entry map : data.entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } + } + excelWriter.finish(); + } + + /** + * 多sheet模板导出 模板格式为 {key.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplateMultiSheet(List> data, String templatePath, OutputStream os) { + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + for (int i = 0; i < data.size(); i++) { + WriteSheet writeSheet = EasyExcel.writerSheet(i).build(); + for (Map.Entry map : data.get(i).entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } + } + } + excelWriter.finish(); + } + + /** + * 重置响应体 + */ + private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException { + String filename = encodingFilename(sheetName); + FileUtils.setAttachmentResponseHeader(response, filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[0].equals(value)) { + propertyString.append(itemArray[1] + separator); + break; + } + } + } else { + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[1].equals(value)) { + propertyString.append(itemArray[0] + separator); + break; + } + } + } else { + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 编码文件名 + */ + public static String encodingFilename(String filename) { + return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; + } + +} diff --git a/ruoyi-common/ruoyi-common-idempotent/pom.xml b/ruoyi-common/ruoyi-common-idempotent/pom.xml new file mode 100644 index 0000000..64418b4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/pom.xml @@ -0,0 +1,41 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-idempotent + + + ruoyi-common-idempotent 幂等功能 + + + + + org.dromara + ruoyi-common-json + + + + org.dromara + ruoyi-common-redis + + + + cn.hutool + hutool-crypto + + + + cn.dev33 + sa-token-core + + + + + diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java new file mode 100644 index 0000000..42ae802 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java @@ -0,0 +1,29 @@ +package org.dromara.common.idempotent.annotation; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +/** + * 自定义注解防止表单重复提交 + * + * @author Lion Li + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit { + + /** + * 间隔时间(ms),小于此时间视为重复提交 + */ + int interval() default 5000; + + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; + + /** + * 提示消息 支持国际化 格式为 {code} + */ + String message() default "{repeat.submit.message}"; + +} diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java new file mode 100644 index 0000000..5a27e91 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java @@ -0,0 +1,146 @@ +package org.dromara.common.idempotent.aspectj; + +import cn.dev33.satoken.SaManager; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.SecureUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.time.Duration; +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; + +/** + * 防止重复提交(参考美团GTIS防重系统) + * + * @author Lion Li + */ +@Aspect +public class RepeatSubmitAspect { + + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + + @Before("@annotation(repeatSubmit)") + public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { + // 如果注解不为0 则使用注解数值 + long interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval()); + + if (interval < 1000) { + throw new ServiceException("重复提交间隔时间不能小于'1'秒"); + } + HttpServletRequest request = ServletUtils.getRequest(); + String nowParams = argsArrayToString(point.getArgs()); + + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); + + // 唯一值(没有消息头则使用请求地址) + String submitKey = StringUtils.trimToEmpty(request.getHeader(SaManager.getConfig().getTokenName())); + + submitKey = SecureUtil.md5(submitKey + ":" + nowParams); + // 唯一标识(指定key + url + 消息头) + String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey; + if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) { + KEY_CACHE.set(cacheRepeatKey); + } else { + String message = repeatSubmit.message(); + if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { + message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); + } + throw new ServiceException(message); + } + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) { + if (jsonResult instanceof R r) { + try { + // 成功则不删除redis数据 保证在有效时间内无法重复提交 + if (r.getCode() == R.SUCCESS) { + return; + } + RedisUtils.deleteObject(KEY_CACHE.get()); + } finally { + KEY_CACHE.remove(); + } + } + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) { + RedisUtils.deleteObject(KEY_CACHE.get()); + KEY_CACHE.remove(); + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray) { + StringJoiner params = new StringJoiner(" "); + if (ArrayUtil.isEmpty(paramsArray)) { + return params.toString(); + } + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + params.add(JsonUtils.toJsonString(o)); + } + } + return params.toString(); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return MultipartFile.class.isAssignableFrom(clazz.getComponentType()); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.values()) { + return value instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } + +} diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java new file mode 100644 index 0000000..fcb9d03 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java @@ -0,0 +1,21 @@ +package org.dromara.common.idempotent.config; + +import org.dromara.common.idempotent.aspectj.RepeatSubmitAspect; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisConfiguration; + +/** + * 幂等功能配置 + * + * @author Lion Li + */ +@AutoConfiguration(after = RedisConfiguration.class) +public class IdempotentConfig { + + @Bean + public RepeatSubmitAspect repeatSubmitAspect() { + return new RepeatSubmitAspect(); + } + +} diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..f2fa958 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.idempotent.config.IdempotentConfig diff --git a/ruoyi-common/ruoyi-common-job/pom.xml b/ruoyi-common/ruoyi-common-job/pom.xml new file mode 100644 index 0000000..3a4a0cb --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/pom.xml @@ -0,0 +1,46 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-job + + + ruoyi-common-job 定时任务 + + + + + + org.springframework.boot + spring-boot-autoconfigure + + + + + com.aizuda + snail-job-client-starter + + + com.aizuda + snail-job-client-job-core + + + + org.projectlombok + lombok + + + + org.dromara + ruoyi-common-core + + + + diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java new file mode 100644 index 0000000..cba3753 --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java @@ -0,0 +1,37 @@ +package org.dromara.common.job.config; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import com.aizuda.snailjob.client.common.appender.SnailLogbackAppender; +import com.aizuda.snailjob.client.common.event.SnailClientStartingEvent; +import com.aizuda.snailjob.client.starter.EnableSnailJob; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * 启动定时任务 + * + * @author opensnail + * @date 2024-05-17 + */ +@AutoConfiguration +@ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true") +@EnableScheduling +@EnableSnailJob +public class SnailJobConfig { + + @EventListener(SnailClientStartingEvent.class) + public void onStarting(SnailClientStartingEvent event) { + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + SnailLogbackAppender ca = new SnailLogbackAppender<>(); + ca.setName("snail_log_appender"); + ca.start(); + Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME); + rootLogger.addAppender(ca); + } + +} diff --git a/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..3aa1881 --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.job.config.SnailJobConfig diff --git a/ruoyi-common/ruoyi-common-json/pom.xml b/ruoyi-common/ruoyi-common-json/pom.xml new file mode 100644 index 0000000..870df5c --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/pom.xml @@ -0,0 +1,37 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-json + + + ruoyi-common-json 序列化模块 + + + + + org.dromara + ruoyi-common-core + + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java new file mode 100644 index 0000000..36400bc --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java @@ -0,0 +1,47 @@ +package org.dromara.common.json.config; + +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.json.handler.BigNumberSerializer; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * jackson 配置 + * + * @author Lion Li + */ +@Slf4j +@AutoConfiguration(before = JacksonAutoConfiguration.class) +public class JacksonConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + // 全局配置序列化返回 JSON 处理 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + builder.modules(javaTimeModule); + builder.timeZone(TimeZone.getDefault()); + log.info("初始化 jackson 配置"); + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigDecimalToIntegerSerializer.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigDecimalToIntegerSerializer.java new file mode 100644 index 0000000..4d9f2fb --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigDecimalToIntegerSerializer.java @@ -0,0 +1,16 @@ +package org.dromara.common.json.handler; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class BigDecimalToIntegerSerializer extends JsonSerializer { + @Override + public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeNumber(value.setScale(0, RoundingMode.DOWN)); // 去除小数部分 + } +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java new file mode 100644 index 0000000..8752353 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java @@ -0,0 +1,42 @@ +package org.dromara.common.json.handler; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.ser.std.NumberSerializer; + +import java.io.IOException; + +/** + * 超出 JS 最大最小值 处理 + * + * @author Lion Li + */ +@JacksonStdImpl +public class BigNumberSerializer extends NumberSerializer { + + /** + * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来 + */ + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); + + public BigNumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 超出范围 序列化为字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + gen.writeString(value.toString()); + } + } +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java new file mode 100644 index 0000000..65c2faa --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java @@ -0,0 +1,170 @@ +package org.dromara.common.json.utils; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils { + + private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class); + + public static ObjectMapper getObjectMapper() { + return OBJECT_MAPPER; + } + + /** + * 将对象转换为JSON格式的字符串 + * + * @param object 要转换的对象 + * @return JSON格式的字符串,如果对象为null,则返回null + * @throws RuntimeException 如果转换过程中发生JSON处理异常,则抛出运行时异常 + */ + public static String toJsonString(Object object) { + if (ObjectUtil.isNull(object)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型的对象 + * + * @param text JSON格式的字符串 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将字节数组转换为指定类型的对象 + * + * @param bytes 字节数组 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字节数组为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型的对象,支持复杂类型 + * + * @param text JSON格式的字符串 + * @param typeReference 指定类型的TypeReference对象 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(String text, TypeReference typeReference) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为Dict对象 + * + * @param text JSON格式的字符串 + * @return 转换后的Dict对象,如果字符串为空或者不是JSON格式则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static Dict parseMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); + } catch (MismatchedInputException e) { + // 类型不匹配说明不是json + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为Dict对象的列表 + * + * @param text JSON格式的字符串 + * @return 转换后的Dict对象的列表,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static List parseArrayMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型对象的列表 + * + * @param text JSON格式的字符串 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象的列表,如果字符串为空则返回空列表 + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static List parseArray(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..1625397 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.json.config.JacksonConfig diff --git a/ruoyi-common/ruoyi-common-jts/pom.xml b/ruoyi-common/ruoyi-common-jts/pom.xml new file mode 100644 index 0000000..b456504 --- /dev/null +++ b/ruoyi-common/ruoyi-common-jts/pom.xml @@ -0,0 +1,26 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-jts + + + ruoyi-common-jts 地图工具模块 + + + + + + org.locationtech.jts + jts-core + + + + diff --git a/ruoyi-common/ruoyi-common-log/pom.xml b/ruoyi-common/ruoyi-common-log/pom.xml new file mode 100644 index 0000000..1e2b33b --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/pom.xml @@ -0,0 +1,32 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-log + + + ruoyi-common-log 日志记录 + + + + + + org.dromara + ruoyi-common-satoken + + + + org.dromara + ruoyi-common-json + + + + + diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java new file mode 100644 index 0000000..2dced97 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java @@ -0,0 +1,48 @@ +package org.dromara.common.log.annotation; + +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.log.enums.OperatorType; + +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author ruoyi + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log { + /** + * 模块 + */ + String title() default ""; + + /** + * 功能 + */ + BusinessType businessType() default BusinessType.OTHER; + + /** + * 操作人类别 + */ + OperatorType operatorType() default OperatorType.MANAGE; + + /** + * 是否保存请求的参数 + */ + boolean isSaveRequestData() default true; + + /** + * 是否保存响应的参数 + */ + boolean isSaveResponseData() default true; + + + /** + * 排除指定的请求参数 + */ + String[] excludeParamNames() default {}; + +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java new file mode 100644 index 0000000..8ab2719 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java @@ -0,0 +1,219 @@ +package org.dromara.common.log.aspect; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.StopWatch; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessStatus; +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.http.HttpMethod; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; + +/** + * 操作日志记录处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +@AutoConfiguration +public class LogAspect { + + /** + * 排除敏感属性字段 + */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + + /** + * 计时 key + */ + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(controllerLog)") + public void doBefore(JoinPoint joinPoint, Log controllerLog) { + StopWatch stopWatch = new StopWatch(); + KEY_CACHE.set(stopWatch); + stopWatch.start(); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) { + handleLog(joinPoint, controllerLog, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) { + handleLog(joinPoint, controllerLog, e, null); + } + + protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) { + try { + + // *========数据库日志=========*// + OperLogEvent operLog = new OperLogEvent(); + operLog.setTenantId(LoginHelper.getTenantId()); + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + String ip = ServletUtils.getClientIP(); + operLog.setOperIp(ip); + operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); + LoginUser loginUser = LoginHelper.getLoginUser(); + operLog.setOperName(loginUser.getUsername()); + operLog.setDeptName(loginUser.getDeptName()); + + if (e != null) { + operLog.setStatus(BusinessStatus.FAIL.ordinal()); + operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 3800)); + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + operLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); + // 处理设置注解上的参数 + getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); + // 设置消耗时间 + StopWatch stopWatch = KEY_CACHE.get(); + stopWatch.stop(); + operLog.setCostTime(stopWatch.getDuration().toMillis()); + // 发布事件保存数据库 + SpringUtils.context().publishEvent(operLog); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + } finally { + KEY_CACHE.remove(); + } + } + + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception { + // 设置action动作 + operLog.setBusinessType(log.businessType().ordinal()); + // 设置标题 + operLog.setTitle(log.title()); + // 设置操作人类别 + operLog.setOperatorType(log.operatorType().ordinal()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) { + // 获取参数的信息,传入到数据库中。 + setRequestValue(joinPoint, operLog, log.excludeParamNames()); + } + // 是否需要保存response,参数和值 + if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) { + operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 3800)); + } + } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { + Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); + String requestMethod = operLog.getRequestMethod(); + if (MapUtil.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) { + String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); + operLog.setOperParam(StringUtils.substring(params, 0, 3800)); + } else { + MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); + MapUtil.removeAny(paramsMap, excludeParamNames); + operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 3800)); + } + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) { + StringJoiner params = new StringJoiner(" "); + if (ArrayUtil.isEmpty(paramsArray)) { + return params.toString(); + } + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + String str = JsonUtils.toJsonString(o); + Dict dict = JsonUtils.parseMap(str); + if (MapUtil.isNotEmpty(dict)) { + MapUtil.removeAny(dict, EXCLUDE_PROPERTIES); + MapUtil.removeAny(dict, excludeParamNames); + str = JsonUtils.toJsonString(dict); + } + params.add(str); + } + } + return params.toString(); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return MultipartFile.class.isAssignableFrom(clazz.getComponentType()); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.values()) { + return value instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java new file mode 100644 index 0000000..d303dc3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java @@ -0,0 +1,18 @@ +package org.dromara.common.log.enums; + +/** + * 操作状态 + * + * @author ruoyi + */ +public enum BusinessStatus { + /** + * 成功 + */ + SUCCESS, + + /** + * 失败 + */ + FAIL, +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java new file mode 100644 index 0000000..2d25ebb --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java @@ -0,0 +1,58 @@ +package org.dromara.common.log.enums; + +/** + * 业务操作类型 + * + * @author ruoyi + */ +public enum BusinessType { + /** + * 其它 + */ + OTHER, + + /** + * 新增 + */ + INSERT, + + /** + * 修改 + */ + UPDATE, + + /** + * 删除 + */ + DELETE, + + /** + * 授权 + */ + GRANT, + + /** + * 导出 + */ + EXPORT, + + /** + * 导入 + */ + IMPORT, + + /** + * 强退 + */ + FORCE, + + /** + * 生成代码 + */ + GENCODE, + + /** + * 清空数据 + */ + CLEAN, +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java new file mode 100644 index 0000000..de9328b --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java @@ -0,0 +1,23 @@ +package org.dromara.common.log.enums; + +/** + * 操作人类别 + * + * @author ruoyi + */ +public enum OperatorType { + /** + * 其它 + */ + OTHER, + + /** + * 后台用户 + */ + MANAGE, + + /** + * 手机端用户 + */ + MOBILE +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java new file mode 100644 index 0000000..938eaad --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java @@ -0,0 +1,52 @@ +package org.dromara.common.log.event; + +import lombok.Data; + +import jakarta.servlet.http.HttpServletRequest; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 登录事件 + * + * @author Lion Li + */ + +@Data +public class LogininforEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 用户账号 + */ + private String username; + + /** + * 登录状态 0成功 1失败 + */ + private String status; + + /** + * 提示消息 + */ + private String message; + + /** + * 请求体 + */ + private HttpServletRequest request; + + /** + * 其他参数 + */ + private Object[] args; + +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java new file mode 100644 index 0000000..0386192 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java @@ -0,0 +1,115 @@ +package org.dromara.common.log.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 操作日志事件 + * + * @author Lion Li + */ + +@Data +public class OperLogEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + private Long operId; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 操作模块 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求url + */ + private String operUrl; + + /** + * 操作地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..6893020 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.log.aspect.LogAspect diff --git a/ruoyi-common/ruoyi-common-mail/pom.xml b/ruoyi-common/ruoyi-common-mail/pom.xml new file mode 100644 index 0000000..c0e1b2e --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/pom.xml @@ -0,0 +1,34 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-mail + + + ruoyi-common-mail 邮件模块 + + + + + org.dromara + ruoyi-common-core + + + + jakarta.mail + jakarta.mail-api + + + org.eclipse.angus + jakarta.mail + + + + diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java new file mode 100644 index 0000000..0ea3007 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java @@ -0,0 +1,37 @@ +package org.dromara.common.mail.config; + +import cn.hutool.extra.mail.MailAccount; +import org.dromara.common.mail.config.properties.MailProperties; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * JavaMail 配置 + * + * @author Michelle.Chung + */ +@AutoConfiguration +@EnableConfigurationProperties(MailProperties.class) +public class MailConfig { + + @Bean + @ConditionalOnProperty(value = "mail.enabled", havingValue = "true") + public MailAccount mailAccount(MailProperties mailProperties) { + MailAccount account = new MailAccount(); + account.setHost(mailProperties.getHost()); + account.setPort(mailProperties.getPort()); + account.setAuth(mailProperties.getAuth()); + account.setFrom(mailProperties.getFrom()); + account.setUser(mailProperties.getUser()); + account.setPass(mailProperties.getPass()); + account.setSocketFactoryPort(mailProperties.getPort()); + account.setStarttlsEnable(mailProperties.getStarttlsEnable()); + account.setSslEnable(mailProperties.getSslEnable()); + account.setTimeout(mailProperties.getTimeout()); + account.setConnectionTimeout(mailProperties.getConnectionTimeout()); + return account; + } + +} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java new file mode 100644 index 0000000..e44aa3d --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java @@ -0,0 +1,75 @@ +package org.dromara.common.mail.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * JavaMail 配置属性 + * + * @author Michelle.Chung + */ +@Data +@ConfigurationProperties(prefix = "mail") +public class MailProperties { + + /** + * 过滤开关 + */ + private Boolean enabled; + + /** + * SMTP服务器域名 + */ + private String host; + + /** + * SMTP服务端口 + */ + private Integer port; + + /** + * 是否需要用户名密码验证 + */ + private Boolean auth; + + /** + * 用户名 + */ + private String user; + + /** + * 密码 + */ + private String pass; + + /** + * 发送方,遵循RFC-822标准
+ * 发件人可以是以下形式: + * + *
+     * 1. user@xxx.xx
+     * 2.  name <user@xxx.xx>
+     * 
+ */ + private String from; + + /** + * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 + */ + private Boolean starttlsEnable; + + /** + * 使用 SSL安全连接 + */ + private Boolean sslEnable; + + /** + * SMTP超时时长,单位毫秒,缺省值不超时 + */ + private Long timeout; + + /** + * Socket连接超时值,单位毫秒,缺省值不超时 + */ + private Long connectionTimeout; +} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java new file mode 100644 index 0000000..a28701f --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java @@ -0,0 +1,469 @@ +package org.dromara.common.mail.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.JakartaMail; +import cn.hutool.extra.mail.JakartaUserPassAuthenticator; +import cn.hutool.extra.mail.MailAccount; +import jakarta.mail.Authenticator; +import jakarta.mail.Session; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; + +import java.io.File; +import java.io.InputStream; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * 邮件工具类 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MailUtils { + + private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class); + + /** + * 获取邮件发送实例 + */ + public static MailAccount getMailAccount() { + return ACCOUNT; + } + + /** + * 获取邮件发送实例 (自定义发送人以及授权码) + * + * @param user 发送人 + * @param pass 授权码 + */ + public static MailAccount getMailAccount(String from, String user, String pass) { + ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom())); + ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser())); + ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass())); + return ACCOUNT; + } + + /** + * 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendText(String to, String subject, String content, File... files) { + return send(to, subject, content, false, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, File... files) { + return send(to, subject, content, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送文本邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + */ + public static String sendText(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, false, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, Map imageMap, File... files) { + return send(to, subject, content, imageMap, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, Map imageMap, File... files) { + return send(tos, subject, content, imageMap, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, + boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + + /** + * 根据配置文件,获取邮件客户端会话 + * + * @param mailAccount 邮件账户配置 + * @param isSingleton 是否单例(全局共享会话) + * @return {@link Session} + * @since 5.5.7 + */ + public static Session getSession(MailAccount mailAccount, boolean isSingleton) { + Authenticator authenticator = null; + if (mailAccount.isAuth()) { + authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass()); + } + + return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) // + : Session.getInstance(mailAccount.getSmtpProps(), authenticator); + } + + // ------------------------------------------------------------------------------------------------------------------------ Private method start + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param useGlobalSession 是否全局共享Session + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:${cid} + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection tos, Collection ccs, Collection bccs, String subject, String content, + Map imageMap, boolean isHtml, File... files) { + final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession); + + // 可选抄送人 + if (CollUtil.isNotEmpty(ccs)) { + mail.setCcs(ccs.toArray(new String[0])); + } + // 可选密送人 + if (CollUtil.isNotEmpty(bccs)) { + mail.setBccs(bccs.toArray(new String[0])); + } + + mail.setTos(tos.toArray(new String[0])); + mail.setTitle(subject); + mail.setContent(content); + mail.setHtml(isHtml); + mail.setFiles(files); + + // 图片 + if (MapUtil.isNotEmpty(imageMap)) { + for (Entry entry : imageMap.entrySet()) { + mail.addImage(entry.getKey(), entry.getValue()); + // 关闭流 + IoUtil.close(entry.getValue()); + } + } + + return mail.send(); + } + + /** + * 将多个联系人转为列表,分隔符为逗号或者分号 + * + * @param addresses 多个联系人,如果为空返回null + * @return 联系人列表 + */ + private static List splitAddress(String addresses) { + if (StrUtil.isBlank(addresses)) { + return null; + } + + List result; + if (StrUtil.contains(addresses, CharUtil.COMMA)) { + result = StrUtil.splitTrim(addresses, CharUtil.COMMA); + } else if (StrUtil.contains(addresses, ';')) { + result = StrUtil.splitTrim(addresses, ';'); + } else { + result = CollUtil.newArrayList(addresses); + } + return result; + } + // ------------------------------------------------------------------------------------------------------------------------ Private method end +} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..ef0cf11 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.mail.config.MailConfig diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml new file mode 100644 index 0000000..2d4dc74 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml @@ -0,0 +1,57 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-mybatis + + + ruoyi-common-mybatis 数据库服务 + + + + + org.dromara + ruoyi-common-core + + + + org.dromara + ruoyi-common-satoken + + + + org.dromara + ruoyi-common-doc + + + + + com.baomidou + dynamic-datasource-spring-boot3-starter + + + + com.baomidou + mybatis-plus-spring-boot3-starter + + + + com.baomidou + mybatis-plus-jsqlparser + + + + + p6spy + p6spy + + + + diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java new file mode 100644 index 0000000..2879b9d --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java @@ -0,0 +1,40 @@ +package org.dromara.common.mybatis.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限注解,用于标记数据权限的占位符关键字和替换值 + *

+ * 一个注解只能对应一个模板 + *

+ * + * @author Lion Li + * @version 3.5.0 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataColumn { + + /** + * 数据权限模板的占位符关键字,默认为 "deptName" + * + * @return 占位符关键字数组 + */ + String[] key() default "deptName"; + + /** + * 数据权限模板的占位符替换值,默认为 "dept_id" + * + * @return 占位符替换值数组 + */ + String[] value() default "dept_id"; + + /** + * 权限标识符 用于通过菜单权限标识符来获取数据权限 + * 拥有此标识符的角色 将不会拼接此角色的数据过滤sql + * + * @return 权限标识符 + */ + String permission() default ""; +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java new file mode 100644 index 0000000..f5f22d5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java @@ -0,0 +1,30 @@ +package org.dromara.common.mybatis.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限组注解,用于标记数据权限配置数组 + * + * @author Lion Li + * @version 3.5.0 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + /** + * 数据权限配置数组,用于指定数据权限的占位符关键字和替换值 + * + * @return 数据权限配置数组 + */ + DataColumn[] value(); + + /** + * 权限拼接标识符(用于指定连接语句的sql符号) + * 如不填 默认 select 用 OR 其他语句用 AND + * 内容 OR 或者 AND + */ + String joinStr() default ""; + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java new file mode 100644 index 0000000..1c83cc3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java @@ -0,0 +1,50 @@ +package org.dromara.common.mybatis.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.helper.DataPermissionHelper; + +/** + * 数据权限处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +public class DataPermissionAspect { + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(dataPermission)") + public void doBefore(JoinPoint joinPoint, DataPermission dataPermission) { + DataPermissionHelper.setPermission(dataPermission); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(dataPermission)") + public void doAfterReturning(JoinPoint joinPoint, DataPermission dataPermission) { + DataPermissionHelper.removePermission(); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(dataPermission)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, DataPermission dataPermission, Exception e) { + DataPermissionHelper.removePermission(); + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java new file mode 100644 index 0000000..00c2691 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java @@ -0,0 +1,138 @@ +package org.dromara.common.mybatis.config; + +import cn.hutool.core.net.NetUtil; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler; +import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import org.dromara.common.core.factory.YmlPropertySourceFactory; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.mybatis.aspect.DataPermissionAspect; +import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler; +import org.dromara.common.mybatis.handler.MybatisExceptionHandler; +import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler; +import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.BeansException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * mybatis-plus配置类(下方注释有插件介绍) + * + * @author Lion Li + */ +@EnableTransactionManagement(proxyTargetClass = true) +@MapperScan("${mybatis-plus.mapperPackage}") +@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class) +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 多租户插件 必须放到第一位 + try { + TenantLineInnerInterceptor tenant = SpringUtils.getBean(TenantLineInnerInterceptor.class); + interceptor.addInnerInterceptor(tenant); + } catch (BeansException ignore) { + } + // 数据权限处理 + interceptor.addInnerInterceptor(dataPermissionInterceptor()); + // 分页插件 + interceptor.addInnerInterceptor(paginationInnerInterceptor()); + // 乐观锁插件 + interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); + return interceptor; + } + + /** + * 数据权限拦截器 + */ + public PlusDataPermissionInterceptor dataPermissionInterceptor() { + return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage")); + } + + /** + * 数据权限切面处理器 + */ + @Bean + public DataPermissionAspect dataPermissionAspect() { + return new DataPermissionAspect(); + } + + /** + * 分页插件,自动识别数据库类型 + */ + public PaginationInnerInterceptor paginationInnerInterceptor() { + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); + // 分页合理化 + paginationInnerInterceptor.setOverflow(true); + return paginationInnerInterceptor; + } + + /** + * 乐观锁插件 + */ + public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { + return new OptimisticLockerInnerInterceptor(); + } + + /** + * 元对象字段填充控制器 + */ + @Bean + public MetaObjectHandler metaObjectHandler() { + return new InjectionMetaObjectHandler(); + } + + /** + * 使用网卡信息绑定雪花生成器 + * 防止集群雪花ID重复 + */ + @Bean + public IdentifierGenerator idGenerator() { + return new DefaultIdentifierGenerator(NetUtil.getLocalhost()); + } + + /** + * 异常处理器 + */ + @Bean + public MybatisExceptionHandler mybatisExceptionHandler() { + return new MybatisExceptionHandler(); + } + + /** + * 初始化表对象处理器 + */ + @Bean + public PostInitTableInfoHandler postInitTableInfoHandler() { + return new PlusPostInitTableInfoHandler(); + } + + /** + * PaginationInnerInterceptor 分页插件,自动识别数据库类型 + * https://baomidou.com/pages/97710a/ + * OptimisticLockerInnerInterceptor 乐观锁插件 + * https://baomidou.com/pages/0d93c0/ + * MetaObjectHandler 元对象字段填充控制器 + * https://baomidou.com/pages/4c6bcf/ + * ISqlInjector sql注入器 + * https://baomidou.com/pages/42ea4a/ + * BlockAttackInnerInterceptor 如果是对全表的删除或更新操作,就会终止该操作 + * https://baomidou.com/pages/f9a237/ + * IllegalSQLInnerInterceptor sql性能规范插件(垃圾SQL拦截) + * IdentifierGenerator 自定义主键策略 + * https://baomidou.com/pages/568eb2/ + * TenantLineInnerInterceptor 多租户插件 + * https://baomidou.com/pages/aef2f2/ + * DynamicTableNameInnerInterceptor 动态表名插件 + * https://baomidou.com/pages/2a45ff/ + */ + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java new file mode 100644 index 0000000..13a7941 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java @@ -0,0 +1,70 @@ +package org.dromara.common.mybatis.core.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Entity基类 + * + * @author Lion Li + */ +@Data +public class BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 搜索值 + */ + @JsonIgnore + @TableField(exist = false) + private String searchValue; + + /** + * 创建部门 + */ + @TableField(fill = FieldFill.INSERT) + private Long createDept; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @TableField(exist = false) + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java new file mode 100644 index 0000000..24557ed --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java @@ -0,0 +1,334 @@ +package org.dromara.common.mybatis.core.mapper; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.toolkit.Db; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * 自定义 Mapper 接口, 实现 自定义扩展 + * + * @param table 泛型 + * @param vo 泛型 + * @author Lion Li + * @since 2021-05-13 + */ +@SuppressWarnings("unchecked") +public interface BaseMapperPlus extends BaseMapper { + + Log log = LogFactory.getLog(BaseMapperPlus.class); + + /** + * 获取当前实例对象关联的泛型类型 V 的 Class 对象 + * + * @return 返回当前实例对象关联的泛型类型 V 的 Class 对象 + */ + default Class currentVoClass() { + return (Class) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1]; + } + + /** + * 获取当前实例对象关联的泛型类型 T 的 Class 对象 + * + * @return 返回当前实例对象关联的泛型类型 T 的 Class 对象 + */ + default Class currentModelClass() { + return (Class) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[0]; + } + + /** + * 使用默认的查询条件查询并返回结果列表 + * + * @return 返回查询结果的列表 + */ + default List selectList() { + return this.selectList(new QueryWrapper<>()); + } + + /** + * 批量插入实体对象集合 + * + * @param entityList 实体对象集合 + * @return 插入操作是否成功的布尔值 + */ + default boolean insertBatch(Collection entityList) { + return Db.saveBatch(entityList); + } + + /** + * 批量根据ID更新实体对象集合 + * + * @param entityList 实体对象集合 + * @return 更新操作是否成功的布尔值 + */ + default boolean updateBatchById(Collection entityList) { + return Db.updateBatchById(entityList); + } + + /** + * 批量插入或更新实体对象集合 + * + * @param entityList 实体对象集合 + * @return 插入或更新操作是否成功的布尔值 + */ + default boolean insertOrUpdateBatch(Collection entityList) { + return Db.saveOrUpdateBatch(entityList); + } + + /** + * 批量插入实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 插入操作是否成功的布尔值 + */ + default boolean insertBatch(Collection entityList, int batchSize) { + return Db.saveBatch(entityList, batchSize); + } + + /** + * 批量根据ID更新实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 更新操作是否成功的布尔值 + */ + default boolean updateBatchById(Collection entityList, int batchSize) { + return Db.updateBatchById(entityList, batchSize); + } + + /** + * 批量插入或更新实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 插入或更新操作是否成功的布尔值 + */ + default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { + return Db.saveOrUpdateBatch(entityList, batchSize); + } + + /** + * 根据ID查询单个VO对象 + * + * @param id 主键ID + * @return 查询到的单个VO对象 + */ + default V selectVoById(Serializable id) { + return selectVoById(id, this.currentVoClass()); + } + + /** + * 根据ID查询单个VO对象并将其转换为指定的VO类 + * + * @param id 主键ID + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的单个VO对象,经过转换为指定的VO类后返回 + */ + default C selectVoById(Serializable id, Class voClass) { + T obj = this.selectById(id); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + /** + * 根据ID集合批量查询VO对象列表 + * + * @param idList 主键ID集合 + * @return 查询到的VO对象列表 + */ + default List selectVoByIds(Collection idList) { + return selectVoByIds(idList, this.currentVoClass()); + } + + /** + * 根据ID集合批量查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param idList 主键ID集合 + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoByIds(Collection idList, Class voClass) { + List list = this.selectByIds(idList); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据查询条件Map查询VO对象列表 + * + * @param map 查询条件Map + * @return 查询到的VO对象列表 + */ + default List selectVoByMap(Map map) { + return selectVoByMap(map, this.currentVoClass()); + } + + /** + * 根据查询条件Map查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param map 查询条件Map + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoByMap(Map map, Class voClass) { + List list = this.selectByMap(map); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据条件查询单个VO对象 + * + * @param wrapper 查询条件Wrapper + * @return 查询到的单个VO对象 + */ + default V selectVoOne(Wrapper wrapper) { + return selectVoOne(wrapper, this.currentVoClass()); + } + + /** + * 根据条件查询单个VO对象,并根据需要决定是否抛出异常 + * + * @param wrapper 查询条件Wrapper + * @param throwEx 是否抛出异常的标志 + * @return 查询到的单个VO对象 + */ + default V selectVoOne(Wrapper wrapper, boolean throwEx) { + return selectVoOne(wrapper, this.currentVoClass(), throwEx); + } + + /** + * 根据条件查询单个VO对象,并指定返回的VO对象的类型 + * + * @param wrapper 查询条件Wrapper + * @param voClass 返回的VO对象的Class对象 + * @param 返回的VO对象的类型 + * @return 查询到的单个VO对象,经过类型转换为指定的VO类后返回 + */ + default C selectVoOne(Wrapper wrapper, Class voClass) { + return selectVoOne(wrapper, voClass, true); + } + + /** + * 根据条件查询单个实体对象,并将其转换为指定的VO对象 + * + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param throwEx 是否抛出异常的标志 + * @param VO类的类型 + * @return 查询到的单个VO对象,经过转换为指定的VO类后返回 + */ + default C selectVoOne(Wrapper wrapper, Class voClass, boolean throwEx) { + T obj = this.selectOne(wrapper, throwEx); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + /** + * 查询所有VO对象列表 + * + * @return 查询到的VO对象列表 + */ + default List selectVoList() { + return selectVoList(new QueryWrapper<>(), this.currentVoClass()); + } + + /** + * 根据条件查询VO对象列表 + * + * @param wrapper 查询条件Wrapper + * @return 查询到的VO对象列表 + */ + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + + /** + * 根据条件查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoList(Wrapper wrapper, Class voClass) { + List list = this.selectList(wrapper); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据条件分页查询VO对象列表 + * + * @param page 分页信息 + * @param wrapper 查询条件Wrapper + * @return 查询到的VO对象分页列表 + */ + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + /** + * 根据条件分页查询实体对象列表,并将其转换为指定的VO对象分页列表 + * + * @param page 分页信息 + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @param

VO对象分页列表的类型 + * @return 查询到的VO对象分页列表,经过转换为指定的VO类后返回 + */ + default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { + // 根据条件分页查询实体对象列表 + List list = this.selectList(page, wrapper); + // 创建一个新的VO对象分页列表,并设置分页信息 + IPage voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal()); + if (CollUtil.isEmpty(list)) { + return (P) voPage; + } + voPage.setRecords(MapstructUtils.convert(list, voClass)); + return (P) voPage; + } + + /** + * 根据条件查询符合条件的对象,并将其转换为指定类型的对象列表 + * + * @param wrapper 查询条件Wrapper + * @param mapper 转换函数,用于将查询到的对象转换为指定类型的对象 + * @param 要转换的对象的类型 + * @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回 + */ + default List selectObjs(Wrapper wrapper, Function mapper) { + return StreamUtils.toList(this.selectObjs(wrapper), mapper); + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java new file mode 100644 index 0000000..1d5c3c9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java @@ -0,0 +1,127 @@ +package org.dromara.common.mybatis.core.page; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.sql.SqlUtil; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 分页查询实体类 + * + * @author Lion Li + */ +@Data +public class PageQuery implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 分页大小 + */ + private Integer pageSize; + + /** + * 当前页数 + */ + private Integer pageNum; + + /** + * 排序列 + */ + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + private String isAsc; + + /** + * 当前记录起始索引 默认值 + */ + public static final int DEFAULT_PAGE_NUM = 1; + + /** + * 每页显示记录数 默认值 默认查全部 + */ + public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; + + /** + * 构建分页对象 + */ + public Page build() { + Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); + Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); + if (pageNum <= 0) { + pageNum = DEFAULT_PAGE_NUM; + } + Page page = new Page<>(pageNum, pageSize); + List orderItems = buildOrderItem(); + if (CollUtil.isNotEmpty(orderItems)) { + page.addOrder(orderItems); + } + return page; + } + + /** + * 构建排序 + * + * 支持的用法如下: + * {isAsc:"asc",orderByColumn:"id"} order by id asc + * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc + * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc + * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc + */ + private List buildOrderItem() { + if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) { + return null; + } + String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); + orderBy = StringUtils.toUnderScoreCase(orderBy); + + // 兼容前端排序类型 + isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"}); + + String[] orderByArr = orderBy.split(StringUtils.SEPARATOR); + String[] isAscArr = isAsc.split(StringUtils.SEPARATOR); + if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) { + throw new ServiceException("排序参数有误"); + } + + List list = new ArrayList<>(); + // 每个字段各自排序 + for (int i = 0; i < orderByArr.length; i++) { + String orderByStr = orderByArr[i]; + String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i]; + if ("asc".equals(isAscStr)) { + list.add(OrderItem.asc(orderByStr)); + } else if ("desc".equals(isAscStr)) { + list.add(OrderItem.desc(orderByStr)); + } else { + throw new ServiceException("排序参数有误"); + } + } + return list; + } + + @JsonIgnore + public Integer getFirstNum() { + return (pageNum - 1) * pageSize; + } + + public PageQuery(Integer pageSize, Integer pageNum) { + this.pageSize = pageSize; + this.pageNum = pageNum; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java new file mode 100644 index 0000000..370f479 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java @@ -0,0 +1,91 @@ +package org.dromara.common.mybatis.core.page; + +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.metadata.IPage; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 表格分页数据对象 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class TableDataInfo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 总记录数 + */ + private long total; + + /** + * 列表数据 + */ + private List rows; + + /** + * 消息状态码 + */ + private int code; + + /** + * 消息内容 + */ + private String msg; + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, long total) { + this.rows = list; + this.total = total; + this.code = HttpStatus.HTTP_OK; + this.msg = "查询成功"; + } + + /** + * 根据分页对象构建表格分页数据对象 + */ + public static TableDataInfo build(IPage page) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(page.getRecords()); + rspData.setTotal(page.getTotal()); + return rspData; + } + + /** + * 根据数据列表构建表格分页数据对象 + */ + public static TableDataInfo build(List list) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(list.size()); + return rspData; + } + + /** + * 构建表格分页数据对象 + */ + public static TableDataInfo build() { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + return rspData; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java new file mode 100644 index 0000000..5084424 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java @@ -0,0 +1,58 @@ +package org.dromara.common.mybatis.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.utils.StringUtils; + +/** + * 数据库类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DataBaseType { + + /** + * MySQL + */ + MY_SQL("MySQL"), + + /** + * Oracle + */ + ORACLE("Oracle"), + + /** + * PostgreSQL + */ + POSTGRE_SQL("PostgreSQL"), + + /** + * SQL Server + */ + SQL_SERVER("Microsoft SQL Server"); + + /** + * 数据库类型 + */ + private final String type; + + /** + * 根据数据库产品名称查找对应的数据库类型 + * + * @param databaseProductName 数据库产品名称 + * @return 对应的数据库类型枚举值,如果未找到则返回 null + */ + public static DataBaseType find(String databaseProductName) { + if (StringUtils.isBlank(databaseProductName)) { + return null; + } + for (DataBaseType type : values()) { + if (type.getType().equals(databaseProductName)) { + return type; + } + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java new file mode 100644 index 0000000..02a5f48 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java @@ -0,0 +1,87 @@ +package org.dromara.common.mybatis.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.helper.DataPermissionHelper; + +/** + * 数据权限类型枚举 + *

+ * 支持使用 SpEL 模板表达式定义 SQL 查询条件 + * 内置数据: + * - {@code user}: 当前登录用户信息,参考 {@link LoginUser} + * 内置服务: + * - {@code sdss}: 系统数据权限服务,参考 ISysDataScopeService + * 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作 + * 如需扩展服务,可以通过 ISysDataScopeService 自行编写 + *

+ * + * @author Lion Li + * @version 3.5.0 + */ +@Getter +@AllArgsConstructor +public enum DataScopeType { + + /** + * 全部数据权限 + */ + ALL("1", "", ""), + + /** + * 自定数据权限 + */ + CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "), + + /** + * 部门数据权限 + */ + DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "), + + /** + * 部门及以下数据权限 + */ + DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "), + + /** + * 仅本人数据权限 + */ + SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "), + + /** + * 部门及以下或本人数据权限 + */ + DEPT_AND_CHILD_OR_SELF("6", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} ) OR #{#userName} = #{#user.userId} ", " 1 = 0 "); + + private final String code; + + /** + * SpEL 模板表达式,用于构建 SQL 查询条件 + */ + private final String sqlTemplate; + + /** + * 如果不满足 {@code sqlTemplate} 的条件,则使用此默认 SQL 表达式 + */ + private final String elseSql; + + /** + * 根据枚举代码查找对应的枚举值 + * + * @param code 枚举代码 + * @return 对应的枚举值,如果未找到则返回 null + */ + public static DataScopeType findCode(String code) { + if (StringUtils.isBlank(code)) { + return null; + } + for (DataScopeType type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java new file mode 100644 index 0000000..fec2579 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java @@ -0,0 +1,102 @@ +package org.dromara.common.mybatis.handler; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.reflection.MetaObject; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.satoken.utils.LoginHelper; + +import java.util.Date; + +/** + * MP注入处理器 + * + * @author Lion Li + * @date 2021/4/25 + */ +@Slf4j +public class InjectionMetaObjectHandler implements MetaObjectHandler { + + /** + * 插入填充方法,用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息 + * + * @param metaObject 元对象,用于获取原始对象并进行填充 + */ + @Override + public void insertFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { + // 获取当前时间作为创建时间和更新时间,如果创建时间不为空,则使用创建时间,否则使用当前时间 + Date current = ObjectUtils.notNull(baseEntity.getCreateTime(), new Date()); + baseEntity.setCreateTime(current); + baseEntity.setUpdateTime(current); + + // 如果创建人为空,则填充当前登录用户的信息 + if (ObjectUtil.isNull(baseEntity.getCreateBy())) { + LoginUser loginUser = getLoginUser(); + if (ObjectUtil.isNotNull(loginUser)) { + Long userId = loginUser.getUserId(); + // 填充创建人、更新人和创建部门信息 + baseEntity.setCreateBy(userId); + baseEntity.setUpdateBy(userId); + baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId())); + } + } + } else { + Date date = new Date(); + this.strictInsertFill(metaObject, "createTime", Date.class, date); + this.strictInsertFill(metaObject, "updateTime", Date.class, date); + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + + /** + * 更新填充方法,用于在更新数据时自动填充实体对象中的更新时间和更新人信息 + * + * @param metaObject 元对象,用于获取原始对象并进行填充 + */ + @Override + public void updateFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { + // 获取当前时间作为更新时间,无论原始对象中的更新时间是否为空都填充 + Date current = new Date(); + baseEntity.setUpdateTime(current); + + // 获取当前登录用户的ID,并填充更新人信息 + Long userId = LoginHelper.getUserId(); + if (ObjectUtil.isNotNull(userId)) { + baseEntity.setUpdateBy(userId); + } + } else { + this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + + /** + * 获取当前登录用户信息 + * + * @return 当前登录用户的信息,如果用户未登录则返回 null + */ + private LoginUser getLoginUser() { + LoginUser loginUser; + try { + loginUser = LoginHelper.getLoginUser(); + } catch (Exception e) { + log.warn("自动注入警告 => 用户未登录"); + return null; + } + return loginUser; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java new file mode 100644 index 0000000..d802bf8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java @@ -0,0 +1,48 @@ +package org.dromara.common.mybatis.handler; + +import io.swagger.v3.oas.annotations.Hidden; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.mybatis.spring.MyBatisSystemException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * Mybatis异常处理器 + * + * @author Lion Li + */ +@Slf4j +@Hidden +@RestControllerAdvice +public class MybatisExceptionHandler { + + /** + * 主键或UNIQUE索引,数据重复异常 + */ + @ExceptionHandler(DuplicateKeyException.class) + public R handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',数据库中已存在记录'{}'", requestURI, e.getMessage()); + return R.fail("数据库中已存在该记录,请联系管理员确认"); + } + + /** + * Mybatis系统异常 通用处理 + */ + @ExceptionHandler(MyBatisSystemException.class) + public R handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + String message = e.getMessage(); + if (StringUtils.contains("CannotFindDataSourceException", message)) { + log.error("请求地址'{}', 未找到数据源", requestURI); + return R.fail("未找到数据源,请联系管理员确认"); + } + log.error("请求地址'{}', Mybatis系统异常", requestURI, e); + return R.fail(message); + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java new file mode 100644 index 0000000..a354707 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java @@ -0,0 +1,332 @@ +package org.dromara.common.mybatis.handler; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.apache.ibatis.io.Resources; +import org.dromara.common.core.domain.dto.RoleDTO; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.enums.DataScopeType; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.expression.*; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.ClassUtils; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +/** + * 数据权限过滤 + * + * @author Lion Li + * @version 3.5.0 + */ +@Slf4j +public class PlusDataPermissionHandler { + + /** + * 类名称与注解的映射关系缓存(由于aop无法拦截mybatis接口类上的注解 只能通过启动预扫描的方式进行) + */ + private final Map dataPermissionCacheMap = new ConcurrentHashMap<>(); + + /** + * spel 解析器 + */ + private final ExpressionParser parser = new SpelExpressionParser(); + private final ParserContext parserContext = new TemplateParserContext(); + /** + * bean解析器 用于处理 spel 表达式中对 bean 的调用 + */ + private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); + + /** + * 构造方法,扫描指定包下的 Mapper 类并初始化缓存 + * + * @param mapperPackage Mapper 类所在的包路径 + */ + public PlusDataPermissionHandler(String mapperPackage) { + scanMapperClasses(mapperPackage); + } + + /** + * 获取数据过滤条件的 SQL 片段 + * + * @param where 原始的查询条件表达式 + * @param mappedStatementId Mapper 方法的 ID + * @param isSelect 是否为查询语句 + * @return 数据过滤条件的 SQL 片段 + */ + public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { + try { + // 获取数据权限配置 + DataPermission dataPermission = getDataPermission(mappedStatementId); + // 获取当前登录用户信息 + LoginUser currentUser = DataPermissionHelper.getVariable("user"); + if (ObjectUtil.isNull(currentUser)) { + currentUser = LoginHelper.getLoginUser(); + DataPermissionHelper.setVariable("user", currentUser); + } + // 如果是超级管理员或租户管理员,则不过滤数据 + if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { + return where; + } + // 构造数据过滤条件的 SQL 片段 + String dataFilterSql = buildDataFilter(dataPermission, isSelect); + if (StringUtils.isBlank(dataFilterSql)) { + return where; + } + Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); + // 数据权限使用单独的括号 防止与其他条件冲突 + ParenthesedExpressionList parenthesis = new ParenthesedExpressionList<>(expression); + if (ObjectUtil.isNotNull(where)) { + return new AndExpression(where, parenthesis); + } else { + return parenthesis; + } + } catch (JSQLParserException e) { + throw new ServiceException("数据权限解析异常 => " + e.getMessage()); + } finally { + DataPermissionHelper.removePermission(); + } + } + + /** + * 构建数据过滤条件的 SQL 语句 + * + * @param dataPermission 数据权限注解 + * @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式 + * @return 构建的数据过滤条件的 SQL 语句 + * @throws ServiceException 如果角色的数据范围异常或者 key 与 value 的长度不匹配,则抛出 ServiceException 异常 + */ + private String buildDataFilter(DataPermission dataPermission, boolean isSelect) { + // 更新或删除需满足所有条件 + String joinStr = isSelect ? " OR " : " AND "; + if (StringUtils.isNotBlank(dataPermission.joinStr())) { + joinStr = " " + dataPermission.joinStr() + " "; + } + LoginUser user = DataPermissionHelper.getVariable("user"); + Object defaultValue = "-1"; + NullSafeStandardEvaluationContext context = new NullSafeStandardEvaluationContext(defaultValue); + context.addPropertyAccessor(new NullSafePropertyAccessor(context.getPropertyAccessors().get(0), defaultValue)); + context.setBeanResolver(beanResolver); + DataPermissionHelper.getContext().forEach(context::setVariable); + Set conditions = new HashSet<>(); + // 优先设置变量 + List keys = new ArrayList<>(); + Map ignoreMap = new HashMap<>(); + for (DataColumn dataColumn : dataPermission.value()) { + if (dataColumn.key().length != dataColumn.value().length) { + throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); + } + // 包含权限标识符 这直接跳过 + if (StringUtils.isNotBlank(dataColumn.permission()) && + CollUtil.contains(user.getMenuPermission(), dataColumn.permission()) + ) { + ignoreMap.put(dataColumn, Boolean.TRUE); + continue; + } + // 设置注解变量 key 为表达式变量 value 为变量值 + for (int i = 0; i < dataColumn.key().length; i++) { + context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); + } + keys.addAll(Arrays.stream(dataColumn.key()).map(key -> "#" + key).toList()); + } + + for (RoleDTO role : user.getRoles()) { + user.setRoleId(role.getRoleId()); + // 获取角色权限泛型 + DataScopeType type = DataScopeType.findCode(role.getDataScope()); + if (ObjectUtil.isNull(type)) { + throw new ServiceException("角色数据范围异常 => " + role.getDataScope()); + } + // 全部数据权限直接返回 + if (type == DataScopeType.ALL) { + return StringUtils.EMPTY; + } + boolean isSuccess = false; + for (DataColumn dataColumn : dataPermission.value()) { + // 包含权限标识符 这直接跳过 + if (ignoreMap.containsKey(dataColumn)) { + // 修复多角色与权限标识符共用问题 https://gitee.com/dromara/RuoYi-Vue-Plus/issues/IB4CS4 + conditions.add(joinStr + " 1 = 1 "); + isSuccess = true; + continue; + } + // 不包含 key 变量 则不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), keys.toArray(String[]::new))) { + continue; + } + // 当前注解不满足模板 不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), dataColumn.key())) { + continue; + } + // 忽略数据权限 防止spel表达式内有其他sql查询导致死循环调用 + String sql = DataPermissionHelper.ignore(() -> + parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class) + ); + // 解析sql模板并填充 + conditions.add(joinStr + sql); + isSuccess = true; + } + // 未处理成功则填充兜底方案 + if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) { + conditions.add(joinStr + type.getElseSql()); + } + } + + if (CollUtil.isNotEmpty(conditions)) { + String sql = StreamUtils.join(conditions, Function.identity(), ""); + return sql.substring(joinStr.length()); + } + return StringUtils.EMPTY; + } + + /** + * 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类 + * + * @param mapperPackage Mapper 类所在的包路径 + */ + private void scanMapperClasses(String mapperPackage) { + // 创建资源解析器和元数据读取工厂 + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); + // 将 Mapper 包路径按分隔符拆分为数组 + String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; + try { + for (String packagePattern : packagePatternArray) { + // 将包路径转换为资源路径 + String path = ClassUtils.convertClassNameToResourcePath(packagePattern); + // 获取指定路径下的所有 .class 文件资源 + Resource[] resources = resolver.getResources(classpath + path + "/*.class"); + for (Resource resource : resources) { + // 获取资源的类元数据 + ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); + // 获取资源对应的类对象 + Class clazz = Resources.classForName(classMetadata.getClassName()); + // 查找类中的特定注解 + if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { + DataPermission dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); + dataPermissionCacheMap.put(clazz.getName(), dataPermission); + } + } + } + } catch (Exception e) { + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); + } + } + + /** + * 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象 + * + * @param mapperId 映射语句 ID + * @return DataPermission 注解对象,如果不存在则返回 null + */ + public DataPermission getDataPermission(String mapperId) { + // 检查上下文中是否包含映射语句 ID 对应的 DataPermission 注解对象 + if (DataPermissionHelper.getPermission() != null) { + return DataPermissionHelper.getPermission(); + } + // 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找 + String clazzName = mapperId.substring(0, mapperId.lastIndexOf(".")); + if (dataPermissionCacheMap.containsKey(clazzName)) { + return dataPermissionCacheMap.get(clazzName); + } + return null; + } + + /** + * 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象 + * + * @param mapperId 映射语句 ID + * @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true + */ + public boolean invalid(String mapperId) { + return getDataPermission(mapperId) == null; + } + + /** + * 对所有null变量找不到的变量返回默认值 + */ + @AllArgsConstructor + private static class NullSafeStandardEvaluationContext extends StandardEvaluationContext { + + private final Object defaultValue; + + @Override + public Object lookupVariable(String name) { + Object obj = super.lookupVariable(name); + // 如果读取到的值是 null,则返回默认值 + if (obj == null) { + return defaultValue; + } + return obj; + } + + } + + /** + * 对所有null变量找不到的变量返回默认值 委托模式 将不需要处理的方法委托给原处理器 + */ + @AllArgsConstructor + private static class NullSafePropertyAccessor implements PropertyAccessor { + + private final PropertyAccessor delegate; + private final Object defaultValue; + + @Override + public Class[] getSpecificTargetClasses() { + return delegate.getSpecificTargetClasses(); + } + + @Override + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return delegate.canRead(context, target, name); + } + + @Override + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + TypedValue value = delegate.read(context, target, name); + // 如果读取到的值是 null,则返回默认值 + if (value.getValue() == null) { + return new TypedValue(defaultValue); + } + return value; + } + + @Override + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return delegate.canWrite(context, target, name); + } + + @Override + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + delegate.write(context, target, name, newValue); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java new file mode 100644 index 0000000..60ca20b --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java @@ -0,0 +1,27 @@ +package org.dromara.common.mybatis.handler; + +import cn.hutool.core.convert.Convert; +import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import org.apache.ibatis.session.Configuration; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; + +/** + * 修改表信息初始化方式 + * 目前用于全局修改是否使用逻辑删除 + * + * @author Lion Li + */ +public class PlusPostInitTableInfoHandler implements PostInitTableInfoHandler { + + @Override + public void postTableInfo(TableInfo tableInfo, Configuration configuration) { + String flag = SpringUtils.getProperty("mybatis-plus.enableLogicDelete", "true"); + // 只有关闭时 统一设置false 为true时mp自动判断不处理 + if (!Convert.toBool(flag)) { + ReflectUtils.setFieldValue(tableInfo, "withLogicDelete", false); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java new file mode 100644 index 0000000..cd43c68 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java @@ -0,0 +1,81 @@ +package org.dromara.common.mybatis.helper; + +import cn.hutool.core.convert.Convert; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.mybatis.enums.DataBaseType; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * 数据库助手 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DataBaseHelper { + + private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); + + /** + * 获取当前数据库类型 + */ + public static DataBaseType getDataBaseType() { + DataSource dataSource = DS.determineDataSource(); + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + return DataBaseType.find(databaseProductName); + } catch (SQLException e) { + throw new ServiceException(e.getMessage()); + } + } + + public static boolean isMySql() { + return DataBaseType.MY_SQL == getDataBaseType(); + } + + public static boolean isOracle() { + return DataBaseType.ORACLE == getDataBaseType(); + } + + public static boolean isPostgerSql() { + return DataBaseType.POSTGRE_SQL == getDataBaseType(); + } + + public static boolean isSqlServer() { + return DataBaseType.SQL_SERVER == getDataBaseType(); + } + + public static String findInSet(Object var1, String var2) { + DataBaseType dataBasyType = getDataBaseType(); + String var = Convert.toStr(var1); + if (dataBasyType == DataBaseType.SQL_SERVER) { + // charindex(',100,' , ',0,100,101,') <> 0 + return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2); + } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { + // (select strpos(',0,100,101,' , ',100,')) <> 0 + return "(select strpos(','||%s||',' , ',%s,')) <> 0".formatted(var2, var); + } else if (dataBasyType == DataBaseType.ORACLE) { + // instr(',0,100,101,' , ',100,') <> 0 + return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var); + } + // find_in_set(100 , '0,100,101') + return "find_in_set('%s' , %s) <> 0".formatted(var, var2); + } + + /** + * 获取当前加载的数据库名 + */ + public static List getDataSourceNameList() { + return new ArrayList<>(DS.getDataSources().keySet()); + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java new file mode 100644 index 0000000..f03d74e --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java @@ -0,0 +1,176 @@ +package org.dromara.common.mybatis.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.mybatis.annotation.DataPermission; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import java.util.function.Supplier; + +/** + * 数据权限助手 + * + * @author Lion Li + * @version 3.5.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings("unchecked cast") +public class DataPermissionHelper { + + private static final String DATA_PERMISSION_KEY = "data:permission"; + + private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new); + + private static final ThreadLocal PERMISSION_CACHE = new ThreadLocal<>(); + + /** + * 获取当前执行mapper权限注解 + * + * @return 返回当前执行mapper权限注解 + */ + public static DataPermission getPermission() { + return PERMISSION_CACHE.get(); + } + + /** + * 设置当前执行mapper权限注解 + * + * @param dataPermission 数据权限注解 + */ + public static void setPermission(DataPermission dataPermission) { + PERMISSION_CACHE.set(dataPermission); + } + + /** + * 删除当前执行mapper权限注解 + */ + public static void removePermission() { + PERMISSION_CACHE.remove(); + } + + /** + * 从上下文中获取指定键的变量值,并将其转换为指定的类型 + * + * @param key 变量的键 + * @param 变量值的类型 + * @return 指定键的变量值,如果不存在则返回 null + */ + public static T getVariable(String key) { + Map context = getContext(); + return (T) context.get(key); + } + + /** + * 向上下文中设置指定键的变量值 + * + * @param key 要设置的变量的键 + * @param value 要设置的变量值 + */ + public static void setVariable(String key, Object value) { + Map context = getContext(); + context.put(key, value); + } + + /** + * 获取数据权限上下文 + * + * @return 存储在SaStorage中的Map对象,用于存储数据权限相关的上下文信息 + * @throws NullPointerException 如果数据权限上下文类型异常,则抛出NullPointerException + */ + public static Map getContext() { + SaStorage saStorage = SaHolder.getStorage(); + Object attribute = saStorage.get(DATA_PERMISSION_KEY); + if (ObjectUtil.isNull(attribute)) { + saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); + attribute = saStorage.get(DATA_PERMISSION_KEY); + } + if (attribute instanceof Map map) { + return map; + } + throw new NullPointerException("data permission context type exception"); + } + + private static IgnoreStrategy getIgnoreStrategy() { + Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL")); + if (ignoreStrategyLocal instanceof ThreadLocal IGNORE_STRATEGY_LOCAL) { + if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) { + return ignoreStrategy; + } + } + return null; + } + + /** + * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) + */ + public static void enableIgnore() { + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNull(ignoreStrategy)) { + InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); + } else { + ignoreStrategy.setDataPermission(true); + } + Stack reentrantStack = REENTRANT_IGNORE.get(); + reentrantStack.push(reentrantStack.size() + 1); + } + + /** + * 关闭忽略数据权限 + */ + public static void disableIgnore() { + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNotNull(ignoreStrategy)) { + boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) + && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack()) + && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) + && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine()) + && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); + Stack reentrantStack = REENTRANT_IGNORE.get(); + boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1; + if (noOtherIgnoreStrategy && empty) { + InterceptorIgnoreHelper.clearIgnoreStrategy(); + } else if (empty) { + ignoreStrategy.setDataPermission(false); + } + + } + } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static void ignore(Runnable handle) { + enableIgnore(); + try { + handle.run(); + } finally { + disableIgnore(); + } + } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static T ignore(Supplier handle) { + enableIgnore(); + try { + return handle.get(); + } finally { + disableIgnore(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java new file mode 100644 index 0000000..85a4d0a --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java @@ -0,0 +1,181 @@ +package org.dromara.common.mybatis.interceptor; + +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.update.Update; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.dromara.common.mybatis.handler.PlusDataPermissionHandler; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +/** + * 数据权限拦截器 + * + * @author Lion Li + * @version 3.5.0 + */ +@Slf4j +public class PlusDataPermissionInterceptor extends BaseMultiTableInnerInterceptor implements InnerInterceptor { + + private final PlusDataPermissionHandler dataPermissionHandler; + + /** + * 构造函数,初始化 PlusDataPermissionHandler 实例 + * + * @param mapperPackage 扫描的映射器包 + */ + public PlusDataPermissionInterceptor(String mapperPackage) { + this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage); + } + + /** + * 在执行查询之前,检查并处理数据权限相关逻辑 + * + * @param executor MyBatis 执行器对象 + * @param ms 映射语句对象 + * @param parameter 方法参数 + * @param rowBounds 分页对象 + * @param resultHandler 结果处理器 + * @param boundSql 绑定的 SQL 对象 + * @throws SQLException 如果发生 SQL 异常 + */ + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { + // 检查是否需要忽略数据权限处理 + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + // 检查是否缺少有效的数据权限注解 + if (dataPermissionHandler.invalid(ms.getId())) { + return; + } + // 解析 sql 分配对应方法 + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + mpBs.sql(parserSingle(mpBs.sql(), ms.getId())); + } + + /** + * 在准备 SQL 语句之前,检查并处理更新和删除操作的数据权限相关逻辑 + * + * @param sh MyBatis StatementHandler 对象 + * @param connection 数据库连接对象 + * @param transactionTimeout 事务超时时间 + */ + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + // 获取 SQL 命令类型(增、删、改、查) + SqlCommandType sct = ms.getSqlCommandType(); + + // 只处理更新和删除操作的 SQL 语句 + if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + // 检查是否缺少有效的数据权限注解 + if (dataPermissionHandler.invalid(ms.getId())) { + return; + } + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + mpBs.sql(parserMulti(mpBs.sql(), ms.getId())); + } + } + + /** + * 处理 SELECT 查询语句中的 WHERE 条件 + * + * @param select SELECT 查询对象 + * @param index 查询语句的索引 + * @param sql 查询语句 + * @param obj WHERE 条件参数 + */ + @Override + protected void processSelect(Select select, int index, String sql, Object obj) { + if (select instanceof PlainSelect) { + this.setWhere((PlainSelect) select, (String) obj); + } else if (select instanceof SetOperationList setOperationList) { + List + + where t.table_id = #{tableId} order by c.sort + + + + + + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm new file mode 100644 index 0000000..511d37c --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm @@ -0,0 +1,50 @@ +package ${packageName}.domain.bo; + +import ${packageName}.domain.${ClassName}; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +#foreach ($import in $importList) +import ${import}; +#end + +/** + * ${functionName}业务对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false) +public class ${ClassName}Bo extends BaseEntity { + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit)) + /** + * $column.columnComment + */ +#if($column.insert && $column.edit) +#set($Group="AddGroup.class, EditGroup.class") +#elseif($column.insert) +#set($Group="AddGroup.class") +#elseif($column.edit) +#set($Group="EditGroup.class") +#end +#if($column.required) +#if($column.javaType == 'String') + @NotBlank(message = "$column.columnComment不能为空", groups = { $Group }) +#else + @NotNull(message = "$column.columnComment不能为空", groups = { $Group }) +#end +#end + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm new file mode 100644 index 0000000..6438971 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm @@ -0,0 +1,115 @@ +package ${packageName}.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import ${packageName}.domain.vo.${ClassName}Vo; +import ${packageName}.domain.bo.${ClassName}Bo; +import ${packageName}.service.I${ClassName}Service; +#if($table.crud) +import org.dromara.common.mybatis.core.page.TableDataInfo; +#elseif($table.tree) +#end + +/** + * ${functionName} + * + * @author ${author} + * @date ${datetime} + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/${moduleName}/${businessName}") +public class ${ClassName}Controller extends BaseController { + + private final I${ClassName}Service ${className}Service; + + /** + * 查询${functionName}列表 + */ + @SaCheckPermission("${permissionPrefix}:list") + @GetMapping("/list") +#if($table.crud) + public TableDataInfo<${ClassName}Vo> list(${ClassName}Bo bo, PageQuery pageQuery) { + return ${className}Service.queryPageList(bo, pageQuery); + } +#elseif($table.tree) + public R> list(${ClassName}Bo bo) { + List<${ClassName}Vo> list = ${className}Service.queryList(bo); + return R.ok(list); + } +#end + + /** + * 导出${functionName}列表 + */ + @SaCheckPermission("${permissionPrefix}:export") + @Log(title = "${functionName}", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(${ClassName}Bo bo, HttpServletResponse response) { + List<${ClassName}Vo> list = ${className}Service.queryList(bo); + ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response); + } + + /** + * 获取${functionName}详细信息 + * + * @param ${pkColumn.javaField} 主键 + */ + @SaCheckPermission("${permissionPrefix}:query") + @GetMapping("/{${pkColumn.javaField}}") + public R<${ClassName}Vo> getInfo(@NotNull(message = "主键不能为空") + @PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) { + return R.ok(${className}Service.queryById(${pkColumn.javaField})); + } + + /** + * 新增${functionName} + */ + @SaCheckPermission("${permissionPrefix}:add") + @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) { + return toAjax(${className}Service.insertByBo(bo)); + } + + /** + * 修改${functionName} + */ + @SaCheckPermission("${permissionPrefix}:edit") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) { + return toAjax(${className}Service.updateByBo(bo)); + } + + /** + * 删除${functionName} + * + * @param ${pkColumn.javaField}s 主键串 + */ + @SaCheckPermission("${permissionPrefix}:remove") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @DeleteMapping("/{${pkColumn.javaField}s}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) { + return toAjax(${className}Service.deleteWithValidByIds(List.of(${pkColumn.javaField}s), true)); + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm new file mode 100644 index 0000000..205fb73 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm @@ -0,0 +1,60 @@ +package ${packageName}.domain; + +#foreach ($column in $columns) +#if($column.javaField=='tenantId') +#set($IsTenant=1) +#end +#end +#if($IsTenant==1) +import org.dromara.common.tenant.core.TenantEntity; +#else +import org.dromara.common.mybatis.core.domain.BaseEntity; +#end +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +#foreach ($import in $importList) +import ${import}; +#end + +import java.io.Serial; + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($IsTenant==1) +#set($Entity="TenantEntity") +#else +#set($Entity="BaseEntity") +#end +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("${tableName}") +public class ${ClassName} extends ${Entity} { + + @Serial + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) + /** + * $column.columnComment + */ +#if($column.javaField=='delFlag') + @TableLogic +#end +#if($column.javaField=='version') + @Version +#end +#if($column.isPk==1) + @TableId(value = "$column.columnName") +#end + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm new file mode 100644 index 0000000..0922401 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm @@ -0,0 +1,15 @@ +package ${packageName}.mapper; + +import ${packageName}.domain.${ClassName}; +import ${packageName}.domain.vo.${ClassName}Vo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * ${functionName}Mapper接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> { + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm new file mode 100644 index 0000000..4db9030 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm @@ -0,0 +1,72 @@ +package ${packageName}.service; + +import ${packageName}.domain.vo.${ClassName}Vo; +import ${packageName}.domain.bo.${ClassName}Bo; +#if($table.crud) +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +#end + +import java.util.Collection; +import java.util.List; + +/** + * ${functionName}Service接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Service { + + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} 主键 + * @return ${functionName} + */ + ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}); + +#if($table.crud) + /** + * 分页查询${functionName}列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return ${functionName}分页列表 + */ + TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery); +#end + + /** + * 查询符合条件的${functionName}列表 + * + * @param bo 查询条件 + * @return ${functionName}列表 + */ + List<${ClassName}Vo> queryList(${ClassName}Bo bo); + + /** + * 新增${functionName} + * + * @param bo ${functionName} + * @return 是否新增成功 + */ + Boolean insertByBo(${ClassName}Bo bo); + + /** + * 修改${functionName} + * + * @param bo ${functionName} + * @return 是否修改成功 + */ + Boolean updateByBo(${ClassName}Bo bo); + + /** + * 校验并批量删除${functionName}信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm new file mode 100644 index 0000000..48cc8b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -0,0 +1,158 @@ +package ${packageName}.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +#if($table.crud) +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +#end +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ${packageName}.domain.bo.${ClassName}Bo; +import ${packageName}.domain.vo.${ClassName}Vo; +import ${packageName}.domain.${ClassName}; +import ${packageName}.mapper.${ClassName}Mapper; +import ${packageName}.service.I${ClassName}Service; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * ${functionName}Service业务层处理 + * + * @author ${author} + * @date ${datetime} + */ +@RequiredArgsConstructor +@Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service { + + private final ${ClassName}Mapper baseMapper; + + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} 主键 + * @return ${functionName} + */ + @Override + public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){ + return baseMapper.selectVoById(${pkColumn.javaField}); + } + +#if($table.crud) + /** + * 分页查询${functionName}列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return ${functionName}分页列表 + */ + @Override + public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery) { + LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo); + Page<${ClassName}Vo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } +#end + + /** + * 查询符合条件的${functionName}列表 + * + * @param bo 查询条件 + * @return ${functionName}列表 + */ + @Override + public List<${ClassName}Vo> queryList(${ClassName}Bo bo) { + LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery(); +#foreach($column in $columns) +#if($column.query) +#set($queryType=$column.queryType) +#set($javaField=$column.javaField) +#set($javaType=$column.javaType) +#set($columnName=$column.columnName) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($mpMethod=$column.queryType.toLowerCase()) +#if($queryType != 'BETWEEN') +#if($javaType == 'String') +#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())') +#else +#set($condition='bo.get'+$AttrName+'() != null') +#end + lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName()); +#else + lqw.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null, + ${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName")); +#end +#end +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#if($column.isPk==1) + lqw.orderByAsc(${ClassName}::get$AttrName); +#end +#end + return lqw; + } + + /** + * 新增${functionName} + * + * @param bo ${functionName} + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(${ClassName}Bo bo) { + ${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; +#set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)}) + if (flag) { + bo.set$pk(add.get$pk()); + } + return flag; + } + + /** + * 修改${functionName} + * + * @param bo ${functionName} + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(${ClassName}Bo bo) { + ${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(${ClassName} entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除${functionName}信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm new file mode 100644 index 0000000..5591f97 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm @@ -0,0 +1,66 @@ +package ${packageName}.domain.vo; + +#foreach ($import in $importList) +import ${import}; +#end +import ${packageName}.domain.${ClassName}; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * ${functionName}视图对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ${ClassName}.class) +public class ${ClassName}Vo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if($column.list) + /** + * $column.columnComment + */ +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if(${column.dictType} && ${column.dictType} != '') + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "${column.dictType}") +#elseif($parentheseIndex != -1) + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "$column.readConverterExp()") +#else + @ExcelProperty(value = "${comment}") +#end + private $column.javaType $column.javaField; + +#if($column.htmlType == "imageUpload") + /** + * ${column.columnComment}Url + */ + @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}") + private String ${column.javaField}Url; +#end +#end +#end + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm new file mode 100644 index 0000000..f6638be --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate, null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate, null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm new file mode 100644 index 0000000..0923392 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm @@ -0,0 +1,20 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, now(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, now(), null, null, ''); + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm new file mode 100644 index 0000000..01824c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate(), null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm new file mode 100644 index 0000000..bdf166e --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, getdate(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, getdate(), null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm new file mode 100644 index 0000000..3aa4a5f --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm @@ -0,0 +1,63 @@ +import request from '@/utils/request'; +import { AxiosPromise } from 'axios'; +import { ${BusinessName}VO, ${BusinessName}Form, ${BusinessName}Query } from '@/api/${moduleName}/${businessName}/types'; + +/** + * 查询${functionName}列表 + * @param query + * @returns {*} + */ + +export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> => { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'get', + params: query + }); +}; + +/** + * 查询${functionName}详细 + * @param ${pkColumn.javaField} + */ +export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'get' + }); +}; + +/** + * 新增${functionName} + * @param data + */ +export const add${BusinessName} = (data: ${BusinessName}Form) => { + return request({ + url: '/${moduleName}/${businessName}', + method: 'post', + data: data + }); +}; + +/** + * 修改${functionName} + * @param data + */ +export const update${BusinessName} = (data: ${BusinessName}Form) => { + return request({ + url: '/${moduleName}/${businessName}', + method: 'put', + data: data + }); +}; + +/** + * 删除${functionName} + * @param ${pkColumn.javaField} + */ +export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array) => { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'delete' + }); +}; diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm new file mode 100644 index 0000000..35a468e --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm @@ -0,0 +1,64 @@ +export interface ${BusinessName}VO { +#foreach ($column in $columns) +#if($column.list) + /** + * $column.columnComment + */ + $column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#if($column.htmlType == "imageUpload") + /** + * ${column.columnComment}Url + */ + ${column.javaField}Url: string; +#end +#end +#end +#if ($table.tree) + /** + * 子对象 + */ + children: ${BusinessName}VO[]; +#end +} + +export interface ${BusinessName}Form extends BaseEntity { +#foreach ($column in $columns) +#if($column.insert || $column.edit) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end +} + +export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{ + +#foreach ($column in $columns) +#if($column.query) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end + /** + * 日期范围参数 + */ + params?: any; +} + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm new file mode 100644 index 0000000..caf3472 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -0,0 +1,498 @@ + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm new file mode 100644 index 0000000..a92d19a --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm @@ -0,0 +1,459 @@ + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm new file mode 100644 index 0000000..9fb48d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-job/pom.xml b/ruoyi-modules/ruoyi-job/pom.xml new file mode 100644 index 0000000..2431a1c --- /dev/null +++ b/ruoyi-modules/ruoyi-job/pom.xml @@ -0,0 +1,34 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + jar + ruoyi-job + + + 任务调度 + + + + + + + org.dromara + ruoyi-common-json + + + + org.dromara + ruoyi-common-job + + + + + + diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java new file mode 100644 index 0000000..2f118b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java @@ -0,0 +1 @@ +package org.dromara.job; diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java new file mode 100644 index 0000000..5bea9da --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java @@ -0,0 +1,23 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.client.model.ExecuteResult; +import com.aizuda.snailjob.common.core.util.JsonUtil; +import com.aizuda.snailjob.common.log.SnailJobLog; +import org.springframework.stereotype.Component; + +/** + * @author opensnail + * @date 2024-05-17 + */ +@Component +@JobExecutor(name = "testJobExecutor") +public class TestAnnoJobExecutor { + + public ExecuteResult jobExecute(JobArgs jobArgs) { + SnailJobLog.LOCAL.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); + SnailJobLog.REMOTE.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); + return ExecuteResult.success("测试成功"); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java new file mode 100644 index 0000000..6f7c21f --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java @@ -0,0 +1,19 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.client.job.core.executor.AbstractJobExecutor; +import com.aizuda.snailjob.client.model.ExecuteResult; +import org.springframework.stereotype.Component; + +/** + * @author opensnail + * @date 2024-05-17 + */ +@Component +public class TestClassJobExecutor extends AbstractJobExecutor { + + @Override + protected ExecuteResult doJobExecute(JobArgs jobArgs) { + return ExecuteResult.success("TestJobExecutor测试成功"); + } +} diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml new file mode 100644 index 0000000..d1bb30e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/pom.xml @@ -0,0 +1,216 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + + ruoyi-system + + + system系统模块 + + + + + + + com.alibaba + fastjson + 2.0.32 + + + + + org.docx4j + docx4j-core + 11.5.3 + + + + org.docx4j + docx4j-JAXB-ReferenceImpl + 11.5.3 + + + + org.docx4j + docx4j-export-fo + 11.5.3 + + + org.apache.pdfbox + pdfbox + + + org.apache.pdfbox + fontbox + + + + + + org.apache.pdfbox + pdfbox + 2.0.29 + + + + org.apache.pdfbox + fontbox + 2.0.29 + + + + + com.deepoove + poi-tl + 1.12.2 + + + + + + com.itextpdf + itext-asian + 5.2.0 + + + + com.itextpdf + itextpdf + 5.5.13.3 + + + + com.google.zxing + core + 3.5.2 + + + com.google.zxing + javase + 3.5.2 + + + + + org.dromara + ruoyi-common-core + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-mybatis + + + + org.dromara + ruoyi-common-translation + + + + + org.dromara + ruoyi-common-oss + + + + org.dromara + ruoyi-common-log + + + + + org.dromara + ruoyi-common-excel + + + + + org.dromara + ruoyi-common-sms + + + + org.dromara + ruoyi-common-tenant + + + + org.dromara + ruoyi-common-security + + + + org.dromara + ruoyi-common-web + + + + org.dromara + ruoyi-common-idempotent + + + + org.dromara + ruoyi-common-sensitive + + + + org.dromara + ruoyi-common-encrypt + + + + org.dromara + ruoyi-common-websocket + + + + org.dromara + ruoyi-common-sse + + + + org.dromara + ruoyi-common-jts + + + org.springframework + spring-test + + + + org.dromara + ruoyi-workflow + + + com.google.code.gson + gson + + + org.scala-lang + scala-library + 2.13.9 + compile + + + net.java.dev.jna + jna-platform + 5.15.0 + compile + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/DesignMapFileConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/DesignMapFileConstant.java new file mode 100644 index 0000000..14ed370 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/DesignMapFileConstant.java @@ -0,0 +1,28 @@ +package org.dromara.common.constant; + +import java.io.File; + +/** + * @author lilemy + * @date 2025/4/23 11:09 + */ +public interface DesignMapFileConstant { + + String DXF_BASE_PATH = "file" + File.separator + "resource" + File.separator + "design"; + + /** + * WGS 84 + */ + String EPSG4326 = "4326"; + + String EPSG4524 = "4524"; + + String DXFFileSuffix = "dxf"; + + String JSONFileSuffix = "json"; + + static String getDxfProjectPath(Long projectId) { + return DXF_BASE_PATH + File.separator + projectId; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/GeoJsonConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/GeoJsonConstant.java new file mode 100644 index 0000000..7f7e74e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/GeoJsonConstant.java @@ -0,0 +1,15 @@ +package org.dromara.common.constant; + +/** + * @author lilemy + * @date 2025/4/24 17:44 + */ +public interface GeoJsonConstant { + + String POINT = "Point"; + + String LINE = "LineString"; + + String POLYGON = "Polygon"; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/MinioPathConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/MinioPathConstant.java new file mode 100644 index 0000000..431ae5b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/MinioPathConstant.java @@ -0,0 +1,14 @@ +package org.dromara.common.constant; + +/** + * @Author: Cory·铁憨憨 + * @Date: 2025-07-03-14:12 + * @Description: minio存储路线 + */ + +public interface MinioPathConstant { + // 联系单 + String ContactNotice = "contactNotice"; + // 联系单模板 + String ContactNoticeTemplate = "contactNotice/template"; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/businessConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/businessConstant.java new file mode 100644 index 0000000..3086e68 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/constant/businessConstant.java @@ -0,0 +1,9 @@ +package org.dromara.common.constant; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:38 + * @Version 1.0 + */public interface businessConstant { + String REDIS_BAIDU_KEY = "baidu:access_token"; //百度token存储在redis中的key +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/enums/DocumentStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/enums/DocumentStatusEnum.java new file mode 100644 index 0000000..f97d412 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/enums/DocumentStatusEnum.java @@ -0,0 +1,24 @@ +package org.dromara.common.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/14 14:03 + */ +@Getter +public enum DocumentStatusEnum { + + NORMAL("正常", "0"), + DELETE("删除", "1"); + + private final String text; + + private final String value; + + DocumentStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/enums/DocumentTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/enums/DocumentTypeEnum.java new file mode 100644 index 0000000..0ead838 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/enums/DocumentTypeEnum.java @@ -0,0 +1,25 @@ +package org.dromara.common.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/14 10:42 + */ +@Getter +public enum DocumentTypeEnum { + + FOLDER("文件夹", "1"), + FILE("文件", "2"), + PICTURE("图片", "3"); + + private final String text; + + private final String value; + + DocumentTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/BigDecimalUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/BigDecimalUtil.java new file mode 100644 index 0000000..581f900 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/BigDecimalUtil.java @@ -0,0 +1,26 @@ +package org.dromara.common.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * @author lilemy + * @date 2025/5/27 9:16 + */ +public class BigDecimalUtil { + + /** + * 计算百分比 + * + * @param dividend 被除数 + * @param divisor 除数 + * @return 百分比(保留2位小数)如 12.34% + */ + public static BigDecimal toPercentage(BigDecimal dividend, BigDecimal divisor) { + if (dividend == null || divisor == null || divisor.compareTo(BigDecimal.ZERO) == 0) { + return new BigDecimal(0); + } + return dividend.divide(divisor, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/DocumentUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/DocumentUtil.java new file mode 100644 index 0000000..6c5a078 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/DocumentUtil.java @@ -0,0 +1,100 @@ +package org.dromara.common.utils; + +import org.apache.poi.util.Units; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFRun; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * @author lilemy + * @date 2025/4/17 14:53 + */ +public class DocumentUtil { + + /** + * 在给定的 run 里插入图片,并按原始大小(或缩放后大小)设置宽高。 + * + * @param run 要插入图片的 XWPFRun + * @param imagePath 本地图片路径或 URL(这里示例用本地文件) + * @param document 当前文档对象 + * @param maxWidthPx 最大允许宽度(像素),如果原图更宽就按比例缩放;设置为 <=0 则不缩放 + */ + public static void insertImageDynamic(XWPFRun run, + String imagePath, + XWPFDocument document, + int maxWidthPx) throws Exception { + // 1. 先把图片读到 byte[] + byte[] imgBytes = Files.readAllBytes(Paths.get(imagePath)); + // 2. 用 ImageIO 读出宽高(像素) + BufferedImage img = ImageIO.read(new ByteArrayInputStream(imgBytes)); + int widthPx = img.getWidth(); + int heightPx = img.getHeight(); + // 3. 如果指定了最大宽度,而且原图更宽,则按比例缩放 + if (maxWidthPx > 0 && widthPx > maxWidthPx) { + double ratio = (double) maxWidthPx / widthPx; + widthPx = maxWidthPx; + heightPx = (int) (heightPx * ratio); + } + // 4. 把像素转换成 EMU + int widthEmu = Units.pixelToEMU(widthPx); + int heightEmu = Units.pixelToEMU(heightPx); + // 5. 插入图片 + String lower = imagePath.toLowerCase(); + int format = lower.endsWith(".png") ? XWPFDocument.PICTURE_TYPE_PNG + : lower.endsWith(".gif") ? XWPFDocument.PICTURE_TYPE_GIF + : lower.endsWith(".jpeg") ? XWPFDocument.PICTURE_TYPE_JPEG + : lower.endsWith(".jpg") ? XWPFDocument.PICTURE_TYPE_JPEG + : XWPFDocument.PICTURE_TYPE_PNG; // 默认当 PNG + try (InputStream picIn = new ByteArrayInputStream(imgBytes)) { + run.addPicture(picIn, format, imagePath, widthEmu, heightEmu); + } + } + + + /** + * 递归将 sourceDir 中的所有文件和子目录,按照相对于 rootDir 的路径写入 ZipOutputStream。 + * + * @param rootDir 源目录的根,用来计算相对路径 + * @param sourceDir 当前递归到的目录 + * @param zos ZIP 输出流 + */ + public static void zipDirectory(Path rootDir, Path sourceDir, ZipOutputStream zos) throws IOException { + // 遍历当前目录下的所有文件和文件夹 + try (DirectoryStream stream = Files.newDirectoryStream(sourceDir)) { + for (Path entry : stream) { + if (Files.isDirectory(entry)) { + // 如果是目录,递归 + zipDirectory(rootDir, entry, zos); + } else { + // 如果是文件,创建一个 ZipEntry,路径以 '/' 分隔 + Path relativePath = rootDir.relativize(entry); + String zipEntryName = relativePath.toString().replace(File.separatorChar, '/'); + ZipEntry zipEntry = new ZipEntry(zipEntryName); + zos.putNextEntry(zipEntry); + // 把文件内容写入 ZIP + try (InputStream is = Files.newInputStream(entry)) { + byte[] buffer = new byte[4096]; + int len; + while ((len = is.read(buffer)) != -1) { + zos.write(buffer, 0, len); + } + } + zos.closeEntry(); + } + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/Dxf2JsonUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/Dxf2JsonUtil.java new file mode 100644 index 0000000..bbcc840 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/Dxf2JsonUtil.java @@ -0,0 +1,97 @@ +package org.dromara.common.utils; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/23 10:42 + */ +@Slf4j +public class Dxf2JsonUtil { + + /** + * dxf转json + * + * @param exePath dxf2json.exe路径 + * @param inputDXFPath 输入dxf文件路径 + * @param outputJSONPath 输出json文件路径 + * @param sourceEPSG 源坐标系 + * @param targetEPSG 目标坐标系 + */ + public static void dxf2json(String exePath, String inputDXFPath, String outputJSONPath, String sourceEPSG, String targetEPSG) { + // 判断对应文件是否存在 + File exeFile = new File(exePath); + if (!exeFile.exists()) { + throw new ServiceException("转换程序不存在!"); + } + File inputDXFFile = new File(inputDXFPath); + if (!inputDXFFile.exists()) { + throw new ServiceException("待转换 dxf 文件不存在!"); + } + // 构造命令行参数 + List parameters = buildParameter(exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG); + // 执行命令行 + ProcessBuilder builder = new ProcessBuilder(parameters); + // 合并标准错误和输出 + builder.redirectErrorStream(true); + try { + Process process = builder.start(); + // 读取输出 + BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream(), "GBK") + ); + String line; + log.info("dxf 转 json 程序开始执行,程序路径:{},输入 dxf 路径:{},输出 json 文件路径:{},源坐标系:{},模板坐标系:{}", + exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG); + while ((line = reader.readLine()) != null) { + log.info("dxf 转 json 程序执行中:{}", line); + JSONObject jsonObject = JSONUtil.parseObj(line); + Integer code = jsonObject.get("code", Integer.class); + if (code != 0 && code != 200) { + throw new ServiceException("dxf 转 json 程序执行出错!"); + } + } + int exitCode = process.waitFor(); + log.info("dxf 转 json 程序执行完毕,程序退出码:{}", exitCode); + reader.close(); + } catch (IOException | InterruptedException e) { + log.error("执行 dxf 转 json 命令行时出错", e); + } + } + + /** + * 构造命令行参数 + * + * @param exePath dxf2json.exe路径 + * @param inputDXFPath 输入dxf文件路径 + * @param outputJSONPath 输出json文件路径 + * @param sourceEPSG 源坐标系 + * @param targetEPSG 目标坐标系 + * @return 命令行参数 + */ + public static List buildParameter(String exePath, + String inputDXFPath, + String outputJSONPath, + String sourceEPSG, + String targetEPSG) { + // 构造命令行 + return Arrays.asList( + exePath, + inputDXFPath, + outputJSONPath, + sourceEPSG, + targetEPSG + ); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/HttpClientConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/HttpClientConfig.java new file mode 100644 index 0000000..613b696 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/HttpClientConfig.java @@ -0,0 +1,24 @@ +package org.dromara.common.utils; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.net.http.HttpClient; +import java.time.Duration; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:16 + * @Version 1.0 + * + * HttpClient 设计为可重用、线程安全的组件,其内部维护了连接池等资源,适合在多个接口调用中共享使用,所以交给Spring Bean 管理 + */ +@Configuration +public class HttpClientConfig { + @Bean + public HttpClient httpClient() { + return HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/IdCardEncryptorUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/IdCardEncryptorUtil.java new file mode 100644 index 0000000..8ec24f6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/IdCardEncryptorUtil.java @@ -0,0 +1,51 @@ +package org.dromara.common.utils; + +import cn.hutool.core.util.HexUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + + +/** + * @author lilemy + * @date 2025/6/25 10:57 + */ +@Slf4j +@Component +public class IdCardEncryptorUtil { + + @Value("${id-card.encrypt-key}") + private String encryptKeyHex; + + private AES aes; + + @PostConstruct + public void init() { + byte[] keyBytes = HexUtil.decodeHex(encryptKeyHex); + this.aes = SecureUtil.aes(keyBytes); + log.info("身份证 AES 加解密工具初始化成功"); + } + + /** + * 加密 + * + * @param idCard 身份证号码 + * @return 加密后的身份证号码 + */ + public String encrypt(String idCard) { + return aes.encryptBase64(idCard); + } + + /** + * 解密 + * + * @param encrypted 密文 + * @return 解密后的身份证号码 + */ + public String decrypt(String encrypted) { + return aes.decryptStr(encrypted); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/JSTUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/JSTUtil.java new file mode 100644 index 0000000..60515da --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/JSTUtil.java @@ -0,0 +1,270 @@ +package org.dromara.common.utils; + +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.constant.GeoJsonConstant; +import org.dromara.facility.domain.dto.geojson.FacFeatureByPlane; +import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint; +import org.dromara.facility.domain.dto.geojson.FacGeometry; +import org.dromara.facility.domain.dto.geojson.FacGeometryByPoint; +import org.locationtech.jts.geom.*; +import org.locationtech.jts.index.strtree.STRtree; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author lilemy + * @date 2025/4/24 11:48 + */ +public class JSTUtil { + + private static final GeometryFactory geometryFactory = new GeometryFactory(); + + /** + * 获取最近点的名称 + * + * @param target 目标点 + * @param nameGeoJson 点对象列表 + * @return 最近点的名称 + */ + public static String findNearestText(List target, List nameGeoJson) { + Point targetPoint = geometryFactory.createPoint(new Coordinate(target.get(0), target.get(1))); + FacFeatureByPoint nearestFeature = null; + double minDistance = Double.MAX_VALUE; + for (FacFeatureByPoint feature : nameGeoJson) { + FacGeometryByPoint geometry = feature.getGeometry(); + List coords = geometry.getCoordinates(); + if (coords != null && coords.size() == 2) { + Point currentPoint = geometryFactory.createPoint(new Coordinate(coords.get(0), coords.get(1))); + double distance = targetPoint.distance(currentPoint); + if (distance < minDistance) { + minDistance = distance; + nearestFeature = feature; + } + } + } + if (nearestFeature != null && nearestFeature.getProperties() != null) { + return nearestFeature.getProperties().getText(); + } + return null; // 如果没找到合适的点 + } + + /** + * 点是否在平面内 + * + * @param planeLists 平面坐标 + * @param pointList 点坐标 + * @return 点是否在平面内 + */ + public static Boolean pointIsWithInPlane(List> planeLists, List pointList) { + // 构建平面 + Coordinate[] coordinates = getPlaneCoordinate(planeLists); + Polygon polygon = geometryFactory.createPolygon(coordinates); + // 构建待判断点 + Point point = geometryFactory.createPoint(new Coordinate(pointList.get(0), pointList.get(1))); + // 判断是否在多边形内 + return polygon.contains(point); + } + + /** + * 获取平面内点列表集合 + * + * @param planeLists 平面坐标列表 + * @param pointLists 点坐标列表集合 + * @return 平面内点坐标列表集合 + */ + public static List> getPointInPlaneList(List> planeLists, List> pointLists) { + // 构建平面 + Coordinate[] coordinates = getPlaneCoordinate(planeLists); + LinearRing shell = geometryFactory.createLinearRing(coordinates); + Polygon polygon = geometryFactory.createPolygon(shell); + // 获取平面内点结合 + return pointLists.stream().filter(pointList -> { + // 构建待判断点 + Point point = geometryFactory.createPoint(new Coordinate(pointList.get(0), pointList.get(1))); + // 判断是否在多边形内 + return polygon.contains(point); + }).toList(); + } + + /** + * 平面是否在平面内 + * + * @param referencePlane 参考平面 + * @param comparePlane 比较平面 + * @return 平面是否在平面内 + */ + public static Boolean planeIsWithInPlane(List> referencePlane, List> comparePlane) { + // 构建参考平面 + Coordinate[] referenceCoordinates = getPlaneCoordinate(referencePlane); + Polygon referencePolygon = geometryFactory.createPolygon(referenceCoordinates); + // 构建比较平面 + Coordinate[] compareCoordinates = getPlaneCoordinate(comparePlane); + Polygon comparePolygon = geometryFactory.createPolygon(compareCoordinates); + // 判断是否在多边形内 + return referencePolygon.contains(comparePolygon); + } + + /** + * 判断两个平面是否相交 + * + * @param referencePlane 参考平面 + * @param comparePlane 待比较平面 + * @return 平面是否相交 + */ + public static Boolean arePolygonsIntersecting(List> referencePlane, List> comparePlane) { + // 构建 Polygon A(参考面) + Coordinate[] coordsA = referencePlane.stream() + .map(p -> new Coordinate(p.getFirst(), p.get(1))) + .toArray(Coordinate[]::new); + Polygon polygonA = geometryFactory.createPolygon(coordsA); + // 构建 Polygon B(比较面) + Coordinate[] coordsB = comparePlane.stream() + .map(p -> new Coordinate(p.getFirst(), p.get(1))) + .toArray(Coordinate[]::new); + Polygon polygonB = geometryFactory.createPolygon(coordsB); + // 使用 JTS 判断是否相交 + return polygonA.intersects(polygonB); + } + + /** + * 获取平面坐标数组 + * + * @param planeLists 平面坐标列表 + * @return 平面坐标数组 + */ + public static Coordinate[] getPlaneCoordinate(List> planeLists) { + return planeLists.stream().map(planeList -> + new Coordinate(planeList.getFirst(), planeList.get(1))) + .toList().toArray(new Coordinate[0]); + } + + /** + * 获取二维坐标 + * + * @param geometry 几何对象 + * @return 二维坐标 + */ + public static List> getTwoDimensionalCoordinates(FacGeometry geometry) { + String type = geometry.getType(); + List coordinates = geometry.getCoordinates(); + return switch (type) { + case GeoJsonConstant.POINT -> throw new ServiceException("点位无法创建方阵", HttpStatus.BAD_REQUEST); + case GeoJsonConstant.LINE -> coordinates.stream() + .filter(obj -> obj instanceof List) + .map(obj -> ((List) obj).stream() + .filter(num -> num instanceof Number) + .map(num -> ((Number) num).doubleValue()) + .collect(Collectors.toList())) + .collect(Collectors.toList()); + case GeoJsonConstant.POLYGON -> coordinates.stream() + .filter(obj -> obj instanceof List) + .flatMap(obj -> ((List) obj).stream()) + .filter(pointObj -> pointObj instanceof List) + .map(pointObj -> ((List) pointObj).stream() + .filter(num -> num instanceof Number) + .map(num -> ((Number) num).doubleValue()) + .collect(Collectors.toList())) + .collect(Collectors.toList()); + default -> throw new ServiceException("暂不支持该类型", HttpStatus.BAD_REQUEST); + }; + } + + /** + * 匹配最近的点,获取该点的名称 + * + * @param polygon 平面 + * @param points 点列表集合 + * @return 最近点的名称 + */ + public static String findNearestPointText(List> polygon, List points) { + if (polygon == null || polygon.size() < 3 || points == null || points.isEmpty()) { + return null; + } + // 1. 构建 Polygon + Coordinate[] polygonCoords = polygon.stream() + .map(coord -> new Coordinate(coord.getFirst(), coord.get(1))) + .toArray(Coordinate[]::new); + Polygon jtsPolygon = geometryFactory.createPolygon(polygonCoords); + // 2. 构建空间索引(JTS STRtree) + STRtree spatialIndex = new STRtree(); + Map coordToFeatureMap = new HashMap<>(); + for (FacFeatureByPoint feature : points) { + List coords = feature.getGeometry().getCoordinates(); + if (coords == null || coords.size() != 2) continue; + Coordinate coord = new Coordinate(coords.get(0), coords.get(1)); + Point point = geometryFactory.createPoint(coord); + // 用点的 Envelope 加入索引 + spatialIndex.insert(point.getEnvelopeInternal(), point); + coordToFeatureMap.put(coord, feature); + } + // 3. 查询距离 polygon 最近的点 + // 用 polygon 中心点附近构造 Envelope(扩大一些范围) + Envelope searchEnv = jtsPolygon.getEnvelopeInternal(); + searchEnv.expandBy(10); // 扩大搜索半径 + @SuppressWarnings("unchecked") + List candidatePoints = spatialIndex.query(searchEnv); + double minDistance = Double.MAX_VALUE; + Coordinate nearestCoord = null; + for (Point point : candidatePoints) { + double distance = point.distance(jtsPolygon); + if (distance < minDistance) { + minDistance = distance; + nearestCoord = point.getCoordinate(); + } + } + if (nearestCoord != null) { + FacFeatureByPoint nearestFeature = coordToFeatureMap.get(nearestCoord); + if (nearestFeature != null && nearestFeature.getProperties() != null) { + return nearestFeature.getProperties().getText(); + } + } + return null; + } + + /** + * 匹配最近的面,获取该面的信息 + * + * @param pointFeature 点位 + * @param polygons 平面列表 + * @return 最近面的信息 + */ + public static FacFeatureByPlane findNearestOrContainingPolygon( + FacFeatureByPoint pointFeature, + List polygons + ) { + if (pointFeature == null || polygons == null || polygons.isEmpty()) { + return null; + } + List coords = pointFeature.getGeometry().getCoordinates(); + if (coords == null || coords.size() != 2) return null; + Coordinate pointCoord = new Coordinate(coords.get(0), coords.get(1)); + Point point = geometryFactory.createPoint(pointCoord); + FacFeatureByPlane nearestPolygon = null; + double minDistance = Double.MAX_VALUE; + for (FacFeatureByPlane polygonFeature : polygons) { + if (polygonFeature == null || polygonFeature.getGeometry() == null) { + continue; // 跳过空对象 + } + List> polyCoords = polygonFeature.getGeometry().getCoordinates().getFirst(); + Coordinate[] polygonCoords = polyCoords.stream() + .map(c -> new Coordinate(c.getFirst(), c.get(1))) + .toArray(Coordinate[]::new); + Polygon polygon = geometryFactory.createPolygon(polygonCoords); + // 优先使用包含点的 polygon + if (polygon.contains(point)) { + return polygonFeature; + } + double distance = polygon.distance(point); + if (distance < minDistance) { + minDistance = distance; + nearestPolygon = polygonFeature; + } + } + return nearestPolygon; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/JsonDimensionUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/JsonDimensionUtil.java new file mode 100644 index 0000000..c01b184 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/JsonDimensionUtil.java @@ -0,0 +1,24 @@ +package org.dromara.common.utils; + +import cn.hutool.json.JSONArray; + +/** + * @author lilemy + * @date 2025/5/30 14:55 + */ +public class JsonDimensionUtil { + + /** + * 判断 JSONArray 的嵌套维度 + * + * @param array 需要判断的 JSONArray + * @return 返回维度层级:1 表示一维,2 表示二维,3 表示三维 ... + */ + public static int getJsonArrayDepth(Object array) { + if (array instanceof JSONArray jsonArray && !jsonArray.isEmpty()) { + return 1 + getJsonArrayDepth(jsonArray.getFirst()); + } + return 0; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/PageConvertUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/PageConvertUtil.java new file mode 100644 index 0000000..139a206 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/PageConvertUtil.java @@ -0,0 +1,34 @@ +package org.dromara.common.utils; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +/** + * @author lilemy + * @date 2025/5/28 11:25 + */ +public class PageConvertUtil { + + /** + * 将 Page 转换为 Page + * + * @param source 原始分页数据 + * @param mapper 实体 -> VO 的转换函数 + * @return Page + */ + public static Page convert(Page source, Function mapper) { + Page target = new Page<>(source.getCurrent(), source.getSize(), source.getTotal()); + if (CollUtil.isEmpty(source.getRecords())) { + target.setRecords(Collections.emptyList()); + } else { + List voList = source.getRecords().stream().map(mapper).toList(); + target.setRecords(voList); + } + return target; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/PdfBoxQrCodeGenerator.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/PdfBoxQrCodeGenerator.java new file mode 100644 index 0000000..3039437 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/PdfBoxQrCodeGenerator.java @@ -0,0 +1,142 @@ +package org.dromara.common.utils; + +import cn.hutool.core.img.ImgUtil; +import cn.hutool.extra.qrcode.QrCodeUtil; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Image; +import com.itextpdf.text.pdf.PdfContentByte; +import com.itextpdf.text.pdf.PdfReader; +import com.itextpdf.text.pdf.PdfStamper; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * @author lilemy + * @date 2025/7/7 9:56 + */ +public class PdfBoxQrCodeGenerator { + + /** + * 生成二维码图片并返回路径 + * + * @param text 二维码文本 + * @param width 二维码宽度 + * @param height 二维码高度 + * @param outputPath 二维码图片保存路径 + * @return 二维码图片保存路径 + */ + public static String generateQRCodeImage(String text, int width, int height, String outputPath) throws Exception { + BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height); + MatrixToImageWriter.writeToPath(bitMatrix, "PNG", new File(outputPath).toPath()); + return outputPath; + } + + /** + * 获取二维码图片字节数组 + * + * @param text 二维码文本 + * @param width 二维码宽度 + * @param height 二维码高度 + * @return 二维码图片字节数组 + */ + public static byte[] generateQRCodeBytes(String text, int width, int height) { + BufferedImage image = QrCodeUtil.generate(text, width, height); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ImgUtil.write(image, ImgUtil.IMAGE_TYPE_PNG, out); + return out.toByteArray(); + } + + /** + * 获取二维码图片字节数组 + * + * @param text 二维码文本 + * @return 二维码图片字节数组 + */ + public static byte[] generateQRCodeBytes(String text) { + return generateQRCodeBytes(text, 200, 200); + } + + /** + * 在PDF指定位置添加二维码 + * + * @param srcPdf 原PDF文件路径 + * @param destPdf 新PDF文件路径 + * @param qrImagePath 二维码图片路径 + * @param pageNum 页码 + * @param x 坐标 + * @param y 坐标 + */ + public static void addQRCodeToPDF(String srcPdf, String destPdf, String qrImagePath, int pageNum, float x, float y) throws IOException, DocumentException { + PdfReader reader = new PdfReader(srcPdf); + PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(destPdf)); + PdfContentByte content = stamper.getOverContent(pageNum); + Image image = Image.getInstance(qrImagePath); + image.setAbsolutePosition(x, y); // 坐标:左下角为原点 + image.scaleAbsolute(100, 100); // 设置二维码大小 + + content.addImage(image); + stamper.close(); + reader.close(); + } + + /** + * 在PDF指定位置添加二维码 + * + * @param srcPdf 原PDF文件路径 + * @param destPdf 新PDF文件路径 + * @param qrCodeBytes 二维码图片字节数组 + * @param pageNum 页码 + * @param x 坐标 + * @param y 坐标 + */ + public static void addQRCodeToPDF(String srcPdf, String destPdf, byte[] qrCodeBytes, int pageNum, float x, float y) throws IOException, DocumentException { + PdfReader reader = new PdfReader(srcPdf); + PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(destPdf)); + PdfContentByte content = stamper.getOverContent(pageNum); + + Image image = Image.getInstance(qrCodeBytes); + image.setAbsolutePosition(x, y); // 坐标:左下角为原点 + image.scaleAbsolute(100, 100); // 设置二维码大小 + + content.addImage(image); + stamper.close(); + reader.close(); + } + + /** + * 在PDF指定位置添加二维码并返回数据流 + * + * @param srcPdf 原PDF文件路径 + * @param qrCodeBytes 二维码图片字节数组 + * @param pageNum 页码 + * @param x 坐标 + * @param y 坐标 + * @return 插入二维码后的PDF文件流 + */ + public static ByteArrayOutputStream addQRCodeToPDF(String srcPdf, byte[] qrCodeBytes, int pageNum, float x, float y) throws IOException, DocumentException { + + PdfReader reader = new PdfReader(srcPdf); + ByteArrayOutputStream pdfOut = new ByteArrayOutputStream(); + PdfStamper stamper = new PdfStamper(reader, pdfOut); + + PdfContentByte content = stamper.getOverContent(pageNum); + Image image = Image.getInstance(qrCodeBytes); + image.setAbsolutePosition(x, y); // 坐标:左下角为原点 + image.scaleAbsolute(100, 100); // 设置二维码大小 + + content.addImage(image); + stamper.close(); + reader.close(); + + return pdfOut; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuCommon.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuCommon.java new file mode 100644 index 0000000..d2e41c5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuCommon.java @@ -0,0 +1,101 @@ +package org.dromara.common.utils.baiduUtil; + +import com.google.gson.Gson; +import org.dromara.common.utils.baiduUtil.entity.AccessTokenResponse; +import org.glassfish.jaxb.runtime.v2.runtime.reflect.opt.Const; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.beans.factory.annotation.Value; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.TimeUnit; + +import static org.dromara.common.constant.businessConstant.REDIS_BAIDU_KEY; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 9:46 + * @Version 1.0 + * + * 获取百度AccessToken + */ +@Service +public class BaiDuCommon { + @Autowired + private HttpClient httpClient; + + @Autowired + private StringRedisTemplate redisTemplate; + + @Value("${baidu.client.id}") + private String clientId; + + @Value("${baidu.client.secret}") + private String clientSecret; + + private static final String TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token?client_id=%s&client_secret=%s&grant_type=client_credentials"; + + private static final Gson gson = new Gson(); + + /** + * 获取百度AccessToken,优先从Redis缓存中获取 + */ + public String getAccessToken() { + // 1. 尝试从Redis中获取 + String cachedToken = redisTemplate.opsForValue().get(REDIS_BAIDU_KEY); + if (cachedToken != null) { + return cachedToken; + } + + // 2. Redis中没有,加锁防止并发请求刷新Token + synchronized (this) { + // 再次检查,避免其他线程已经刷新 + cachedToken = redisTemplate.opsForValue().get(REDIS_BAIDU_KEY); + if (cachedToken != null) { + return cachedToken; + } + + // 3. 真正调用API获取新Token + String newToken = fetchAccessTokenFromBaidu(); + if (newToken != null) { + // 4. 将新Token存入Redis,并设置过期时间(比实际有效期短一些) + redisTemplate.opsForValue().set(REDIS_BAIDU_KEY, newToken, 29, TimeUnit.DAYS); + return newToken; + } + } + + return null; // 获取失败 + } + + /** + * 从百度API获取AccessToken + */ + private String fetchAccessTokenFromBaidu() { + String url = String.format(TOKEN_URL, clientId, clientSecret); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .POST(HttpRequest.BodyPublishers.noBody()) + .build(); + + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + AccessTokenResponse tokenResponse = gson.fromJson(response.body(), AccessTokenResponse.class); + return tokenResponse.getAccessToken(); + } else { + throw new IOException("获取AccessToken失败,状态码: " + response.statusCode()); + } + } catch (IOException | InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("调用百度API获取AccessToken失败", e); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuFace.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuFace.java new file mode 100644 index 0000000..733f0c1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuFace.java @@ -0,0 +1,205 @@ +package org.dromara.common.utils.baiduUtil; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.dromara.common.utils.baiduUtil.entity.face.ComparisonRes; +import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceReq; +import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceRes; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 17:09 + * @Version 1.0 + * 处理百度人脸相关逻辑:人脸检测、人脸对比 + */ +@Service +public class BaiDuFace { + + @Autowired + private BaiDuCommon baiDuCommon; + @Autowired + private HttpClient httpClient; + @Autowired + private ObjectMapper objectMapper; + + // 人脸识别API地址 + private static final String FACE_DETECT_URL = "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=%s"; + // 人脸对比API地址 + private static final String FACE_COMPARE_URL = "https://aip.baidubce.com/rest/2.0/face/v3/match?access_token=%s"; + + + + /** + * 人脸识别+人脸检测 + * @param request 人脸请求参数 + * @throws RuntimeException 检测失败时抛出异常(由Spring统一处理) + */ + public void humanFace(HumanFaceReq request) { + // 1. 获取AccessToken + String accessToken = baiDuCommon.getAccessToken(); + if (accessToken == null || accessToken.trim().isEmpty()) { + throw new RuntimeException("获取访问令牌失败:token为空"); + } + + // 2. 构建请求URL + String requestUrl = String.format(FACE_DETECT_URL, URLEncoder.encode(accessToken, StandardCharsets.UTF_8)); + + try { + // 3. 序列化请求参数 + String requestBody = objectMapper.writeValueAsString(request); + + // 4. 构建HTTP请求 + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(URI.create(requestUrl)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .build(); + + // 5. 发送请求并获取响应 + HttpResponse response = httpClient.send( + httpRequest, + HttpResponse.BodyHandlers.ofString() + ); + + // 6. 解析响应结果 + HumanFaceRes faceRep = objectMapper.readValue(response.body(), HumanFaceRes.class); + + // 7. 处理API返回错误 + if (faceRep.getErrorCode() != 0) { + throw new RuntimeException("错误码说明:" + faceRep.getErrorMsg()); + } + + // 8. 验证人脸信息(无人脸时抛出异常) + if (faceRep.getResult() == null + || faceRep.getResult().getFaceList() == null + || faceRep.getResult().getFaceList().isEmpty()) { + throw new RuntimeException("未检测到有效人脸信息"); + } + + // 9. 人脸质量校验 + HumanFaceRes.FaceList faceInfo = faceRep.getResult().getFaceList().get(0); + + // 9.1 人脸置信度校验(必须为1.0) + if (faceInfo.getFaceProbability() != 1.0) { + throw new RuntimeException("人脸置信度过低,请重新拍摄!"); + } + + // 9.2 真实人脸校验(排除卡通人脸) + HumanFaceRes.FaceType faceType = faceInfo.getFaceType(); + if (faceType == null) { + throw new RuntimeException("无法判断人脸类型"); + } + if ("cartoon".equals(faceType.getType())) { + throw new RuntimeException("请传入真实人脸,勿使用卡通图像"); + } + // 校验真实人脸置信度(需≥0.8) + if (faceType.getProbability() < 0.8) { + throw new RuntimeException("人脸识别不清晰,请换个角度拍摄"); + } + + // 9.3 人脸模糊度校验(模糊度≥0.1视为模糊) + HumanFaceRes.Quality quality = faceInfo.getQuality(); + if (quality == null) { + throw new RuntimeException("无法获取人脸质量信息"); + } + if (quality.getBlur() != 0) { + throw new RuntimeException("人脸过于模糊,请保持镜头稳定"); + } + + // 9.4 光线校验(光线值<100视为过暗) + if (quality.getIllumination() < 100.0) { + throw new RuntimeException("光线太暗,请在光线充足的环境下拍摄"); + } + + // 9.5 人脸完整性校验(1为完整,0为不完整) + if (quality.getCompleteness() != 1) { + throw new RuntimeException("人脸未完全显示,请确保面部在框内"); + } + + } catch (JsonProcessingException e) { + throw new RuntimeException("请求参数序列化失败:" + e.getMessage(), e); + } catch (IOException e) { + throw new RuntimeException("IO处理异常:" + e.getMessage(), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); // 恢复中断状态 + throw new RuntimeException("请求被中断:" + e.getMessage(), e); + } + } + + + + /** + * 人脸对比(计算人脸相似度) + * @param requestList 人脸请求参数列表(至少包含2个人脸) + * @return 人脸相似度得分 + * @throws RuntimeException 对比失败时抛出异常 + */ + public double comparison(List requestList) { + // 1. 校验请求参数 + if (requestList == null || requestList.size() < 2) { + throw new RuntimeException("人脸对比至少需要2张人脸图片"); + } + + // 2. 获取AccessToken + String accessToken = baiDuCommon.getAccessToken(); + if (accessToken == null || accessToken.trim().isEmpty()) { + throw new RuntimeException("获取访问令牌失败:token为空"); + } + + // 3. 构建请求URL + String requestUrl = String.format(FACE_COMPARE_URL, URLEncoder.encode(accessToken, StandardCharsets.UTF_8)); + + try { + // 4. 序列化请求参数 + String requestBody = objectMapper.writeValueAsString(requestList); + + // 5. 构建HTTP请求 + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(URI.create(requestUrl)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .build(); + + // 6. 发送请求并获取响应 + HttpResponse response = httpClient.send( + httpRequest, + HttpResponse.BodyHandlers.ofString() + ); + + // 7. 解析响应结果 + ComparisonRes comparisonRep = objectMapper.readValue(response.body(), ComparisonRes.class); + + // 8. 处理API返回错误 + if (comparisonRep.getErrorCode() != 0) { + throw new RuntimeException("人脸对比失败:" + comparisonRep.getErrorMsg() + + "(错误码:" + comparisonRep.getErrorCode() + ")"); + } + + // 9. 校验对比结果 + if (comparisonRep.getResult() == null) { + throw new RuntimeException("人脸对比结果为空"); + } + + return comparisonRep.getResult().getScore(); + + } catch (JsonProcessingException e) { + throw new RuntimeException("请求参数序列化失败:" + e.getMessage(), e); + } catch (IOException e) { + throw new RuntimeException("IO处理异常:" + e.getMessage(), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("请求被中断:" + e.getMessage(), e); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuOCR.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuOCR.java new file mode 100644 index 0000000..65a45da --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/BaiDuOCR.java @@ -0,0 +1,204 @@ +package org.dromara.common.utils.baiduUtil; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.dromara.common.utils.baiduUtil.entity.ocr.IDCardInfo; +import org.dromara.common.utils.baiduUtil.entity.ocr.OcrReq; +import org.dromara.common.utils.baiduUtil.entity.ocr.Result; +import org.dromara.common.utils.baiduUtil.entity.ocr.WordsResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:45 + * @Version 1.0 + * + * 处理百度OCR相关逻辑:身份证识别、银行卡识别 + */ +@Service +public class BaiDuOCR { + @Autowired + private BaiDuCommon baiDuCommon; + @Autowired + private HttpClient httpClient; + @Autowired + private ObjectMapper objectMapper; //ObjectMapper 是 Java 处理 JSON 的核心工具,项目中使用它进行 JSON 与 Java 对象的相互转换。 + + + String baseUrlTemplate = "https://aip.baidubce.com/rest/2.0/ocr/v1/bankcard?access_token=%s"; + String BASE_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=%s"; + + + + /** + * @description 银行卡OCR识别 + * @author 铁憨憨 + * @date 2025/7/18 11:50 + * @param vr 请求参数 + * @return 识别结果Result + **/ + public Result bankCardOCRRecognition(OcrReq vr) { + // 先从缓存里面捞取token,若为空直接抛出异常 + String atStr = baiDuCommon.getAccessToken(); + if (atStr == null || atStr.trim().isEmpty()) { + throw new RuntimeException("获取访问令牌失败:token为空"); + } + + try { + // 构建请求URL(包含token参数) + String requestUrl = String.format(baseUrlTemplate, URLEncoder.encode(atStr, StandardCharsets.UTF_8)); + + // 准备请求体(将请求参数转为JSON) + String requestBody = objectMapper.writeValueAsString(vr); + if (requestBody == null) { + throw new RuntimeException("请求参数序列化失败"); + } + + // 构建HTTP请求 + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(requestUrl)) + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .build(); + + // 发送请求并获取响应 + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + // 处理响应状态码(非200直接抛出异常) + if (response.statusCode() != 200) { + throw new RuntimeException("接口请求失败,状态码:" + response.statusCode() + ",响应信息:" + response.body()); + } + + // 解析响应结果(若解析失败抛出异常) + Result result = objectMapper.readValue(response.body(), Result.class); + if (result == null) { + throw new RuntimeException("响应结果解析失败"); + } + +// // 若接口返回错误码(如百度API的error_code),抛出异常 +// if (result.getErrorCode() != null && result.getErrorCode() != 0) { +// throw new RuntimeException("接口返回错误:" + result.getErrorMessage() + "(错误码:" + result.getErrorCode() + ")"); +// } + + return result; + + } catch (IOException e) { + // IO异常(如序列化失败、网络IO错误) + throw new RuntimeException("IO处理异常:" + e.getMessage(), e); + } catch (InterruptedException e) { + // 线程中断异常 + Thread.currentThread().interrupt(); // 恢复中断状态 + throw new RuntimeException("请求被中断:" + e.getMessage(), e); + } + } + + + + + /** + * @description 身份证OCR识别 + * @author 铁憨憨 + * @date 2025/7/18 16:53 + * @param request 请求参数 + * @return 识别结果WordsResult + **/ + public WordsResult idCardOCR(OcrReq request) { + // 获取AccessToken,为空直接抛异常 + String accessToken = baiDuCommon.getAccessToken(); + if (accessToken == null || accessToken.trim().isEmpty()) { + throw new RuntimeException("获取访问令牌失败:token为空"); + } + + // 构建请求URL + String requestUrl = String.format(BASE_URL, accessToken); + + try { + // 准备请求体(序列化失败抛异常) + String requestBody = objectMapper.writeValueAsString(request); + if (requestBody == null) { + throw new RuntimeException("请求参数序列化失败"); + } + + // 构建HTTP请求 + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(URI.create(requestUrl)) + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .build(); + + // 发送请求并获取响应 + HttpResponse response = httpClient.send( + httpRequest, + HttpResponse.BodyHandlers.ofString() + ); + + // 处理响应状态码(非200直接抛异常) + if (response.statusCode() != 200) { + throw new RuntimeException("接口请求失败,状态码:" + response.statusCode() + ",响应信息:" + response.body()); + } + + // 处理响应内容(去除空格并解析) + String responseBody = response.body().replaceAll("\\s+", ""); + IDCardInfo idCardInfo = objectMapper.readValue(responseBody, IDCardInfo.class); + if (idCardInfo == null) { + throw new RuntimeException("响应结果解析失败"); + } + + // 检查身份证状态(状态异常由validateImageStatus抛异常) + validateImageStatus(idCardInfo.getImageStatus()); + + // 提取识别结果(结果为空抛异常) + WordsResult wordsResult = idCardInfo.getWordsResult(); + if (wordsResult == null) { + throw new RuntimeException("未识别到身份证信息"); + } + + return wordsResult; + + } catch (IOException e) { + // IO异常(序列化、网络IO等) + throw new RuntimeException("IO处理异常:" + e.getMessage(), e); + } catch (InterruptedException e) { + // 线程中断异常 + Thread.currentThread().interrupt(); // 恢复中断状态 + throw new RuntimeException("请求被中断:" + e.getMessage(), e); + } + } + + + /** + * @description 验证身份证图片状态 + * @author 铁憨憨 + * @date 2025/7/18 17:08 + * @param imageStatus 图片状态 + * @throws RuntimeException 当状态不正常时抛出运行时异常 + **/ + private void validateImageStatus(String imageStatus) { + if (imageStatus == null || "normal".equals(imageStatus)) { + return; // 正常状态,直接返回 + } + + // 根据不同状态码抛出不同的异常信息 + String errorMessage = switch (imageStatus) { + case "reversed_side" -> "身份证正反面颠倒,请调整后重新上传"; + case "non_idcard" -> "上传的图片中不包含身份证,请重新上传"; + case "blurred" -> "身份证图片模糊,请重新上传清晰的图片"; + case "other_type_card" -> "上传的不是身份证,请上传有效的身份证图片"; + case "over_exposure" -> "身份证关键字段反光或过曝,请调整光线后重新上传"; + case "over_dark" -> "身份证图片欠曝(亮度过低),请调整光线后重新上传"; + default -> "未知错误:" + imageStatus; + }; + + throw new RuntimeException(errorMessage); + } + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/AccessTokenResponse.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/AccessTokenResponse.java new file mode 100644 index 0000000..d0fec39 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/AccessTokenResponse.java @@ -0,0 +1,19 @@ +package org.dromara.common.utils.baiduUtil.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 9:56 + * @Version 1.0 + */ +@Data +@Accessors(chain = true) +public class AccessTokenResponse { + private String accessToken; + private int expiresIn; + private String scope; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/ComparisonRes.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/ComparisonRes.java new file mode 100644 index 0000000..0873565 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/ComparisonRes.java @@ -0,0 +1,49 @@ +package org.dromara.common.utils.baiduUtil.entity.face; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 17:15 + * @Version 1.0 + * + * 人脸对比响应结果 + */ +@Data +public class ComparisonRes { + @JsonProperty("error_code") + private int errorCode; + + @JsonProperty("error_msg") + private String errorMsg; + + @JsonProperty("log_id") + private long logId; + + @JsonProperty("timestamp") + private long timestamp; + + @JsonProperty("cached") + private int cached; + + @JsonProperty("result") + private CompareResult result; + + @Data + public static class CompareResult { + @JsonProperty("score") + private double score; // 人脸相似度得分 + + @JsonProperty("face_list") + private List faceList; + } + + @Data + public static class FaceToken { + @JsonProperty("face_token") + private String faceToken; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/HumanFaceReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/HumanFaceReq.java new file mode 100644 index 0000000..e3383f1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/HumanFaceReq.java @@ -0,0 +1,23 @@ +package org.dromara.common.utils.baiduUtil.entity.face; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 17:12 + * @Version 1.0 + * + * 人脸识别请求参数 + */ +@Data +public class HumanFaceReq { + @JsonProperty("image") + private String image; // 图片base64字符串 + + @JsonProperty("image_type") + private String imageType = "BASE64"; // 图片类型(固定为BASE64) + + @JsonProperty("face_field") + private String faceField = "face_type,quality"; // 需要返回的人脸字段 +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/HumanFaceRes.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/HumanFaceRes.java new file mode 100644 index 0000000..2e4c574 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/face/HumanFaceRes.java @@ -0,0 +1,142 @@ +package org.dromara.common.utils.baiduUtil.entity.face; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 17:13 + * @Version 1.0 + * + * 人脸识别响应结果 + */ +@Data +public class HumanFaceRes { + @JsonProperty("error_code") + private int errorCode; + + @JsonProperty("error_msg") + private String errorMsg; + + @JsonProperty("log_id") + private long logId; + + @JsonProperty("timestamp") + private long timestamp; + + @JsonProperty("cached") + private int cached; + + @JsonProperty("result") + private Result result; + + @Data + public static class Result { + @JsonProperty("face_num") + private int faceNum; + + @JsonProperty("face_list") + private List faceList; + } + + @Data + public static class FaceList { + @JsonProperty("face_token") + private String faceToken; + + @JsonProperty("location") + private Location location; + + @JsonProperty("face_probability") + private double faceProbability; + + @JsonProperty("angle") + private Angle angle; + + @JsonProperty("face_type") + private FaceType faceType; + + @JsonProperty("quality") + private Quality quality; + } + + @Data + public static class Location { + @JsonProperty("left") + private double left; + + @JsonProperty("top") + private double top; + + @JsonProperty("width") + private int width; + + @JsonProperty("height") + private int height; + + @JsonProperty("rotation") + private int rotation; + } + + @Data + public static class Angle { + @JsonProperty("yaw") + private double yaw; + + @JsonProperty("pitch") + private double pitch; + + @JsonProperty("roll") + private double roll; + } + + @Data + public static class FaceType { + @JsonProperty("type") + private String type; + + @JsonProperty("probability") + private double probability; + } + + @Data + public static class Quality { + @JsonProperty("occlusion") + private Occlusion occlusion; + + @JsonProperty("blur") + private double blur; + + @JsonProperty("illumination") + private double illumination; + + @JsonProperty("completeness") + private long completeness; + } + + @Data + public static class Occlusion { + @JsonProperty("left_eye") + private double leftEye; + + @JsonProperty("right_eye") + private double rightEye; + + @JsonProperty("nose") + private double nose; + + @JsonProperty("mouth") + private double mouth; + + @JsonProperty("left_cheek") + private double leftCheek; + + @JsonProperty("right_cheek") + private double rightCheek; + + @JsonProperty("chin_contour") + private double chinContour; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/BankData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/BankData.java new file mode 100644 index 0000000..e74f846 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/BankData.java @@ -0,0 +1,39 @@ +package org.dromara.common.utils.baiduUtil.entity.ocr; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:58 + * @Version 1.0 + * + * 银行卡具体信息 + */ +@Data +//public class BankData { +// private String valid_date; // 有效期 +// private String bank_card_number; // 卡号 +// private String bank_name; // 银行名称 +// private int bank_card_type; // 卡类型(0未知,1借记卡,2贷记卡等) +// private String holder_name; // 持卡人姓名(可能为空) +//} + + +public class BankData { + + @JSONField(name = "bank_card_number",label = "银行卡卡号") + private String bankCardNumber; + + @JSONField(name = "valid_date",label = "有效期") + private String validDate; + + @JSONField(name = "bank_card_type",label = "银行卡类型,0:不能识别; 1:借记卡; 2:贷记卡(原信用卡大部分为贷记卡); 3:准贷记卡; 4:预付费卡") + private int bankCardType; + + @JSONField(name = "bank_name",label = "银行名,不能识别时为空") + private String bankName; + + @JSONField(name = "holder_name",label = "持卡人姓名,不能识别时为空") + private String holderName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Field.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Field.java new file mode 100644 index 0000000..ebc77a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Field.java @@ -0,0 +1,16 @@ +package org.dromara.common.utils.baiduUtil.entity.ocr; + +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:55 + * @Version 1.0 + * + * 单个识别字段(含文字和位置) + */ +@Data +public class Field { + private Location location; // 位置信息 + private String words; // 识别文字 +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/IDCardInfo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/IDCardInfo.java new file mode 100644 index 0000000..fbd30a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/IDCardInfo.java @@ -0,0 +1,30 @@ +package org.dromara.common.utils.baiduUtil.entity.ocr; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:50 + * @Version 1.0 + * + * 身份证识别结果 + */ +@Data +public class IDCardInfo { + @JSONField(name = "words_result") + private WordsResult wordsResult; // 识别字段集合(姓名、身份证号等) + + @JSONField(name = "words_result_num") + private int wordsResultNum; // 识别字段数量 + + @JSONField(name = "idcard_number_type") + private int idCardNumberType; // 身份证类型(如18位/15位) + + private String imageStatus; // 图像状态(如是否颠倒) + + @JSONField(name = "log_id") + private long logId; // 请求唯一标识(日志ID) + + private String photo; // 身份证照片base64(若检测) +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Location.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Location.java new file mode 100644 index 0000000..fc61151 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Location.java @@ -0,0 +1,18 @@ +package org.dromara.common.utils.baiduUtil.entity.ocr; + +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:56 + * @Version 1.0 + * + * 位置信息(坐标) + */ +@Data +public class Location { + private int top; // 顶部坐标 + private int left; // 左侧坐标 + private int width; // 宽度 + private int height; // 高度 +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/OcrReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/OcrReq.java new file mode 100644 index 0000000..a785503 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/OcrReq.java @@ -0,0 +1,24 @@ +package org.dromara.common.utils.baiduUtil.entity.ocr; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:47 + * @Version 1.0 + * + * OCR请求参数(身份证/银行卡通用) + */ +@Data +public class OcrReq { + private String image; // 图像base64(与url二选一) + + private String url; // 图像URL(与image二选一) + + @JSONField(name = "id_card_side") + private String idCardSide; // 身份证正反面(front/back,银行卡无需) + + @JSONField(name = "detect_photo") + private boolean detectPhoto;// 是是否开启银行卡质量类型(清晰模糊、边框/四角不完整)检测功能,默认不开启,即:false。 +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Result.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Result.java new file mode 100644 index 0000000..b92420c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/Result.java @@ -0,0 +1,22 @@ +package org.dromara.common.utils.baiduUtil.entity.ocr; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 11:20 + * @Version 1.0 + * + * 银行卡识别的完整返回结果 + */ +@Data +public class Result { + @JSONField(name = "result") + private BankData res; + + private int direction; + + @JSONField(name = "log_id") + private long logId; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/WordsResult.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/WordsResult.java new file mode 100644 index 0000000..43de74b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/baiduUtil/entity/ocr/WordsResult.java @@ -0,0 +1,33 @@ +package org.dromara.common.utils.baiduUtil.entity.ocr; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @Author 铁憨憨 + * @Date 2025/7/18 10:50 + * @Version 1.0 + * + * 身份证识别字段集合 + */ +@Data +public class WordsResult { + @JSONField(name = "姓名") + private Field name; // 姓名 + @JSONField(name = "民族") + private Field nation; // 民族 + @JSONField(name = "住址") + private Field address; // 住址 + @JSONField(name = "公民身份号码") + private Field citizenIdentification; // 身份证号 + @JSONField(name = "出生") + private Field birth; // 出生日期 + @JSONField(name = "性别") + private Field gender; // 性别 + @JSONField(name = "失效日期") + private Field expirationDate; // 失效日期 + @JSONField(name = "签发机关") + private Field issuingAuthority; // 签发机关 + @JSONField(name = "签发日期") + private Field issueDate; // 签发日期 +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/documentOperations/WordToPdfToImg.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/documentOperations/WordToPdfToImg.java new file mode 100644 index 0000000..a089166 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/documentOperations/WordToPdfToImg.java @@ -0,0 +1,166 @@ +package org.dromara.common.utils.documentOperations; + +import jakarta.annotation.Resource; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.rendering.PDFRenderer; +import org.docx4j.Docx4J; +import org.docx4j.openpackaging.exceptions.Docx4JException; +import org.docx4j.openpackaging.packages.WordprocessingMLPackage; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.dromara.common.constant.MinioPathConstant.ContactNotice; + +@Component +public class WordToPdfToImg { + + @Resource + private ISysOssService ossService; + + /** + * wordToImg 根据file生成缩略图(路径) + * + * @param file 文件 + */ + public String wordToImg(MultipartFile file) throws Docx4JException, IOException { + String mergedPath = "output/merged.png"; + // ✅ 1. Word → PDF(内存) + ByteArrayOutputStream pdfOut = new ByteArrayOutputStream(); + // 直接走路径 + // WordprocessingMLPackage wordML = WordprocessingMLPackage.load(new File(docxPath)); + // 直接走文件,word不落地 + WordprocessingMLPackage wordML = WordprocessingMLPackage.load(file.getInputStream()); + Docx4J.toPDF(wordML, pdfOut); + // ✅ 2. PDF → 各页 PNG + List pages = new ArrayList<>(); + try (PDDocument pdf = PDDocument.load(new ByteArrayInputStream(pdfOut.toByteArray()))) { + PDFRenderer renderer = new PDFRenderer(pdf); + for (int i = 0; i < pdf.getNumberOfPages(); i++) { + BufferedImage img = renderer.renderImageWithDPI(i, 144); + pages.add(img); +// ImageIO.write(img, "png", new File(outDir, "page_" + i + ".png")); + } + } + // ✅ 3. 合成所有页为一张长图 + int totalHeight = pages.stream().mapToInt(BufferedImage::getHeight).sum(); + int maxWidth = pages.stream().mapToInt(BufferedImage::getWidth).max().orElse(0); + BufferedImage merged = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D g = merged.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, maxWidth, totalHeight); + + int y = 0; + for (BufferedImage img : pages) { + g.drawImage(img, 0, y, null); + y += img.getHeight(); + } + g.dispose(); + ImageIO.write(merged, "png", new File(mergedPath)); + System.out.println("✅ 成功合并图片:" + mergedPath); + return mergedPath; + } + + + /** + * convertWordToImage 根据MultipartFile转成缩略图 并上传至minio + * + * @param wordFile 文件 + */ + public SysOssUploadVo convertWordToImage(MultipartFile wordFile) throws Exception { + // 1. Word -> PDF (内存) + WordprocessingMLPackage wordML = WordprocessingMLPackage.load(wordFile.getInputStream()); + ByteArrayOutputStream pdfOut = new ByteArrayOutputStream(); + Docx4J.toPDF(wordML, pdfOut); + + // 2. PDF -> BufferedImage 每页 + List pages = new ArrayList<>(); + try (PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfOut.toByteArray()))) { + PDFRenderer renderer = new PDFRenderer(document); + for (int i = 0; i < document.getNumberOfPages(); i++) { + BufferedImage img = renderer.renderImageWithDPI(i, 144); + pages.add(img); + } + } + + // 3. 合并图片为一张长图 + int width = pages.stream().mapToInt(BufferedImage::getWidth).max().orElse(0); + int totalHeight = pages.stream().mapToInt(BufferedImage::getHeight).sum(); + + BufferedImage merged = new BufferedImage(width, totalHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D g = merged.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, width, totalHeight); + + int y = 0; + for (BufferedImage img : pages) { + g.drawImage(img, 0, y, null); + y += img.getHeight(); + } + g.dispose(); + + // 4. 写入 ByteArrayOutputStream 并转换为 MultipartFile + ByteArrayOutputStream imageOut = new ByteArrayOutputStream(); + ImageIO.write(merged, "png", imageOut); + + MockMultipartFile image = new MockMultipartFile( + "image", // 字段名 + wordFile.getOriginalFilename() + ".png", // 文件名 + "image/png", // ContentType + new ByteArrayInputStream(imageOut.toByteArray()) // 文件内容 + ); + return ossService.uploadWithNoSave(image, ossService.minioFileName(ContactNotice, image)); + } + +// public static void main(String[] args) throws Exception { +// String docxPath = "C:\\Users\\YuanJie-DSJ\\Downloads\\123.docx"; +// String outDir = "output/pages"; +// String mergedPath = "output/merged.png"; +// +// new File(outDir).mkdirs(); +// +// // ✅ 1. Word → PDF(内存) +// ByteArrayOutputStream pdfOut = new ByteArrayOutputStream(); +// WordprocessingMLPackage wordML = WordprocessingMLPackage.load(new File(docxPath)); +// Docx4J.toPDF(wordML, pdfOut); // 推荐 facade 方法 :contentReference[oaicite:2]{index=2} +// // ✅ 2. PDF → 各页 PNG +// List pages = new ArrayList<>(); +// try (PDDocument pdf = PDDocument.load(new ByteArrayInputStream(pdfOut.toByteArray()))) { +// PDFRenderer renderer = new PDFRenderer(pdf); +// for (int i = 0; i < pdf.getNumberOfPages(); i++) { +// BufferedImage img = renderer.renderImageWithDPI(i, 144); +// pages.add(img); +//// ImageIO.write(img, "png", new File(outDir, "page_" + i + ".png")); +// } +// } +// // ✅ 3. 合成所有页为一张长图 +// int totalHeight = pages.stream().mapToInt(BufferedImage::getHeight).sum(); +// int maxWidth = pages.stream().mapToInt(BufferedImage::getWidth).max().orElse(0); +// BufferedImage merged = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_RGB); +// Graphics2D g = merged.createGraphics(); +// g.setColor(Color.WHITE); +// g.fillRect(0, 0, maxWidth, totalHeight); +// +// int y = 0; +// for (BufferedImage img : pages) { +// g.drawImage(img, 0, y, null); +// y += img.getHeight(); +// } +// g.dispose(); +// +// ImageIO.write(merged, "png", new File(mergedPath)); +// System.out.println("✅ 成功合并图片:" + mergedPath); +// } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/config/WebConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/config/WebConfig.java new file mode 100644 index 0000000..76b48f9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/config/WebConfig.java @@ -0,0 +1,21 @@ +package org.dromara.contractor.config; + +import jakarta.annotation.Resource; +import org.dromara.contractor.interceptor.ContractorInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Resource + private ContractorInterceptor contractorInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(contractorInterceptor) + .addPathPatterns("/contractor/**") // 拦截所有 /contractor 开头 + .excludePathPatterns("/contractor/contractor/**"); // 排除具体路径 + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/constant/SubConstructionUserConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/constant/SubConstructionUserConstant.java new file mode 100644 index 0000000..12f419e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/constant/SubConstructionUserConstant.java @@ -0,0 +1,14 @@ +package org.dromara.contractor.constant; + +/** + * @author lilemy + * @date 2025/4/2 17:18 + */ +public interface SubConstructionUserConstant { + + /** + * 施工人员文件类型字典 + */ + String USER_FILE_TYPE = "user_file_type"; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserController.java new file mode 100644 index 0000000..b8ebe90 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserController.java @@ -0,0 +1,193 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.constructionuser.*; +import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserAttendanceMonthVo; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserAttendanceTotalVo; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserGisVo; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 施工人员 + * + * @author lilemy + * @date 2025-03-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/contractor/constructionUser") +public class SubConstructionUserController extends BaseController { + + private final ISubConstructionUserService constructionUserService; + + /** + * 查询施工人员列表 + */ + @SaCheckPermission("contractor:constructionUser:list") + @GetMapping("/list") + public TableDataInfo list(SubConstructionUserQueryReq req, PageQuery pageQuery) { + return constructionUserService.queryPageList(req, pageQuery); + } + + /** + * 查询每个施工人员总的考勤列表 + */ + @SaCheckPermission(value = {"contractor:constructionUser:list", "project:attendance:list"}) + @GetMapping("/list/attendance/total") + public TableDataInfo listAttendanceTotal(SubConstructionUserAttendanceQueryReq req, + PageQuery pageQuery) { + return constructionUserService.queryPageAttendanceList(req, pageQuery); + } + + /** + * 查询施工人员月份考勤列表 + */ + @SaCheckPermission("contractor:constructionUser:list") + @GetMapping("/list/attendance/month") + public R> listAttendanceMonth(SubConstructionUserAttendanceMonthReq req) { + return R.ok(constructionUserService.queryAttendanceMonthList(req)); + } + + /** + * 导出施工人员列表 + */ + @SaCheckPermission("contractor:constructionUser:export") + @Log(title = "施工人员", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SubConstructionUserQueryReq req, HttpServletResponse response) { + List list = constructionUserService.queryList(req); + ExcelUtil.exportExcel(list, "施工人员", BusConstructionUserExportVo.class, response); + } + + /** + * 获取施工人员详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("contractor:constructionUser:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(constructionUserService.queryById(id)); + } + + /** + * 查询大屏施工人员信息 + */ + @SaCheckPermission("contractor:constructionUser:query") + @GetMapping("/gis") + public R getGisData(SubConstructionUserGisReq req) { + return R.ok(constructionUserService.getGisData(req)); + } + + /** + * 新增施工人员 + */ + @SaCheckPermission("contractor:constructionUser:add") + @Log(title = "施工人员", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SubConstructionUserCreateReq req) { + return R.ok(constructionUserService.insertByBo(req)); + } + + /** + * 修改施工人员 + */ + @SaCheckPermission("contractor:constructionUser:edit") + @Log(title = "施工人员", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SubConstructionUserUpdateReq req) { + return toAjax(constructionUserService.updateByBo(req)); + } + + /** + * 修改施工人员工资 + */ + @SaCheckPermission("contractor:constructionUser:edit") + @Log(title = "施工人员", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/salary") + public R editSalary(@Validated(EditGroup.class) @RequestBody SubConstructionUserUpdateSalaryReq req) { + return toAjax(constructionUserService.updateSalary(req)); + } + + /** + * 修改施工人员打卡状态 + */ + @SaCheckPermission("contractor:constructionUser:edit") + @Log(title = "施工人员", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/clock") + public R editClock(@Validated(EditGroup.class) @RequestBody SubConstructionUserUpdateClockReq req) { + return toAjax(constructionUserService.updateClock(req)); + } + + /** + * 批量修改施工人员状态 + */ + @SaCheckPermission("contractor:constructionUser:edit") + @Log(title = "施工人员", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/batch/status") + public R batchUpdateStatus(@Validated(EditGroup.class) @RequestBody SubConstructionUserBatchUpdateStatusReq req) { + return toAjax(constructionUserService.batchUpdateStatus(req)); + } + + /** + * 根据项目id批量修改施工人员打卡状态 + */ + @SaCheckPermission("contractor:constructionUser:edit") + @Log(title = "施工人员", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/batch/clock") + public R batchUpdateClock(@Validated(EditGroup.class) @RequestBody SubConstructionUserBatchUpdateClockReq req) { + return toAjax(constructionUserService.batchUpdateClockByProjectId(req)); + } + + /** + * 施工人员迁移 + */ + @SaCheckPermission("contractor:constructionUser:migration") + @Log(title = "施工人员", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/change/project") + public R changeUserProject(@Validated(EditGroup.class) @RequestBody SubConstructionUserChangeProjectReq req) { + return toAjax(constructionUserService.changeUserProject(req)); + } + + /** + * 删除施工人员 + * + * @param ids 主键串 + */ + @SaCheckPermission("contractor:constructionUser:remove") + @Log(title = "施工人员", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(constructionUserService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserFileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserFileController.java new file mode 100644 index 0000000..693cdf3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserFileController.java @@ -0,0 +1,104 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileQueryReq; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileSaveReq; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileTemplateReq; +import org.dromara.contractor.domain.vo.constructionuserfile.SubConstructionUserFileVo; +import org.dromara.contractor.service.ISubConstructionUserFileService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 施工人员文件存储 + * + * @author lilemy + * @date 2025-04-01 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/contractor/constructionUserFile") +public class SubConstructionUserFileController extends BaseController { + + private final ISubConstructionUserFileService constructionUserFileService; + + /** + * 查询施工人员文件存储列表 + */ + @SaCheckPermission(value = {"project:constructionUserFile:list", "contractor:constructionUserFile:list"}, mode = SaMode.OR) + @GetMapping("/list") + public R> list(SubConstructionUserFileQueryReq req) { + return R.ok(constructionUserFileService.queryList(req)); + } + + /** + * 导出施工人员文件存储列表 + */ + @SaCheckPermission(value = {"project:constructionUserFile:export", "contractor:constructionUserFile:export"}, mode = SaMode.OR) + @Log(title = "施工人员文件存储", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SubConstructionUserFileQueryReq req, HttpServletResponse response) { + List list = constructionUserFileService.queryList(req); + ExcelUtil.exportExcel(list, "施工人员文件存储", SubConstructionUserFileVo.class, response); + } + + /** + * 下载施工人员文件存储模板 + */ + @SaCheckPermission(value = {"project:constructionUserFile:download", "contractor:constructionUserFile:download"}, mode = SaMode.OR) + @Log(title = "施工人员文件存储", businessType = BusinessType.EXPORT) + @RepeatSubmit() + @PostMapping("/exportFileTemplate") + public void exportFileTemplate(SubConstructionUserFileTemplateReq req, HttpServletResponse response) { + constructionUserFileService.downloadFileTemplate(req, response); + } + + /** + * 上传施工人员文件压缩包,批量导入存储施工人员文件 + */ + @SaCheckPermission(value = {"project:constructionUserFile:upload", "contractor:constructionUserFile:upload"}, mode = SaMode.OR) + @Log(title = "施工人员文件存储", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/upload/zip") + public R uploadFileZip(@RequestParam("file") MultipartFile file) { + Boolean result = constructionUserFileService.batchUploadFileByZip(file); + return R.ok(result); + } + + /** + * 获取施工人员文件存储详细信息 + * + * @param id 主键 + */ + @SaCheckPermission(value = {"project:constructionUserFile:query", "contractor:constructionUserFile:query"}, mode = SaMode.OR) + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(constructionUserFileService.queryById(id)); + } + + /** + * 保存施工人员文件存储详情信息 + */ + @SaCheckPermission(value = {"project:constructionUserFile:save", "contractor:constructionUserFile:save"}, mode = SaMode.OR) + @Log(title = "施工人员文件存储", businessType = BusinessType.INSERT) + @PostMapping("/save") + public R save(@RequestBody SubConstructionUserFileSaveReq req) { + return R.ok(constructionUserFileService.saveFileList(req)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorController.java new file mode 100644 index 0000000..3962724 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorController.java @@ -0,0 +1,118 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.contractor.SubContractorCreateReq; +import org.dromara.contractor.domain.dto.contractor.SubContractorQueryReq; +import org.dromara.contractor.domain.dto.contractor.SubContractorUpdateReq; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; +import org.dromara.contractor.service.ISubContractorService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 分包单位 + * + * @author lilemy + * @date 2025-03-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/contractor/contractor") +public class SubContractorController extends BaseController { + + private final ISubContractorService contractorService; + + /** + * 查询分包单位列表 + */ + @SaCheckPermission("contractor:contractor:list") + @GetMapping("/list") + public TableDataInfo list(SubContractorQueryReq req, PageQuery pageQuery) { + return contractorService.queryPageList(req, pageQuery); + } + + /** + * 查询没有绑定部门的分包单位列表 + */ + @SaCheckPermission("contractor:contractor:listNoDept") + @GetMapping("/listNoDept/{projectId}") + public List listNoDept(@NotNull(message = "项目主键不能为空") + @PathVariable Long projectId) { + return contractorService.queryListNoDept(projectId); + } + + /** + * 导出分包单位列表 + */ + @SaCheckPermission("contractor:contractor:export") + @Log(title = "分包单位", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SubContractorQueryReq req, HttpServletResponse response) { + List list = contractorService.queryList(req); + ExcelUtil.exportExcel(list, "分包单位", SubContractorVo.class, response); + } + + /** + * 获取分包单位详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("contractor:contractor:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(contractorService.queryById(id)); + } + + /** + * 新增分包单位 + */ + @SaCheckPermission("contractor:contractor:add") + @Log(title = "分包单位", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SubContractorCreateReq req) { + return R.ok(contractorService.insertByBo(req)); + } + + /** + * 修改分包单位 + */ + @SaCheckPermission("contractor:contractor:edit") + @Log(title = "分包单位", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SubContractorUpdateReq req) { + return toAjax(contractorService.updateByBo(req)); + } + + /** + * 删除分包单位 + * + * @param ids 主键串 + */ + @SaCheckPermission("contractor:contractor:remove") + @Log(title = "分包单位", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(contractorService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorMaterialController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorMaterialController.java new file mode 100644 index 0000000..9ae903b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorMaterialController.java @@ -0,0 +1,108 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialCreateReq; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialQueryReq; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialUpdateReq; +import org.dromara.contractor.domain.vo.contractormaterial.SubContractorMaterialVo; +import org.dromara.contractor.service.ISubContractorMaterialService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 分包方物料 + * + * @author lilemy + * @date 2025-06-27 + */ +@Validated +@RestController +@RequestMapping("/contractor/contractorMaterial") +public class SubContractorMaterialController extends BaseController { + + @Resource + private ISubContractorMaterialService contractorMaterialService; + + /** + * 查询分包方物料列表 + */ + @SaCheckPermission("contractor:contractorMaterial:list") + @GetMapping("/list") + public TableDataInfo list(SubContractorMaterialQueryReq req, PageQuery pageQuery) { + return contractorMaterialService.queryPageList(req, pageQuery); + } + + /** + * 导出分包方物料列表 + */ + @SaCheckPermission("contractor:contractorMaterial:export") + @Log(title = "分包方物料", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SubContractorMaterialQueryReq req, HttpServletResponse response) { + List list = contractorMaterialService.queryList(req); + ExcelUtil.exportExcel(list, "分包方物料", SubContractorMaterialVo.class, response); + } + + /** + * 获取分包方物料详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("contractor:contractorMaterial:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(contractorMaterialService.queryById(id)); + } + + /** + * 新增分包方物料 + */ + @SaCheckPermission("contractor:contractorMaterial:add") + @Log(title = "分包方物料", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SubContractorMaterialCreateReq req) { + return R.ok(contractorMaterialService.insertByBo(req)); + } + + /** + * 修改分包方物料 + */ + @SaCheckPermission("contractor:contractorMaterial:edit") + @Log(title = "分包方物料", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SubContractorMaterialUpdateReq req) { + return toAjax(contractorMaterialService.updateByBo(req)); + } + + /** + * 删除分包方物料 + * + * @param ids 主键串 + */ + @SaCheckPermission("contractor:contractorMaterial:remove") + @Log(title = "分包方物料", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(contractorMaterialService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorMaterialRecordController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorMaterialRecordController.java new file mode 100644 index 0000000..0c37b78 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorMaterialRecordController.java @@ -0,0 +1,108 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordCreateReq; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordQueryReq; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordUpdateReq; +import org.dromara.contractor.domain.vo.contractormaterialrecord.SubContractorMaterialRecordVo; +import org.dromara.contractor.service.ISubContractorMaterialRecordService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 分包方物料记录 + * + * @author lilemy + * @date 2025-06-27 + */ +@Validated +@RestController +@RequestMapping("/contractor/contractorMaterialRecord") +public class SubContractorMaterialRecordController extends BaseController { + + @Resource + private ISubContractorMaterialRecordService subContractorMaterialRecordService; + + /** + * 查询分包方物料记录列表 + */ + @SaCheckPermission("contractor:contractorMaterialRecord:list") + @GetMapping("/list") + public TableDataInfo list(SubContractorMaterialRecordQueryReq req, PageQuery pageQuery) { + return subContractorMaterialRecordService.queryPageList(req, pageQuery); + } + + /** + * 导出分包方物料记录列表 + */ + @SaCheckPermission("contractor:contractorMaterialRecord:export") + @Log(title = "分包方物料记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SubContractorMaterialRecordQueryReq req, HttpServletResponse response) { + List list = subContractorMaterialRecordService.queryList(req); + ExcelUtil.exportExcel(list, "分包方物料记录", SubContractorMaterialRecordVo.class, response); + } + + /** + * 获取分包方物料记录详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("contractor:contractorMaterialRecord:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(subContractorMaterialRecordService.queryById(id)); + } + + /** + * 新增分包方物料记录 + */ + @SaCheckPermission("contractor:contractorMaterialRecord:add") + @Log(title = "分包方物料记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SubContractorMaterialRecordCreateReq req) { + return R.ok(subContractorMaterialRecordService.insertByBo(req)); + } + + /** + * 修改分包方物料记录 + */ + @SaCheckPermission("contractor:contractorMaterialRecord:edit") + @Log(title = "分包方物料记录", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SubContractorMaterialRecordUpdateReq req) { + return toAjax(subContractorMaterialRecordService.updateByBo(req)); + } + + /** + * 删除分包方物料记录 + * + * @param ids 主键串 + */ + @SaCheckPermission("contractor:contractorMaterialRecord:remove") + @Log(title = "分包方物料记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(subContractorMaterialRecordService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorToolController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorToolController.java new file mode 100644 index 0000000..225025b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorToolController.java @@ -0,0 +1,108 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolCreateReq; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolQueryReq; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolUpdateReq; +import org.dromara.contractor.domain.vo.contractortool.SubContractorToolVo; +import org.dromara.contractor.service.ISubContractorToolService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 分包方工器具 + * + * @author lilemy + * @date 2025-06-26 + */ +@Validated +@RestController +@RequestMapping("/contractor/contractorTool") +public class SubContractorToolController extends BaseController { + + @Resource + private ISubContractorToolService busContractorToolService; + + /** + * 查询分包方工器具列表 + */ + @SaCheckPermission("contractor:contractorTool:list") + @GetMapping("/list") + public TableDataInfo list(SubContractorToolQueryReq req, PageQuery pageQuery) { + return busContractorToolService.queryPageList(req, pageQuery); + } + + /** + * 导出分包方工器具列表 + */ + @SaCheckPermission("contractor:contractorTool:export") + @Log(title = "分包方工器具", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SubContractorToolQueryReq req, HttpServletResponse response) { + List list = busContractorToolService.queryList(req); + ExcelUtil.exportExcel(list, "分包方工器具", SubContractorToolVo.class, response); + } + + /** + * 获取分包方工器具详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("contractor:contractorTool:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busContractorToolService.queryById(id)); + } + + /** + * 新增分包方工器具 + */ + @SaCheckPermission("contractor:contractorTool:add") + @Log(title = "分包方工器具", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SubContractorToolCreateReq req) { + return R.ok(busContractorToolService.insertByBo(req)); + } + + /** + * 修改分包方工器具 + */ + @SaCheckPermission("contractor:contractorTool:edit") + @Log(title = "分包方工器具", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SubContractorToolUpdateReq req) { + return toAjax(busContractorToolService.updateByBo(req)); + } + + /** + * 删除分包方工器具 + * + * @param ids 主键串 + */ + @SaCheckPermission("contractor:contractorTool:remove") + @Log(title = "分包方工器具", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busContractorToolService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorToolRecordController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorToolRecordController.java new file mode 100644 index 0000000..c039b99 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubContractorToolRecordController.java @@ -0,0 +1,106 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordCreateReq; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordQueryReq; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordUpdateReq; +import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo; +import org.dromara.contractor.service.ISubContractorToolRecordService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 分包方工器具记录 + * + * @author lilemy + * @date 2025-06-26 + */ +@Validated +@RestController +@RequestMapping("/contractor/contractorToolRecord") +public class SubContractorToolRecordController extends BaseController { + + @Resource + private ISubContractorToolRecordService contractorToolRecordService; + + /** + * 查询分包方工器具记录列表 + */ + @SaCheckPermission("contractor:contractorToolRecord:list") + @GetMapping("/list") + public TableDataInfo list(SubContractorToolRecordQueryReq req, PageQuery pageQuery) { + return contractorToolRecordService.queryPageList(req, pageQuery); + } + + /** + * 导出分包方工器具记录列表 + */ + @SaCheckPermission("contractor:contractorToolRecord:export") + @Log(title = "分包方工器具记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SubContractorToolRecordQueryReq req, HttpServletResponse response) { + List list = contractorToolRecordService.queryList(req); + ExcelUtil.exportExcel(list, "分包方工器具记录", SubContractorToolRecordVo.class, response); + } + + /** + * 获取分包方工器具记录详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("contractor:contractorToolRecord:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(contractorToolRecordService.queryById(id)); + } + + /** + * 新增分包方工器具记录 + */ + @SaCheckPermission("contractor:contractorToolRecord:add") + @Log(title = "分包方工器具记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@RequestBody SubContractorToolRecordCreateReq req) { + return R.ok(contractorToolRecordService.insertByBo(req)); + } + + /** + * 修改分包方工器具记录 + */ + @SaCheckPermission("contractor:contractorToolRecord:edit") + @Log(title = "分包方工器具记录", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@RequestBody SubContractorToolRecordUpdateReq req) { + return toAjax(contractorToolRecordService.updateByBo(req)); + } + + /** + * 删除分包方工器具记录 + * + * @param ids 主键串 + */ + @SaCheckPermission("contractor:contractorToolRecord:remove") + @Log(title = "分包方工器具记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(contractorToolRecordService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubSubcontractController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubSubcontractController.java new file mode 100644 index 0000000..a65d8ba --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubSubcontractController.java @@ -0,0 +1,95 @@ +package org.dromara.contractor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractCreateReq; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractQueryReq; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractUpdateReq; +import org.dromara.contractor.domain.vo.subcontract.SubSubcontractVo; +import org.dromara.contractor.service.ISubSubcontractService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 分包合同 + * + * @author lilemy + * @date 2025-06-25 + */ +@Validated +@RestController +@RequestMapping("/contractor/subcontract") +public class SubSubcontractController extends BaseController { + + @Resource + private ISubSubcontractService subcontractService; + + /** + * 查询分包合同列表 + */ + @SaCheckPermission("contractor:subcontract:list") + @GetMapping("/list") + public TableDataInfo list(SubSubcontractQueryReq req, PageQuery pageQuery) { + return subcontractService.queryPageList(req, pageQuery); + } + + /** + * 获取分包合同详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("contractor:subcontract:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(subcontractService.queryById(id)); + } + + /** + * 新增分包合同 + */ + @SaCheckPermission("contractor:subcontract:add") + @Log(title = "分包合同", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SubSubcontractCreateReq req) { + return R.ok(subcontractService.insertByBo(req)); + } + + /** + * 修改分包合同 + */ + @SaCheckPermission("contractor:subcontract:edit") + @Log(title = "分包合同", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SubSubcontractUpdateReq req) { + return toAjax(subcontractService.updateByBo(req)); + } + + /** + * 删除分包合同 + * + * @param ids 主键串 + */ + @SaCheckPermission("contractor:subcontract:remove") + @Log(title = "分包合同", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(subcontractService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubConstructionUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubConstructionUser.java new file mode 100644 index 0000000..6d73f44 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubConstructionUser.java @@ -0,0 +1,192 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 施工人员对象 sub_construction_user + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sub_construction_user") +public class SubConstructionUser extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 人脸照 + */ + private String facePic; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 状态(0在职 1离职) + */ + private String status; + + /** + * 是否代打 + */ + private String isPinch; + + /** + * 联系电话 + */ + private String phone; + + /** + * 0:保密 1:男 2女 + */ + private String sex; + + /** + * 民族 + */ + private String nation; + + /** + * 身份证正面图片 + */ + private String sfzFrontPic; + + /** + * 身份证反面图片 + */ + private String sfzBackPic; + + /** + * 身份证号码 + */ + private String sfzNumber; + + /** + * 身份证有效开始期 + */ + private String sfzStart; + + /** + * 身份证有效结束期 + */ + private String sfzEnd; + + /** + * 身份证地址 + */ + private String sfzSite; + + /** + * 身份证出生日期 + */ + private String sfzBirth; + + /** + * 籍贯 + */ + private String nativePlace; + + /** + * 银行卡图片 + */ + private String yhkPic; + + /** + * 银行卡号 + */ + private String yhkNumber; + + /** + * 开户行 + */ + private String yhkOpeningBank; + + /** + * 持卡人 + */ + private String yhkCardholder; + + /** + * 工种(字典type_of_work) + */ + private String typeOfWork; + + /** + * 工资计量单位 + */ + private String wageMeasureUnit; + + /** + * 特种工作证图片 + */ + private String specialWorkPic; + + /** + * 打卡(0启用打卡 1禁止打卡) + */ + private String clock; + + /** + * 入场时间 + */ + private Date entryDate; + + /** + * 离场时间 + */ + private Date leaveDate; + + /** + * 薪水 + */ + private Long salary; + + /** + * 用户角色 + */ + private String userRole; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubConstructionUserFile.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubConstructionUserFile.java new file mode 100644 index 0000000..f6f920d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubConstructionUserFile.java @@ -0,0 +1,60 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 施工人员文件存储对象 sub_construction_user_file + * + * @author lilemy + * @date 2025-04-01 + */ +@Data +@TableName("sub_construction_user_file") +public class SubConstructionUserFile implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 用户id + */ + private Long userId; + + /** + * 文件类型 + */ + private String fileType; + + /** + * 文件路径 + */ + private String path; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractor.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractor.java new file mode 100644 index 0000000..2fee3e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractor.java @@ -0,0 +1,81 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 分包单位对象 sub_contractor + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sub_contractor") +public class SubContractor extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 公司名称 + */ + private String name; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人联系电话 + */ + private String principalPhone; + + /** + * 管理人 + */ + private String custodian; + + /** + * 管理人联系电话 + */ + private String custodianPhone; + + /** + * 分包类型 + */ + private String contractorType; + + /** + * 公司相关文件 + */ + private String files; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorMaterial.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorMaterial.java new file mode 100644 index 0000000..019e7b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorMaterial.java @@ -0,0 +1,77 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 分包方物料对象 sub_contractor_material + * + * @author lilemy + * @date 2025-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sub_contractor_material") +public class SubContractorMaterial extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 物料名称 + */ + private String materialName; + + /** + * 物料类型 + */ + private String materialType; + + /** + * 物料型号 + */ + private String materialModel; + + /** + * 物料数量 + */ + private BigDecimal materialNumber; + + /** + * 物料单位 + */ + private String materialUnit; + + /** + * 文件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorMaterialRecord.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorMaterialRecord.java new file mode 100644 index 0000000..2dcb190 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorMaterialRecord.java @@ -0,0 +1,83 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 分包方物料记录对象 sub_contractor_material_record + * + * @author lilemy + * @date 2025-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sub_contractor_material_record") +public class SubContractorMaterialRecord extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 物料id + */ + private Long contractorMaterialId; + + /** + * 记录类型(1到货计划 2使用情况) + */ + private String recordType; + + /** + * 记录时间 + */ + private Date recordTime; + + /** + * 数量 + */ + private BigDecimal recordNumber; + + /** + * 剩余数量(到货 使用) + */ + private BigDecimal remainingNumber; + + /** + * 使用位置或构件部位(使用情况) + */ + private String usedPosition; + + /** + * 相关附件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorTool.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorTool.java new file mode 100644 index 0000000..039312d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorTool.java @@ -0,0 +1,72 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 分包方工器具对象 sub_contractor_tool + * + * @author lilemy + * @date 2025-06-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sub_contractor_tool") +public class SubContractorTool extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 工具名称 + */ + private String toolName; + + /** + * 工具类型 + */ + private String toolType; + + /** + * 工具型号 + */ + private String toolModel; + + /** + * 工具数量 + */ + private BigDecimal toolNumber; + + /** + * 文件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorToolRecord.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorToolRecord.java new file mode 100644 index 0000000..045d6ce --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubContractorToolRecord.java @@ -0,0 +1,97 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.json.handler.BigDecimalToIntegerSerializer; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 分包方工器具记录对象 sub_contractor_tool_record + * + * @author lilemy + * @date 2025-06-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sub_contractor_tool_record") +public class SubContractorToolRecord extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 分包方工器具id + */ + private Long contractorToolId; + + /** + * 记录类型(1进场 2出场) + */ + private String recordType; + + /** + * 记录工器具数量 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal recordNumber; + + /** + * 剩余数量 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal remainingNumber; + + /** + * 检测编号 + */ + private String checkNum; + + /** + * 检测部门 + */ + private String checkDept; + + /** + * 检测时间 + */ + private Date checkTime; + + /** + * 合格证 + */ + private String certificate; + + /** + * 备注 + */ + private String remark; + + /** + * 记录时间 + */ + private Date recordTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubSubcontract.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubSubcontract.java new file mode 100644 index 0000000..b820928 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/SubSubcontract.java @@ -0,0 +1,86 @@ +package org.dromara.contractor.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 分包合同对象 sub_subcontract + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@TableName("sub_subcontract") +public class SubSubcontract implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 合同文件id + */ + private Long contractFileId; + + /** + * 合同编号 + */ + private String contractNumber; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 合同类型 + */ + private String contractType; + + /** + * 合同金额 + */ + private BigDecimal contractAmount; + + /** + * 合同时间 + */ + private Date contractTime; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAttendanceMonthReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAttendanceMonthReq.java new file mode 100644 index 0000000..bd0bd1c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAttendanceMonthReq.java @@ -0,0 +1,30 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/7 15:04 + */ +@Data +public class SubConstructionUserAttendanceMonthReq implements Serializable { + + @Serial + private static final long serialVersionUID = -1496942176392426636L; + + /** + * id + */ + @NotNull(message = "用户主键不能为空") + private Long userId; + + /** + * 打卡月份 + */ + private String clockMonth; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAttendanceQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAttendanceQueryReq.java new file mode 100644 index 0000000..cca9e2e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAttendanceQueryReq.java @@ -0,0 +1,45 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/7 10:52 + */ +@Data +public class SubConstructionUserAttendanceQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6634291825924626633L; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 工种 + */ + private String typeOfWork; + + /** + * 打卡月份 + */ + private String clockDate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserBatchUpdateClockReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserBatchUpdateClockReq.java new file mode 100644 index 0000000..fd1667a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserBatchUpdateClockReq.java @@ -0,0 +1,32 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 根据项目id一键开关施工人员打卡状态 + * + * @author lilemy + * @date 2025/4/2 9:14 + */ +@Data +public class SubConstructionUserBatchUpdateClockReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5803749609177642435L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 打卡(0启用打卡 1禁止打卡) + */ + @NotNull(message = "打卡状态不能为空") + private String clock; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserBatchUpdateStatusReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserBatchUpdateStatusReq.java new file mode 100644 index 0000000..899d9f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserBatchUpdateStatusReq.java @@ -0,0 +1,34 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 批量修改施工人员状态请求对象 + * + * @author lilemy + * @date 2025/4/1 17:11 + */ +@Data +public class SubConstructionUserBatchUpdateStatusReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3756685899069233313L; + + /** + * 主键id列表 + */ + @NotNull(message = "主键id列表不能为空") + private List idList; + + /** + * 状态(0在职 1离职) + */ + @NotNull(message = "状态不能为空") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserChangeProjectReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserChangeProjectReq.java new file mode 100644 index 0000000..9e95b14 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserChangeProjectReq.java @@ -0,0 +1,37 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 施工人员迁移请求对象 + * + * @author lilemy + * @date 2025/3/31 14:50 + */ +@Data +public class SubConstructionUserChangeProjectReq implements Serializable { + @Serial + private static final long serialVersionUID = -2638471692809830501L; + + /** + * 主键 + */ + @NotNull(message = "主键id不能为空") + private Long id; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 分包公司id + */ + @NotNull(message = "分包公司id不能为空") + private Long contractorId; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserCreateReq.java new file mode 100644 index 0000000..313b26b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserCreateReq.java @@ -0,0 +1,153 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class SubConstructionUserCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 人脸照 + */ + private String facePic; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 状态(0在职 1离职) + */ + private String status; + + /** + * 是否代打 + */ + private String isPinch; + + /** + * 联系电话 + */ + private String phone; + + /** + * 0:保密 1:男 2女 + */ + private String sex; + + /** + * 民族 + */ + private String nation; + + /** + * 身份证正面图片 + */ + private String sfzFrontPic; + + /** + * 身份证反面图片 + */ + private String sfzBackPic; + + /** + * 身份证号码 + */ + private String sfzNumber; + + /** + * 身份证有效开始期 + */ + private String sfzStart; + + /** + * 身份证有效结束期 + */ + private String sfzEnd; + + /** + * 身份证地址 + */ + private String sfzSite; + + /** + * 身份证出生日期 + */ + private String sfzBirth; + + /** + * 籍贯 + */ + private String nativePlace; + + /** + * 银行卡图片 + */ + private String yhkPic; + + /** + * 银行卡号 + */ + private String yhkNumber; + + /** + * 开户行 + */ + private String yhkOpeningBank; + + /** + * 持卡人 + */ + private String yhkCardholder; + + /** + * 工种(字典type_of_work) + */ + private String typeOfWork; + + /** + * 工资计量单位 + */ + private String wageMeasureUnit; + + /** + * 特种工作证图片 + */ + private String specialWorkPic; + + /** + * 打卡(0启用打卡 1禁止打卡) + */ + private String clock; + + /** + * 薪水 + */ + private Long salary; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserGisReq.java new file mode 100644 index 0000000..d711716 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserGisReq.java @@ -0,0 +1,25 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 9:40 + */ +@Data +public class SubConstructionUserGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2487357135566518535L; + + /** + * 项目id + */ + @NotNull(message = "项目主键不能为空") + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserQueryReq.java new file mode 100644 index 0000000..e153d82 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserQueryReq.java @@ -0,0 +1,108 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class SubConstructionUserQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3252651952758479341L; + + /** + * 主键id + */ + private Long id; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 不在班组id + */ + private Long notTeamId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 状态(0在职 1离职) + */ + private String status; + + /** + * 是否代打 + */ + private String isPinch; + + /** + * 0:保密 1:男 2女 + */ + private String sex; + + /** + * 民族 + */ + private String nation; + + /** + * 籍贯 + */ + private String nativePlace; + + /** + * 开户行 + */ + private String yhkOpeningBank; + + /** + * 工种(字典type_of_work) + */ + private String typeOfWork; + + /** + * 工资计量单位 + */ + private String wageMeasureUnit; + + /** + * 打卡(0启用打卡 1禁止打卡) + */ + private String clock; + + /** + * 用户角色 + */ + private String userRole; + + /** + * 不是用户角色 + */ + private String notUserRole; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateClockReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateClockReq.java new file mode 100644 index 0000000..ebcbd61 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateClockReq.java @@ -0,0 +1,32 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 更新施工人员打卡状态 + * + * @author lilemy + * @date 2025/4/2 9:14 + */ +@Data +public class SubConstructionUserUpdateClockReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5803749609177642435L; + + /** + * 用户id + */ + @NotNull(message = "用户id不能为空") + private Long id; + + /** + * 打卡(0启用打卡 1禁止打卡) + */ + @NotNull(message = "打卡状态不能为空") + private String clock; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateReq.java new file mode 100644 index 0000000..434ed44 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateReq.java @@ -0,0 +1,150 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class SubConstructionUserUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8022860866890925958L; + + /** + * 主键id + */ + @NotNull(message = "主键id不能为空") + private Long id; + + /** + * 人脸照 + */ + private String facePic; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 状态(0在职 1离职) + */ + private String status; + + /** + * 是否代打 + */ + private String isPinch; + + /** + * 联系电话 + */ + private String phone; + + /** + * 0:保密 1:男 2女 + */ + private String sex; + + /** + * 民族 + */ + private String nation; + + /** + * 身份证正面图片 + */ + private String sfzFrontPic; + + /** + * 身份证反面图片 + */ + private String sfzBackPic; + + /** + * 身份证有效开始期 + */ + private String sfzStart; + + /** + * 身份证有效结束期 + */ + private String sfzEnd; + + /** + * 身份证地址 + */ + private String sfzSite; + + /** + * 身份证出生日期 + */ + private String sfzBirth; + + /** + * 籍贯 + */ + private String nativePlace; + + /** + * 银行卡图片 + */ + private String yhkPic; + + /** + * 开户行 + */ + private String yhkOpeningBank; + + /** + * 持卡人 + */ + private String yhkCardholder; + + /** + * 工种(字典type_of_work) + */ + private String typeOfWork; + + /** + * 工资计量单位 + */ + private String wageMeasureUnit; + + /** + * 特种工作证图片 + */ + private String specialWorkPic; + + /** + * 打卡(0启用打卡 1禁止打卡) + */ + private String clock; + + /** + * 薪水 + */ + private Long salary; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateSalaryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateSalaryReq.java new file mode 100644 index 0000000..7a3d3f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserUpdateSalaryReq.java @@ -0,0 +1,30 @@ +package org.dromara.contractor.domain.dto.constructionuser; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/2 11:35 + */ +@Data +public class SubConstructionUserUpdateSalaryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -1300674086812422523L; + + /** + * 主键id + */ + @NotNull(message = "主键不能为空") + private Long id; + + /** + * 薪水 + */ + private Long salary; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileQueryReq.java new file mode 100644 index 0000000..8b6d048 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.contractor.domain.dto.constructionuserfile; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/1 10:06 + */ +@Data +public class SubConstructionUserFileQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 552027602186820020L; + + /** + * 主键id + */ + private Long id; + + /** + * 用户id + */ + private Long userId; + + /** + * 文件类型 + */ + private String fileType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileReq.java new file mode 100644 index 0000000..0afc27a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileReq.java @@ -0,0 +1,26 @@ +package org.dromara.contractor.domain.dto.constructionuserfile; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author lilemy + * @date 2025/4/1 15:21 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SubConstructionUserFileReq { + + /** + * 文件类型 + */ + private String fileType; + + /** + * 文件id + */ + private String fileId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileSaveReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileSaveReq.java new file mode 100644 index 0000000..40f997b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileSaveReq.java @@ -0,0 +1,29 @@ +package org.dromara.contractor.domain.dto.constructionuserfile; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/1 10:01 + */ +@Data +public class SubConstructionUserFileSaveReq implements Serializable { + + @Serial + private static final long serialVersionUID = 4319620202781413796L; + + /** + * 用户id + */ + private Long userId; + + /** + * 文件列表 + */ + private List fileList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileTemplateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileTemplateReq.java new file mode 100644 index 0000000..42499af --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuserfile/SubConstructionUserFileTemplateReq.java @@ -0,0 +1,56 @@ +package org.dromara.contractor.domain.dto.constructionuserfile; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/9 9:25 + */ +@Data +public class SubConstructionUserFileTemplateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6895109153171403950L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 用户名 + */ + private String userName; + + /** + * 分包单位id + */ + private Long contractorId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 工种 + */ + private String typeOfWork; + + /** + * 打卡 + */ + private String clock; + + /** + * 用户id列表 + */ + private List userIdList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorCreateReq.java new file mode 100644 index 0000000..e896fb2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorCreateReq.java @@ -0,0 +1,64 @@ +package org.dromara.contractor.domain.dto.contractor; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class SubContractorCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 公司名称 + */ + private String name; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人联系电话 + */ + private String principalPhone; + + /** + * 管理人 + */ + private String custodian; + + /** + * 管理人联系电话 + */ + private String custodianPhone; + + /** + * 公司相关文件 + */ + private Map fileMap; + + /** + * 分包类型 + */ + private String contractorType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorQueryReq.java new file mode 100644 index 0000000..39d5581 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorQueryReq.java @@ -0,0 +1,63 @@ +package org.dromara.contractor.domain.dto.contractor; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class SubContractorQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3252651952758479341L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 公司名称 + */ + private String name; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人联系电话 + */ + private String principalPhone; + + /** + * 管理人 + */ + private String custodian; + + /** + * 管理人联系电话 + */ + private String custodianPhone; + + /** + * 分包类型 + */ + private String contractorType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorUpdateReq.java new file mode 100644 index 0000000..d7c9aec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractor/SubContractorUpdateReq.java @@ -0,0 +1,69 @@ +package org.dromara.contractor.domain.dto.contractor; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class SubContractorUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8022860866890925958L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 公司名称 + */ + private String name; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人联系电话 + */ + private String principalPhone; + + /** + * 管理人 + */ + private String custodian; + + /** + * 管理人联系电话 + */ + private String custodianPhone; + + /** + * 分包类型 + */ + private String contractorType; + + /** + * 公司相关文件 + */ + private Map fileMap; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialCreateReq.java new file mode 100644 index 0000000..0b14c62 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialCreateReq.java @@ -0,0 +1,58 @@ +package org.dromara.contractor.domain.dto.contractormaterial; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/27 14:18 + */ +@Data +public class SubContractorMaterialCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5984785792671407395L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 物料名称 + */ + private String materialName; + + /** + * 物料类型 + */ + private String materialType; + + /** + * 物料型号 + */ + private String materialModel; + + /** + * 物料单位 + */ + private String materialUnit; + + /** + * 文件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialQueryReq.java new file mode 100644 index 0000000..53344a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.contractor.domain.dto.contractormaterial; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/27 14:20 + */ +@Data +public class SubContractorMaterialQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 640474123189874263L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 物料名称 + */ + private String materialName; + + /** + * 物料类型 + */ + private String materialType; + + /** + * 物料型号 + */ + private String materialModel; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialUpdateReq.java new file mode 100644 index 0000000..0beb920 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterial/SubContractorMaterialUpdateReq.java @@ -0,0 +1,63 @@ +package org.dromara.contractor.domain.dto.contractormaterial; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/27 14:20 + */ +@Data +public class SubContractorMaterialUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4488270790673814590L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 物料名称 + */ + private String materialName; + + /** + * 物料类型 + */ + private String materialType; + + /** + * 物料型号 + */ + private String materialModel; + + /** + * 物料单位 + */ + private String materialUnit; + + /** + * 文件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordCreateReq.java new file mode 100644 index 0000000..c2ed12f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordCreateReq.java @@ -0,0 +1,57 @@ +package org.dromara.contractor.domain.dto.contractormaterialrecord; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/27 14:35 + */ +@Data +public class SubContractorMaterialRecordCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2325294573057427849L; + + /** + * 物料id + */ + private Long contractorMaterialId; + + /** + * 记录类型(1到货计划 2使用情况) + */ + private String recordType; + + /** + * 记录时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date recordTime; + + /** + * 数量 + */ + private BigDecimal recordNumber; + + /** + * 使用位置或构件部位(使用情况) + */ + private String usedPosition; + + /** + * 相关附件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordQueryReq.java new file mode 100644 index 0000000..bc41668 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.contractor.domain.dto.contractormaterialrecord; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/27 14:36 + */ +@Data +public class SubContractorMaterialRecordQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5817912360176038347L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 物料id + */ + private Long contractorMaterialId; + + /** + * 记录类型(1到货计划 2使用情况) + */ + private String recordType; + + /** + * 使用位置或构件部位(使用情况) + */ + private String usedPosition; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordUpdateReq.java new file mode 100644 index 0000000..ba7c43c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractormaterialrecord/SubContractorMaterialRecordUpdateReq.java @@ -0,0 +1,62 @@ +package org.dromara.contractor.domain.dto.contractormaterialrecord; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/27 14:36 + */ +@Data +public class SubContractorMaterialRecordUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6087029523445301396L; + + /** + * 主键id + */ + private Long id; + + /** + * 物料id + */ + private Long contractorMaterialId; + + /** + * 记录类型(1到货计划 2使用情况) + */ + private String recordType; + + /** + * 记录时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date recordTime; + + /** + * 数量 + */ + private BigDecimal recordNumber; + + /** + * 使用位置或构件部位(使用情况) + */ + private String usedPosition; + + /** + * 相关附件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolCreateReq.java new file mode 100644 index 0000000..a754efa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolCreateReq.java @@ -0,0 +1,59 @@ +package org.dromara.contractor.domain.dto.contractortool; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author lilemy + * @date 2025/6/26 15:26 + */ +@Data +public class SubContractorToolCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -148571725751082526L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 工具名称 + */ + private String toolName; + + /** + * 工具类型 + */ + private String toolType; + + /** + * 工具型号 + */ + private String toolModel; + + /** + * 工具数量 + */ + private BigDecimal toolNumber; + + /** + * 文件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolQueryReq.java new file mode 100644 index 0000000..99bb648 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.contractor.domain.dto.contractortool; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 15:26 + */ +@Data +public class SubContractorToolQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -654101391027815665L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 工具名称 + */ + private String toolName; + + /** + * 工具类型 + */ + private String toolType; + + /** + * 工具型号 + */ + private String toolModel; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolUpdateReq.java new file mode 100644 index 0000000..875836f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortool/SubContractorToolUpdateReq.java @@ -0,0 +1,64 @@ +package org.dromara.contractor.domain.dto.contractortool; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author lilemy + * @date 2025/6/26 15:26 + */ +@Data +public class SubContractorToolUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6147452720586538283L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 工具名称 + */ + private String toolName; + + /** + * 工具类型 + */ + private String toolType; + + /** + * 工具型号 + */ + private String toolModel; + + /** + * 工具数量 + */ + private BigDecimal toolNumber; + + /** + * 文件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordCreateReq.java new file mode 100644 index 0000000..f6c2656 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordCreateReq.java @@ -0,0 +1,67 @@ +package org.dromara.contractor.domain.dto.contractortoolentry; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/26 17:52 + */ +@Data +public class SubContractorToolRecordCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8161480499208093948L; + + /** + * 分包方工器具id + */ + private Long contractorToolId; + + /** + * 记录类型(1进场 2出场) + */ + private String recordType; + + /** + * 记录工器具数量 + */ + private BigDecimal recordNumber; + + /** + * 检测编号 + */ + private String checkNum; + + /** + * 检测部门 + */ + private String checkDept; + + /** + * 检测时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date checkTime; + + /** + * 合格证 + */ + private String certificate; + + /** + * 备注 + */ + private String remark; + + /** + * 记录时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date recordTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordQueryReq.java new file mode 100644 index 0000000..0220141 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordQueryReq.java @@ -0,0 +1,48 @@ +package org.dromara.contractor.domain.dto.contractortoolentry; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 17:52 + */ +@Data +public class SubContractorToolRecordQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5521479525294608178L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 分包方工器具id + */ + private Long contractorToolId; + + /** + * 检测编号 + */ + private String checkNum; + + /** + * 检测部门 + */ + private String checkDept; + + /** + * 记录类型 + */ + private String recordType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordUpdateReq.java new file mode 100644 index 0000000..4c97674 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/contractortoolentry/SubContractorToolRecordUpdateReq.java @@ -0,0 +1,63 @@ +package org.dromara.contractor.domain.dto.contractortoolentry; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/26 17:52 + */ +@Data +public class SubContractorToolRecordUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5280254073638207854L; + + /** + * 主键id + */ + private Long id; + + /** + * 记录工器具数量 + */ + private BigDecimal recordNumber; + + /** + * 检测编号 + */ + private String checkNum; + + /** + * 检测部门 + */ + private String checkDept; + + /** + * 检测时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date checkTime; + + /** + * 合格证 + */ + private String certificate; + + /** + * 备注 + */ + private String remark; + + /** + * 记录时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date recordTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractCreateReq.java new file mode 100644 index 0000000..62a1199 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractCreateReq.java @@ -0,0 +1,67 @@ +package org.dromara.contractor.domain.dto.subcontract; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/25 16:36 + */ +@Data +public class SubSubcontractCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3386090526440868496L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 合同文件id + */ + private Long contractFileId; + + /** + * 合同编号 + */ + private String contractNumber; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 合同类型 + */ + private String contractType; + + /** + * 合同金额 + */ + private BigDecimal contractAmount; + + /** + * 合同时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date contractTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractQueryReq.java new file mode 100644 index 0000000..8fd8659 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.contractor.domain.dto.subcontract; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/25 16:37 + */ +@Data +public class SubSubcontractQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3731492397283570840L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 合同编号 + */ + private String contractNumber; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 合同类型 + */ + private String contractType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractUpdateReq.java new file mode 100644 index 0000000..ae2f8e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/subcontract/SubSubcontractUpdateReq.java @@ -0,0 +1,72 @@ +package org.dromara.contractor.domain.dto.subcontract; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/25 16:37 + */ +@Data +public class SubSubcontractUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5617446079713109912L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 合同文件id + */ + private Long contractFileId; + + /** + * 合同编号 + */ + private String contractNumber; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 合同类型 + */ + private String contractType; + + /** + * 合同金额 + */ + private BigDecimal contractAmount; + + /** + * 合同时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date contractTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/enums/SubConstructionUserFileStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/enums/SubConstructionUserFileStatusEnum.java new file mode 100644 index 0000000..7b923f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/enums/SubConstructionUserFileStatusEnum.java @@ -0,0 +1,25 @@ +package org.dromara.contractor.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/3 17:47 + */ +@Getter +public enum SubConstructionUserFileStatusEnum { + + NOUPLOAD("未上传", "1"), + PARTUPLOAD("部分上传", "2"), + UPLOAD("已上传", "3"); + + private final String text; + + private final String value; + + SubConstructionUserFileStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/enums/SubContractorRecordEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/enums/SubContractorRecordEnum.java new file mode 100644 index 0000000..8df2d92 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/enums/SubContractorRecordEnum.java @@ -0,0 +1,23 @@ +package org.dromara.contractor.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/6/27 10:30 + */ +@Getter +public enum SubContractorRecordEnum { + + PUT("进场/入库", "1"), + OUT("出场/出库", "2"); + + private final String text; + + private final String value; + + SubContractorRecordEnum(String text, String value) { + this.text = text; + this.value = value; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/exportvo/BusConstructionUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/exportvo/BusConstructionUserExportVo.java new file mode 100644 index 0000000..c69bfcf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/exportvo/BusConstructionUserExportVo.java @@ -0,0 +1,127 @@ +package org.dromara.contractor.domain.exportvo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.contractor.domain.SubConstructionUser; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/2 14:46 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubConstructionUser.class) +public class BusConstructionUserExportVo implements Serializable { + + @Serial + private static final long serialVersionUID = -7147024838012426821L; + + /** + * 姓名 + */ + @ExcelProperty(value = "姓名") + private String userName; + + /** + * 项目名称 + */ + @ExcelProperty(value = "项目") + private String projectName; + + /** + * 分包公司 + */ + @ExcelProperty(value = "分包公司") + private String contractorName; + + /** + * 班组 + */ + @ExcelProperty(value = "班组") + private String teamName; + + /** + * 状态(0在职 1离职) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=在职,1=离职") + private String status; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String phone; + + /** + * 0:保密 1:男 2女 + */ + @ExcelProperty(value = "性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_sex_type") + private String sex; + + /** + * 民族 + */ + @ExcelProperty(value = "民族") + private String nation; + + /** + * 身份证号码 + */ + @ExcelProperty(value = "身份证号码") + private String sfzNumber; + + /** + * 身份证地址 + */ + @ExcelProperty(value = "身份证地址") + private String sfzSite; + + /** + * 银行卡号 + */ + @ExcelProperty(value = "银行卡号") + private String yhkNumber; + + /** + * 工种 + */ + @ExcelProperty(value = "工种", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "type_of_work") + private String typeOfWork; + + /** + * 工资计量单位 + */ + @ExcelProperty(value = "工资计量单位", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "wage_measure_unit_type") + private String wageMeasureUnit; + + /** + * 入场时间 + */ + @ExcelProperty(value = "入场时间") + private Date entryDate; + + /** + * 离场时间 + */ + @ExcelProperty(value = "离场时间") + private Date leaveDate; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceByDay.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceByDay.java new file mode 100644 index 0000000..9035557 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceByDay.java @@ -0,0 +1,71 @@ +package org.dromara.contractor.domain.vo.constructionuser; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.enums.BusAttendanceCommuterEnum; + +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/8 17:38 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SubConstructionUserAttendanceByDay { + + /** + * 上班打卡时间 + */ + private Date upClockTime; + + /** + * 上班打卡图片id + */ + private Long upClockPicId; + + /** + * 上班打卡图片 + */ + private String upClockPic; + + /** + * 下班打卡图片id + */ + private Long downClockPicId; + /** + * 下班打卡图片 + */ + private String downClockPic; + + /** + * 下班打卡时间 + */ + private Date downClockTime; + + public static SubConstructionUserAttendanceByDay build(List attendanceList) { + if (attendanceList == null) { + return null; + } + SubConstructionUserAttendanceByDay constructionUserAttendanceByDay = new SubConstructionUserAttendanceByDay(); + for (BusAttendance attendance : attendanceList) { + if (attendance.getCommuter().equals(BusAttendanceCommuterEnum.CLOCKIN.getValue())) { + constructionUserAttendanceByDay.setUpClockTime(attendance.getClockTime()); + if (attendance.getFacePic() != null) { + constructionUserAttendanceByDay.setUpClockPicId(Long.valueOf(attendance.getFacePic())); + } + } else if (attendance.getCommuter().equals(BusAttendanceCommuterEnum.CLOCKOUT.getValue())) { + constructionUserAttendanceByDay.setDownClockTime(attendance.getClockTime()); + if (attendance.getFacePic() != null) { + constructionUserAttendanceByDay.setDownClockPicId(Long.valueOf(attendance.getFacePic())); + } + } + } + return constructionUserAttendanceByDay; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceMonthVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceMonthVo.java new file mode 100644 index 0000000..e8bb462 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceMonthVo.java @@ -0,0 +1,43 @@ +package org.dromara.contractor.domain.vo.constructionuser; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/7 15:06 + */ +@Data +public class SubConstructionUserAttendanceMonthVo implements Serializable { + + @Serial + private static final long serialVersionUID = -413447291128760025L; + + /** + * 主键id + */ + private Long id; + + /** + * 打卡日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd", + timezone = "GMT+8") + private Date clockDate; + + /** + * 当天打卡状态 + */ + private String Status; + + /** + * 当天打卡记录 + */ + private SubConstructionUserAttendanceByDay clockList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceTotalVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceTotalVo.java new file mode 100644 index 0000000..2319757 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserAttendanceTotalVo.java @@ -0,0 +1,69 @@ +package org.dromara.contractor.domain.vo.constructionuser; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * @author lilemy + * @date 2025/4/7 10:16 + */ +@Data +public class SubConstructionUserAttendanceTotalVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1335094839733429171L; + + /** + * 主键id + */ + private Long id; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 班组id + */ + private Long teamId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 工种 + */ + private String typeOfWork; + + /** + * 出勤天数 + */ + private Integer attendanceDays; + + /** + * 迟到天数 + */ + private Integer lateDays; + + /** + * 早退天数 + */ + private Integer leaveEarlyDays; + + /** + * 缺卡天数 + */ + private Integer unClockDays; + + /** + * 请假天数 + */ + private Integer leaveDays; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserGisVo.java new file mode 100644 index 0000000..851be3e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserGisVo.java @@ -0,0 +1,33 @@ +package org.dromara.contractor.domain.vo.constructionuser; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 9:33 + */ +@Data +public class SubConstructionUserGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -3496633845665259321L; + + /** + * 施工人员数量 + */ + private Long peopleCount; + + /** + * 出勤人员数量 + */ + private Long attendanceCount; + + /** + * 出勤率 + */ + private String attendanceRate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserVo.java new file mode 100644 index 0000000..0bcd700 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserVo.java @@ -0,0 +1,262 @@ +package org.dromara.contractor.domain.vo.constructionuser; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 施工人员视图对象 bus_construction_user + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubConstructionUser.class) +public class SubConstructionUserVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 人脸照 + */ + @ExcelProperty(value = "人脸照") + private String facePic; + + /** + * 人脸照 url + */ + @ExcelProperty(value = "人脸照 url") + private String facePicUrl; + + /** + * 人员姓名 + */ + @ExcelProperty(value = "人员姓名") + private String userName; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 分包公司id + */ + @ExcelProperty(value = "分包公司id") + private Long contractorId; + + /** + * 分包公司 + */ + private SubContractorVo contractorVo; + + /** + * 班组id + */ + @ExcelProperty(value = "班组id") + private Long teamId; + + /** + * 班组名称 + */ + @ExcelProperty(value = "班组名称") + private String teamName; + + /** + * 状态(0在职 1离职) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=在职,1=离职") + private String status; + + /** + * 是否代打 + */ + @ExcelProperty(value = "是否代打") + private String isPinch; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String phone; + + /** + * 0:保密 1:男 2女 + */ + @ExcelProperty(value = "性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_sex_type") + private String sex; + + /** + * 民族 + */ + @ExcelProperty(value = "民族") + private String nation; + + /** + * 身份证正面图片 + */ + @ExcelProperty(value = "身份证正面图片") + private String sfzFrontPic; + + /** + * 身份证反面图片 + */ + @ExcelProperty(value = "身份证反面图片") + private String sfzBackPic; + + /** + * 身份证号码 + */ + @ExcelProperty(value = "身份证号码") + private String sfzNumber; + + /** + * 身份证有效开始期 + */ + @ExcelProperty(value = "身份证有效开始期") + private String sfzStart; + + /** + * 身份证有效结束期 + */ + @ExcelProperty(value = "身份证有效结束期") + private String sfzEnd; + + /** + * 身份证地址 + */ + @ExcelProperty(value = "身份证地址") + private String sfzSite; + + /** + * 身份证出生日期 + */ + @ExcelProperty(value = "身份证出生日期") + private String sfzBirth; + + /** + * 籍贯 + */ + @ExcelProperty(value = "籍贯") + private String nativePlace; + + /** + * 银行卡图片 + */ + @ExcelProperty(value = "银行卡图片") + private String yhkPic; + + /** + * 银行卡号 + */ + @ExcelProperty(value = "银行卡号") + private String yhkNumber; + + /** + * 开户行 + */ + @ExcelProperty(value = "开户行") + private String yhkOpeningBank; + + /** + * 持卡人 + */ + @ExcelProperty(value = "持卡人") + private String yhkCardholder; + + /** + * 工种 + */ + @ExcelProperty(value = "工种", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "type_of_work") + private String typeOfWork; + + /** + * 工资计量单位 + */ + @ExcelProperty(value = "工资计量单位", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "wage_measure_unit_type") + private String wageMeasureUnit; + + /** + * 特种工作证图片 + */ + @ExcelProperty(value = "特种工作证图片") + private String specialWorkPic; + + /** + * 打卡(0启用打卡 1禁止打卡) + */ + @ExcelProperty(value = "打卡(0启用打卡 1禁止打卡)") + private String clock; + + /** + * 入场时间 + */ + @ExcelProperty(value = "入场时间") + private Date entryDate; + + /** + * 离场时间 + */ + @ExcelProperty(value = "离场时间") + private Date leaveDate; + + /** + * 标准薪水 + */ + @ExcelProperty(value = "标准薪水") + private Long standardSalary; + + /** + * 薪水 + */ + @ExcelProperty(value = "薪水") + private Long salary; + + /** + * 用户角色 + */ + private String userRole; + + /** + * 文件上传状态 + */ + @ExcelProperty(value = "文件上传状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_file_status_type") + private String fileUploadStatus; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuserfile/SubConstructionUserFileVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuserfile/SubConstructionUserFileVo.java new file mode 100644 index 0000000..befb215 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuserfile/SubConstructionUserFileVo.java @@ -0,0 +1,60 @@ +package org.dromara.contractor.domain.vo.constructionuserfile; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.contractor.domain.SubConstructionUserFile; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 施工人员文件存储视图对象 bus_construction_user_file + * + * @author lilemy + * @date 2025-04-01 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubConstructionUserFile.class) +public class SubConstructionUserFileVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 文件类型 + */ + @ExcelProperty(value = "文件类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_file_type") + private String fileType; + + /** + * 文件路径 + */ + @ExcelProperty(value = "文件路径") + private String path; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractor/SubContractorVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractor/SubContractorVo.java new file mode 100644 index 0000000..7b666db --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractor/SubContractorVo.java @@ -0,0 +1,94 @@ +package org.dromara.contractor.domain.vo.contractor; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.contractor.domain.SubContractor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + + +/** + * 分包单位视图对象 sub_contractor + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubContractor.class) +public class SubContractorVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 公司名称 + */ + @ExcelProperty(value = "公司名称") + private String name; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String principal; + + /** + * 负责人联系电话 + */ + @ExcelProperty(value = "负责人联系电话") + private String principalPhone; + + /** + * 管理人 + */ + @ExcelProperty(value = "管理人") + private String custodian; + + /** + * 管理人联系电话 + */ + @ExcelProperty(value = "管理人联系电话") + private String custodianPhone; + + /** + * 分包类型 + */ + private String contractorType; + + /** + * 公司相关文件 + */ + @ExcelProperty(value = "公司相关文件") + private Map fileMap; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractormaterial/SubContractorMaterialVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractormaterial/SubContractorMaterialVo.java new file mode 100644 index 0000000..ee2f7f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractormaterial/SubContractorMaterialVo.java @@ -0,0 +1,97 @@ +package org.dromara.contractor.domain.vo.contractormaterial; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableId; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.contractor.domain.SubContractorMaterial; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + + +/** + * 分包方物料视图对象 sub_contractor_material + * + * @author lilemy + * @date 2025-06-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubContractorMaterial.class) +public class SubContractorMaterialVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 分包方id + */ + @ExcelProperty(value = "分包方id") + private Long contractorId; + + /** + * 分包方名称 + */ + private String contractorName; + + /** + * 物料名称 + */ + @ExcelProperty(value = "物料名称") + private String materialName; + + /** + * 物料类型 + */ + @ExcelProperty(value = "物料类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "contractor_material_type") + private String materialType; + + /** + * 物料型号 + */ + @ExcelProperty(value = "物料型号") + private String materialModel; + + /** + * 物料数量 + */ + @ExcelProperty(value = "物料数量") + private BigDecimal materialNumber; + + /** + * 物料单位 + */ + @ExcelProperty(value = "物料单位") + private String materialUnit; + + /** + * 文件 + */ + @ExcelProperty(value = "文件") + private String file; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractormaterialrecord/SubContractorMaterialRecordVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractormaterialrecord/SubContractorMaterialRecordVo.java new file mode 100644 index 0000000..2968c68 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractormaterialrecord/SubContractorMaterialRecordVo.java @@ -0,0 +1,109 @@ +package org.dromara.contractor.domain.vo.contractormaterialrecord; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.contractor.domain.SubContractorMaterialRecord; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + + +/** + * 分包方物料记录视图对象 sub_contractor_material_record + * + * @author lilemy + * @date 2025-06-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubContractorMaterialRecord.class) +public class SubContractorMaterialRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 分包方id + */ + @ExcelProperty(value = "分包方id") + private Long contractorId; + + /** + * 分包方名称 + */ + private String contractorName; + + /** + * 物料id + */ + @ExcelProperty(value = "物料id") + private Long contractorMaterialId; + + /** + * 物料名称 + */ + private String contractorMaterialName; + + /** + * 记录类型(1到货计划 2使用情况) + */ + @ExcelProperty(value = "记录类型(1到货计划 2使用情况)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "contractor_material_record_type") + private String recordType; + + /** + * 记录时间 + */ + @ExcelProperty(value = "记录时间") + private Date recordTime; + + /** + * 数量 + */ + @ExcelProperty(value = "数量") + private BigDecimal recordNumber; + + /** + * 剩余数量(到货 使用) + */ + @ExcelProperty(value = "剩余数量(到货 使用)") + private BigDecimal remainingNumber; + + /** + * 使用位置或构件部位(使用情况) + */ + @ExcelProperty(value = "使用位置或构件部位(使用情况)") + private String usedPosition; + + /** + * 相关附件 + */ + @ExcelProperty(value = "相关附件") + private String file; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractortool/SubContractorToolVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractortool/SubContractorToolVo.java new file mode 100644 index 0000000..8ef443b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractortool/SubContractorToolVo.java @@ -0,0 +1,91 @@ +package org.dromara.contractor.domain.vo.contractortool; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.contractor.domain.SubContractorTool; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + + +/** + * 分包方工器具视图对象 sub_contractor_tool + * + * @author lilemy + * @date 2025-06-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubContractorTool.class) +public class SubContractorToolVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 分包方id + */ + @ExcelProperty(value = "分包方id") + private Long contractorId; + + /** + * 分包方名称 + */ + private String contractorName; + + /** + * 工具名称 + */ + @ExcelProperty(value = "工具名称") + private String toolName; + + /** + * 工具类型 + */ + @ExcelProperty(value = "工具类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "contractor_tool_type") + private String toolType; + + /** + * 工具型号 + */ + @ExcelProperty(value = "工具型号") + private String toolModel; + + /** + * 工具数量 + */ + @ExcelProperty(value = "工具数量") + private BigDecimal toolNumber; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractortoolentry/SubContractorToolRecordVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractortoolentry/SubContractorToolRecordVo.java new file mode 100644 index 0000000..9e5c281 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/contractortoolentry/SubContractorToolRecordVo.java @@ -0,0 +1,120 @@ +package org.dromara.contractor.domain.vo.contractortoolentry; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.contractor.domain.SubContractorToolRecord; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + + +/** + * 分包方工器具记录视图对象 sub_contractor_tool_entry + * + * @author lilemy + * @date 2025-06-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SubContractorToolRecord.class) +public class SubContractorToolRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 分包方id + */ + @ExcelProperty(value = "分包方id") + private Long contractorId; + + /** + * 分包方名称 + */ + private String contractorName; + + /** + * 分包方工器具id + */ + @ExcelProperty(value = "分包方工器具id") + private Long contractorToolId; + + /** + * 分包方工器具名称 + */ + private String contractorToolName; + + /** + * 记录类型(1进场 2出场) + */ + @ExcelProperty(value = "记录类型(1进场 2出场)") + private String recordType; + + /** + * 记录工器具数量 + */ + @ExcelProperty(value = "记录工器具数量") + private BigDecimal recordNumber; + + /** + * 剩余数量 + */ + @ExcelProperty(value = "剩余数量") + private BigDecimal remainingNumber; + + /** + * 检测编号 + */ + @ExcelProperty(value = "检测编号") + private String checkNum; + + /** + * 检测部门 + */ + @ExcelProperty(value = "检测部门") + private String checkDept; + + /** + * 检测时间 + */ + @ExcelProperty(value = "检测时间") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date checkTime; + + /** + * 合格证 + */ + @ExcelProperty(value = "合格证") + private String certificate; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 记录时间 + */ + @ExcelProperty(value = "记录时间") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date recordTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/subcontract/SubSubcontractVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/subcontract/SubSubcontractVo.java new file mode 100644 index 0000000..744c8bd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/subcontract/SubSubcontractVo.java @@ -0,0 +1,81 @@ +package org.dromara.contractor.domain.vo.subcontract; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.contractor.domain.SubSubcontract; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + + +/** + * 分包合同视图对象 sub_subcontract + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@AutoMapper(target = SubSubcontract.class) +public class SubSubcontractVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包方id + */ + private Long contractorId; + + /** + * 分包方名称 + */ + private String contractorName; + + /** + * 合同文件id + */ + private Long contractFileId; + + /** + * 合同编号 + */ + private String contractNumber; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 合同类型 + */ + private String contractType; + + /** + * 合同金额 + */ + private BigDecimal contractAmount; + + /** + * 合同时间 + */ + private Date contractTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/interceptor/ContractorInterceptor.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/interceptor/ContractorInterceptor.java new file mode 100644 index 0000000..ea1d8d6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/interceptor/ContractorInterceptor.java @@ -0,0 +1,84 @@ +package org.dromara.contractor.interceptor; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.filter.RepeatedlyRequestWrapper; +import org.dromara.system.domain.enums.SysDeptTypeEnum; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.service.ISysDeptService; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.io.BufferedReader; +import java.util.Arrays; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/7/21 15:57 + */ +@Component +public class ContractorInterceptor implements HandlerInterceptor { + + @Resource + private ISysDeptService deptService; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + Long deptId = LoginHelper.getDeptId(); + if (ObjectUtil.isNotNull(deptId)) { + SysDeptVo deptVo = deptService.selectDeptById(deptId); + if (deptVo.getDeptType().equals(SysDeptTypeEnum.CONTRACT.getCode())) { + // 在请求前处理逻辑 + System.out.println("拦截到了 /contractor/** 请求:" + request.getRequestURI()); + Long contractorId = deptVo.getContractorId(); + if (isJsonRequest(request)) { + String jsonParam = ""; + if (request instanceof RepeatedlyRequestWrapper) { + BufferedReader reader = request.getReader(); + jsonParam = IoUtil.read(reader); + } + JSONObject jsonObject = JSONUtil.parseObj(jsonParam); + contractorId = jsonObject.getLong("contractorId"); + } else { + Map parameterMap = request.getParameterMap(); + if (MapUtil.isNotEmpty(parameterMap)) { + String[] contractorIds = parameterMap.get("contractorId"); + if (contractorIds != null && contractorIds.length != 0 && StringUtils.isNotBlank(contractorIds[0])) { + contractorId = Long.valueOf(Arrays.asList(contractorIds).getFirst()); + } + } + } + if (ObjectUtil.isNull(contractorId) || !contractorId.equals(deptVo.getContractorId())) { + throw new ServiceException("无访问权限"); + } + } + } + return true; // 返回 true 放行,false 拦截 + } + + /** + * 判断本次请求的数据类型是否为json + * + * @param request request + * @return boolean + */ + private boolean isJsonRequest(HttpServletRequest request) { + String contentType = request.getContentType(); + if (contentType != null) { + return StringUtils.startsWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE); + } + return false; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubConstructionUserFileMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubConstructionUserFileMapper.java new file mode 100644 index 0000000..af45eca --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubConstructionUserFileMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.contractor.domain.SubConstructionUserFile; +import org.dromara.contractor.domain.vo.constructionuserfile.SubConstructionUserFileVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 施工人员文件存储Mapper接口 + * + * @author lilemy + * @date 2025-04-01 + */ +public interface SubConstructionUserFileMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubConstructionUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubConstructionUserMapper.java new file mode 100644 index 0000000..8b02f94 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubConstructionUserMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 施工人员Mapper接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface SubConstructionUserMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMapper.java new file mode 100644 index 0000000..927e329 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; + +/** + * 分包单位Mapper接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface SubContractorMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMaterialMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMaterialMapper.java new file mode 100644 index 0000000..18caade --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMaterialMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.contractor.domain.SubContractorMaterial; +import org.dromara.contractor.domain.vo.contractormaterial.SubContractorMaterialVo; + +/** + * 分包方物料Mapper接口 + * + * @author lilemy + * @date 2025-06-27 + */ +public interface SubContractorMaterialMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMaterialRecordMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMaterialRecordMapper.java new file mode 100644 index 0000000..1c9cb9e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorMaterialRecordMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.contractor.domain.SubContractorMaterialRecord; +import org.dromara.contractor.domain.vo.contractormaterialrecord.SubContractorMaterialRecordVo; + +/** + * 分包方物料记录Mapper接口 + * + * @author lilemy + * @date 2025-06-27 + */ +public interface SubContractorMaterialRecordMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorToolMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorToolMapper.java new file mode 100644 index 0000000..be4060a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorToolMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.contractor.domain.SubContractorTool; +import org.dromara.contractor.domain.vo.contractortool.SubContractorToolVo; + +/** + * 分包方工器具Mapper接口 + * + * @author lilemy + * @date 2025-06-26 + */ +public interface SubContractorToolMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorToolRecordMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorToolRecordMapper.java new file mode 100644 index 0000000..06ab266 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubContractorToolRecordMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.contractor.domain.SubContractorToolRecord; +import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo; + +/** + * 分包方工器具记录Mapper接口 + * + * @author lilemy + * @date 2025-06-26 + */ +public interface SubContractorToolRecordMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubSubcontractMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubSubcontractMapper.java new file mode 100644 index 0000000..14f3914 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/mapper/SubSubcontractMapper.java @@ -0,0 +1,15 @@ +package org.dromara.contractor.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.contractor.domain.SubSubcontract; +import org.dromara.contractor.domain.vo.subcontract.SubSubcontractVo; + +/** + * 分包合同Mapper接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface SubSubcontractMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserFileService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserFileService.java new file mode 100644 index 0000000..e7e35ee --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserFileService.java @@ -0,0 +1,80 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.domain.SubConstructionUserFile; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileQueryReq; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileSaveReq; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileTemplateReq; +import org.dromara.contractor.domain.vo.constructionuserfile.SubConstructionUserFileVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 施工人员文件存储Service接口 + * + * @author lilemy + * @date 2025-04-01 + */ +public interface ISubConstructionUserFileService extends IService { + + /** + * 查询施工人员文件存储 + * + * @param id 主键 + * @return 施工人员文件存储 + */ + SubConstructionUserFileVo queryById(Long id); + + /** + * 查询符合条件的施工人员文件存储列表 + * + * @param req 查询条件 + * @return 施工人员文件存储列表 + */ + List queryList(SubConstructionUserFileQueryReq req); + + /** + * 导出施工人员文件模版zip + * + * @param req 查询条件 + * @param response 响应对象 + */ + void downloadFileTemplate(SubConstructionUserFileTemplateReq req, HttpServletResponse response); + + /** + * 通过zip文件批量上传施工人员文件 + * + * @param multipartFile zip文件 + * @return 是否上传成功 + */ + Boolean batchUploadFileByZip(MultipartFile multipartFile); + + /** + * 保存施工人员文件存储 + * + * @param req 保存参数 + * @return 是否保存成功 + */ + Boolean saveFileList(SubConstructionUserFileSaveReq req); + + /** + * 获取施工人员文件存储查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubConstructionUserFileQueryReq req); + + /** + * 获取施工人员查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildTemplateQueryWrapper(SubConstructionUserFileTemplateReq req); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserService.java new file mode 100644 index 0000000..16487a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserService.java @@ -0,0 +1,175 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.domain.dto.constructionuser.*; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo; +import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserAttendanceMonthVo; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserAttendanceTotalVo; +import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserGisVo; + +import java.util.Collection; +import java.util.List; + +/** + * 施工人员Service接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface ISubConstructionUserService extends IService { + + /** + * 查询施工人员 + * + * @param id 主键 + * @return 施工人员 + */ + SubConstructionUserVo queryById(Long id); + + /** + * 分页查询施工人员列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员分页列表 + */ + TableDataInfo queryPageList(SubConstructionUserQueryReq req, PageQuery pageQuery); + + /** + * 分页查询施工人员考勤列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员考勤分页列表 + */ + TableDataInfo queryPageAttendanceList(SubConstructionUserAttendanceQueryReq req, PageQuery pageQuery); + + /** + * 查询施工人员月考勤列表 + * + * @param req 查询条件 + * @return 施工人员考勤月列表 + */ + List queryAttendanceMonthList(SubConstructionUserAttendanceMonthReq req); + + /** + * 查询符合条件的施工人员列表 + * + * @param req 查询条件 + * @return 施工人员列表 + */ + List queryList(SubConstructionUserQueryReq req); + + /** + * 获取施工人员大屏数据 + * + * @param req 查询条件 + * @return 施工人员大屏数据 + */ + SubConstructionUserGisVo getGisData(SubConstructionUserGisReq req); + + /** + * 新增施工人员 + * + * @param req 施工人员 + * @return 是否新增成功 + */ + Long insertByBo(SubConstructionUserCreateReq req); + + /** + * 修改施工人员 + * + * @param req 施工人员 + * @return 是否修改成功 + */ + Boolean updateByBo(SubConstructionUserUpdateReq req); + + /** + * 修改施工人员工资 + * + * @param req 修改施工人员工资对象 + * @return 是否修改成功 + */ + Boolean updateSalary(SubConstructionUserUpdateSalaryReq req); + + /** + * 修改施工人员打卡状态 + * + * @param req 修改施工人员打卡状态对象 + * @return 是否修改成功 + */ + Boolean updateClock(SubConstructionUserUpdateClockReq req); + + /** + * 修改施工人员项目(人员迁移) + * + * @param req 修改施工人员项目对象 + * @return 是否修改成功 + */ + Boolean changeUserProject(SubConstructionUserChangeProjectReq req); + + /** + * 批量修改施工人员状态 + * + * @param req 批量修改施工人员状态对象 + * @return 是否修改成功 + */ + Boolean batchUpdateStatus(SubConstructionUserBatchUpdateStatusReq req); + + /** + * 根据项目id批量修改施工人员打卡状态 + * + * @param req 批量修改施工人员打卡状态对象 + * @return 是否修改成功 + */ + Boolean batchUpdateClockByProjectId(SubConstructionUserBatchUpdateClockReq req); + + /** + * 校验并批量删除施工人员信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取施工人员视图对象 + * + * @param constructionUser 施工人员对象 + * @return 施工人员视图对象 + */ + SubConstructionUserVo getVo(SubConstructionUser constructionUser); + + /** + * 获取施工人员查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubConstructionUserQueryReq req); + + /** + * 获取施工人员分页对象视图 + * + * @param constructionUserPage 施工人员分页对象 + * @return 施工人员分页对象视图 + */ + Page getVoPage(Page constructionUserPage); + + /** + * 获取施工人员考勤分页对象视图 + * + * @param req 施工人员考勤分页查询条件 + * @return 施工人员考勤分页对象视图 + */ + Page getAttendanceTotalVoPage(SubConstructionUserAttendanceQueryReq req, + PageQuery pageQuery); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorMaterialRecordService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorMaterialRecordService.java new file mode 100644 index 0000000..e50828e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorMaterialRecordService.java @@ -0,0 +1,98 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubContractorMaterialRecord; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordCreateReq; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordQueryReq; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordUpdateReq; +import org.dromara.contractor.domain.vo.contractormaterialrecord.SubContractorMaterialRecordVo; + +import java.util.Collection; +import java.util.List; + +/** + * 分包方物料记录Service接口 + * + * @author lilemy + * @date 2025-06-27 + */ +public interface ISubContractorMaterialRecordService extends IService { + + /** + * 查询分包方物料记录 + * + * @param id 主键 + * @return 分包方物料记录 + */ + SubContractorMaterialRecordVo queryById(Long id); + + /** + * 分页查询分包方物料记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方物料记录分页列表 + */ + TableDataInfo queryPageList(SubContractorMaterialRecordQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的分包方物料记录列表 + * + * @param req 查询条件 + * @return 分包方物料记录列表 + */ + List queryList(SubContractorMaterialRecordQueryReq req); + + /** + * 新增分包方物料记录 + * + * @param req 分包方物料记录 + * @return 新增分包方物料记录id + */ + Long insertByBo(SubContractorMaterialRecordCreateReq req); + + /** + * 修改分包方物料记录 + * + * @param req 分包方物料记录 + * @return 是否修改成功 + */ + Boolean updateByBo(SubContractorMaterialRecordUpdateReq req); + + /** + * 校验并批量删除分包方物料记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取分包方物料记录视图对象 + * + * @param contractorMaterialRecord 分包方物料记录对象 + * @return 分包方物料记录视图对象 + */ + SubContractorMaterialRecordVo getVo(SubContractorMaterialRecord contractorMaterialRecord); + + /** + * 获取分包方物料记录查询条件封装 + * + * @param req 分包方物料记录查询条件 + * @return 分包方物料记录查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubContractorMaterialRecordQueryReq req); + + /** + * 获取分包方物料记录分页对象视图 + * + * @param contractorMaterialRecordPage 分包方物料记录分页对象 + * @return 分包方物料记录分页对象视图 + */ + Page getVoPage(Page contractorMaterialRecordPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorMaterialService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorMaterialService.java new file mode 100644 index 0000000..4bb67b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorMaterialService.java @@ -0,0 +1,98 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubContractorMaterial; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialCreateReq; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialQueryReq; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialUpdateReq; +import org.dromara.contractor.domain.vo.contractormaterial.SubContractorMaterialVo; + +import java.util.Collection; +import java.util.List; + +/** + * 分包方物料Service接口 + * + * @author lilemy + * @date 2025-06-27 + */ +public interface ISubContractorMaterialService extends IService { + + /** + * 查询分包方物料 + * + * @param id 主键 + * @return 分包方物料 + */ + SubContractorMaterialVo queryById(Long id); + + /** + * 分页查询分包方物料列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方物料分页列表 + */ + TableDataInfo queryPageList(SubContractorMaterialQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的分包方物料列表 + * + * @param req 查询条件 + * @return 分包方物料列表 + */ + List queryList(SubContractorMaterialQueryReq req); + + /** + * 新增分包方物料 + * + * @param req 分包方物料 + * @return 新增分包物料主键id + */ + Long insertByBo(SubContractorMaterialCreateReq req); + + /** + * 修改分包方物料 + * + * @param req 分包方物料 + * @return 是否修改成功 + */ + Boolean updateByBo(SubContractorMaterialUpdateReq req); + + /** + * 校验并批量删除分包方物料信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取分包方物料视图对象 + * + * @param contractorMaterial 分包方物料对象 + * @return 分包方物料视图对象 + */ + SubContractorMaterialVo getVo(SubContractorMaterial contractorMaterial); + + /** + * 获取分包方物料查询条件封装 + * + * @param req 分包方物料查询条件 + * @return 分包方物料查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubContractorMaterialQueryReq req); + + /** + * 获取分包方物料分页对象视图 + * + * @param contractorMaterialPage 分包方物料分页对象 + * @return 分包方物料分页对象视图 + */ + Page getVoPage(Page contractorMaterialPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorService.java new file mode 100644 index 0000000..250ce5e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorService.java @@ -0,0 +1,107 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.dto.contractor.SubContractorCreateReq; +import org.dromara.contractor.domain.dto.contractor.SubContractorQueryReq; +import org.dromara.contractor.domain.dto.contractor.SubContractorUpdateReq; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; + +import java.util.Collection; +import java.util.List; + +/** + * 分包单位Service接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface ISubContractorService extends IService { + + /** + * 查询分包单位 + * + * @param id 主键 + * @return 分包单位 + */ + SubContractorVo queryById(Long id); + + /** + * 分页查询分包单位列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包单位分页列表 + */ + TableDataInfo queryPageList(SubContractorQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的分包单位列表 + * + * @param req 查询条件 + * @return 分包单位列表 + */ + List queryList(SubContractorQueryReq req); + + /** + * 查询未绑定部门的分包单位列表 + * + * @param projectId 项目id + * @return 分包单位列表 + */ + List queryListNoDept(Long projectId); + + /** + * 新增分包单位 + * + * @param req 分包单位 + * @return 新增id + */ + Long insertByBo(SubContractorCreateReq req); + + /** + * 修改分包单位 + * + * @param req 分包单位 + * @return 是否修改成功 + */ + Boolean updateByBo(SubContractorUpdateReq req); + + /** + * 校验并批量删除分包单位信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取分包公司视图对象 + * + * @param contractor 分包公司对象 + * @return 分包公司视图对象 + */ + SubContractorVo getVo(SubContractor contractor); + + /** + * 获取分包公司查询条件封装 + * + * @param req 分包公司查询条件 + * @return 分包公司查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubContractorQueryReq req); + + /** + * 获取分包公司分页对象视图 + * + * @param contractorPage 分包公司分页对象 + * @return 分包公司分页对象视图 + */ + Page getVoPage(Page contractorPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorToolRecordService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorToolRecordService.java new file mode 100644 index 0000000..1dda933 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorToolRecordService.java @@ -0,0 +1,98 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubContractorToolRecord; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordCreateReq; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordQueryReq; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordUpdateReq; +import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo; + +import java.util.Collection; +import java.util.List; + +/** + * 分包方工器具记录Service接口 + * + * @author lilemy + * @date 2025-06-26 + */ +public interface ISubContractorToolRecordService extends IService { + + /** + * 查询分包方工器具记录 + * + * @param id 主键 + * @return 分包方工器具记录 + */ + SubContractorToolRecordVo queryById(Long id); + + /** + * 分页查询分包方工器具记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方工器具记录分页列表 + */ + TableDataInfo queryPageList(SubContractorToolRecordQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的分包方工器具记录列表 + * + * @param req 查询条件 + * @return 分包方工器具记录列表 + */ + List queryList(SubContractorToolRecordQueryReq req); + + /** + * 新增分包方工器具记录 + * + * @param req 分包方工器具记录 + * @return 新增分包方工器具记录主键id + */ + Long insertByBo(SubContractorToolRecordCreateReq req); + + /** + * 修改分包方工器具记录 + * + * @param req 分包方工器具记录 + * @return 是否修改成功 + */ + Boolean updateByBo(SubContractorToolRecordUpdateReq req); + + /** + * 校验并批量删除分包方工器具记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取分包方工器具记录视图对象 + * + * @param subContractorToolRecord 分包方工器具记录对象 + * @return 分包方工器具记录视图对象 + */ + SubContractorToolRecordVo getVo(SubContractorToolRecord subContractorToolRecord); + + /** + * 获取分包方工器具记录查询条件封装 + * + * @param req 分包方工器具记录查询条件 + * @return 分包方工器具记录查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubContractorToolRecordQueryReq req); + + /** + * 获取分包方工器具记录分页对象视图 + * + * @param contractorToolRecordPage 分包方工器具记录分页对象 + * @return 分包方工器具记录分页对象视图 + */ + Page getVoPage(Page contractorToolRecordPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorToolService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorToolService.java new file mode 100644 index 0000000..efbb11c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubContractorToolService.java @@ -0,0 +1,98 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubContractorTool; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolCreateReq; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolQueryReq; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolUpdateReq; +import org.dromara.contractor.domain.vo.contractortool.SubContractorToolVo; + +import java.util.Collection; +import java.util.List; + +/** + * 分包方工器具Service接口 + * + * @author lilemy + * @date 2025-06-26 + */ +public interface ISubContractorToolService extends IService { + + /** + * 查询分包方工器具 + * + * @param id 主键 + * @return 分包方工器具 + */ + SubContractorToolVo queryById(Long id); + + /** + * 分页查询分包方工器具列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方工器具分页列表 + */ + TableDataInfo queryPageList(SubContractorToolQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的分包方工器具列表 + * + * @param req 查询条件 + * @return 分包方工器具列表 + */ + List queryList(SubContractorToolQueryReq req); + + /** + * 新增分包方工器具 + * + * @param req 分包方工器具 + * @return 新增分包工器具主键id + */ + Long insertByBo(SubContractorToolCreateReq req); + + /** + * 修改分包方工器具 + * + * @param req 分包方工器具 + * @return 是否修改成功 + */ + Boolean updateByBo(SubContractorToolUpdateReq req); + + /** + * 校验并批量删除分包方工器具信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取分包方工器具视图对象 + * + * @param contractorTool 分包方工器具对象 + * @return 分包方工器具视图对象 + */ + SubContractorToolVo getVo(SubContractorTool contractorTool); + + /** + * 获取分包方工器具查询条件封装 + * + * @param req 分包方工器具查询条件 + * @return 分包方工器具查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubContractorToolQueryReq req); + + /** + * 获取分包方工器具分页对象视图 + * + * @param contractorPage 分包方工器具分页对象 + * @return 分包方工器具分页对象视图 + */ + Page getVoPage(Page contractorPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubSubcontractService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubSubcontractService.java new file mode 100644 index 0000000..20ae039 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubSubcontractService.java @@ -0,0 +1,99 @@ +package org.dromara.contractor.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubSubcontract; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractCreateReq; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractQueryReq; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractUpdateReq; +import org.dromara.contractor.domain.vo.subcontract.SubSubcontractVo; + +import java.util.Collection; +import java.util.List; + +/** + * 分包合同Service接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface ISubSubcontractService extends IService { + + /** + * 查询分包合同 + * + * @param id 主键 + * @return 分包合同 + */ + SubSubcontractVo queryById(Long id); + + /** + * 分页查询分包合同列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包合同分页列表 + */ + TableDataInfo queryPageList(SubSubcontractQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的分包合同列表 + * + * @param req 查询条件 + * @return 分包合同列表 + */ + List queryList(SubSubcontractQueryReq req); + + /** + * 新增分包合同 + * + * @param req 分包合同 + * @return 新增主键id + */ + Long insertByBo(SubSubcontractCreateReq req); + + /** + * 修改分包合同 + * + * @param req 分包合同 + * @return 是否修改成功 + */ + Boolean updateByBo(SubSubcontractUpdateReq req); + + /** + * 校验并批量删除分包合同信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取分包合同视图 + * + * @param subcontract 分包合同 + * @return 分包合同视图 + */ + SubSubcontractVo getVo(SubSubcontract subcontract); + + /** + * 获取用户和项目关联对象查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SubSubcontractQueryReq req); + + /** + * 获取分包合同分页视图 + * + * @param subcontractPage 分包合同分页 + * @return 分包合同分页视图 + */ + Page getVoPage(Page subcontractPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserFileServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserFileServiceImpl.java new file mode 100644 index 0000000..aaf7354 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserFileServiceImpl.java @@ -0,0 +1,448 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.ZipUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubConstructionUserFile; +import org.dromara.contractor.constant.SubConstructionUserConstant; +import org.dromara.project.domain.BusConstructionBlacklist; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.project.domain.BusProject; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileQueryReq; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileReq; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileSaveReq; +import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileTemplateReq; +import org.dromara.contractor.domain.vo.constructionuserfile.SubConstructionUserFileVo; +import org.dromara.contractor.mapper.SubConstructionUserFileMapper; +import org.dromara.project.service.IBusConstructionBlacklistService; +import org.dromara.contractor.service.ISubConstructionUserFileService; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysDictTypeService; +import org.dromara.system.service.ISysOssService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 施工人员文件存储Service业务层处理 + * + * @author lilemy + * @date 2025-04-01 + */ +@Slf4j +@Service +public class SubConstructionUserFileServiceImpl extends ServiceImpl + implements ISubConstructionUserFileService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private ISysDictTypeService dictTypeService; + + @Resource + private IBusConstructionBlacklistService constructionBlacklistService; + + @Resource + private ISysOssService ossService; + + /** + * 查询施工人员文件存储 + * + * @param id 主键 + * @return 施工人员文件存储 + */ + @Override + public SubConstructionUserFileVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 查询符合条件的施工人员文件存储列表 + * + * @param req 查询条件 + * @return 施工人员文件存储列表 + */ + @Override + public List queryList(SubConstructionUserFileQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return baseMapper.selectVoList(lqw); + } + + /** + * 导出施工人员文件模版zip + * + * @param req 项目id + * @param response 响应对象 + */ + @Override + public void downloadFileTemplate(SubConstructionUserFileTemplateReq req, HttpServletResponse response) { + // 1. 校验项目是否存在 + Long projectId = req.getProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); + } + // 2. 查询施工人员列表 + List constructionUserList = constructionUserService.list(this.buildTemplateQueryWrapper(req)); + // 3. 根目录名称 + String randomString = project.getId() + "_" + RandomUtil.randomString(8); + String rootFolder = project.getShortName() + "_" + randomString + "/"; + // 4. 设置响应头 + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=\"" + randomString + ".zip\""); + // 5. 获取输出流,并封装为 ZipOutputStream + try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) { + // 6. 根目录下创建一个文件夹 + zipOut.putNextEntry(new ZipEntry(rootFolder)); + zipOut.closeEntry(); + // 7. 对每个人,创建其文件夹,再在其中创建子文件夹(如“三级安全教育”、“体检报告”...)及文件 + for (SubConstructionUser constructionUser : constructionUserList) { + String personFolder = rootFolder + constructionUser.getUserName() + "-" + constructionUser.getId() + "/"; + // 7.1. 写入个人文件夹条目 + zipOut.putNextEntry(new ZipEntry(personFolder)); + zipOut.closeEntry(); + // 7.2. 在个人文件夹下写几个子文件夹 + List dictDataList = dictTypeService.selectDictDataByType(SubConstructionUserConstant.USER_FILE_TYPE); + for (SysDictDataVo dataVo : dictDataList) { + String subFolderPath = personFolder + dataVo.getDictValue() + "_" + dataVo.getDictLabel() + "/"; + zipOut.putNextEntry(new ZipEntry(subFolderPath)); + zipOut.closeEntry(); + } + } + zipOut.flush(); + response.flushBuffer(); // 确保数据全部写入响应流 + } catch (IOException e) { + throw new ServiceException("文件下载失败", HttpStatus.ERROR); + } + } + + /** + * 通过zip文件批量上传施工人员文件 + * + * @param multipartFile zip文件 + * @return 是否上传成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean batchUploadFileByZip(MultipartFile multipartFile) { + // 获取文件原始名字 + String originalFilename = multipartFile.getOriginalFilename(); + // 校验 + if (originalFilename == null) { + throw new ServiceException("文件不存在", HttpStatus.BAD_REQUEST); + } + // 校验是否为压缩包zip格式 + String suffix = FileUtil.getSuffix(originalFilename); + if (!suffix.equals("zip")) { + throw new ServiceException("请上传zip格式的文件", HttpStatus.BAD_REQUEST); + } + // 1. 获取项目id + String[] parts = originalFilename.split("_"); + long projectId = Long.parseLong(parts[1]); + // 压缩包临时文件路径 + String randomStr = RandomUtil.randomString(16); + File tempZipFile = null; + String tempZipFilePath = randomStr + "-" + originalFilename; + // 解压后的文件夹路径 + File destDir = null; + String basePath = "unzip_path"; + String destDirPath = basePath + "/" + DateUtils.getDate() + "/" + projectId + "/" + randomStr; + // 构建需要修改的对象 + List constructionUserFileList = new ArrayList<>(); + try { + // 2. 创建临时文件 + tempZipFile = File.createTempFile(tempZipFilePath, null); + multipartFile.transferTo(tempZipFile); + // 3. 解压 zip + destDir = new File(destDirPath); + ZipUtil.unzip(tempZipFile, destDir); + // 4. 遍历最外层文件夹 + File[] userFolders = destDir.listFiles(); + if (userFolders != null) { + for (File userFolder : userFolders) { + if (userFolder.isDirectory()) { + String userFolderName = userFolder.getName(); // 李四-1905161272755195006 + // 5. 解析 userId + long userId = Long.parseLong(userFolderName.substring(userFolderName.lastIndexOf("-") + 1)); + // 6. 继续遍历每个用户子文件夹里的 1_合同, 2_体检报告, ... + File[] docFolders = userFolder.listFiles(); + if (docFolders != null) { + for (File docFolder : docFolders) { + if (docFolder.isDirectory()) { + String docFolderName = docFolder.getName(); // 1_合同 + String[] docParts = docFolderName.split("_"); + String fileType = docParts[0]; + // 7. 获取该文件夹下所有文件 + File[] filesInDocFolder = docFolder.listFiles(); + String fileIdStr = null; + if (filesInDocFolder != null) { + // 遍历文件 + List fileIds = new ArrayList<>(); + for (File file : filesInDocFolder) { + if (file.isFile()) { + SysOssVo upload = ossService.upload(file); + if (upload != null) { + fileIds.add(upload.getOssId()); + } + } + } + // 跳过空文件 + if (fileIds.isEmpty()) { + continue; + } + fileIdStr = fileIds.stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); + } + // 8. 创建 BusConstructionUserFile 对象 + SubConstructionUserFile constructionUserFile = new SubConstructionUserFile(); + constructionUserFile.setUserId(userId); + constructionUserFile.setFileType(fileType); + constructionUserFile.setPath(fileIdStr); + constructionUserFileList.add(constructionUserFile); + } + } + } + } + } + } + } catch (Exception e) { + throw new ServiceException("文件上传失败", HttpStatus.ERROR); + } finally { + if (tempZipFile != null) { + // 删除临时文件 + boolean delete = tempZipFile.delete(); + if (!delete) { + log.error("临时文件删除失败,路径:{}", tempZipFilePath); + } + } + if (destDir != null) { + Path dirPath = Paths.get(basePath); + try { + FileUtils.deleteDirectory(dirPath); + } catch (IOException e) { + log.error("解压文件删除失败,路径:{}", destDirPath, e); + } + } + } + if (CollUtil.isEmpty(constructionUserFileList)) { + return true; + } + // 9. 判断是否已经存在 + List userIdList = constructionUserFileList.stream().map(SubConstructionUserFile::getUserId).toList(); + List oldConstructionUserFileList = this.lambdaQuery() + .in(SubConstructionUserFile::getUserId, userIdList).list(); + // 10. 如果存在,则删除数据库对应记录和文件 + if (CollUtil.isNotEmpty(oldConstructionUserFileList)) { + // 待删除id + List deleteIds = oldConstructionUserFileList.stream().map(SubConstructionUserFile::getId).toList(); + // 待删除对象存储id + List deleteOssIds = new ArrayList<>(); + for (SubConstructionUserFile constructionUserFile : oldConstructionUserFileList) { + String path = constructionUserFile.getPath(); + if (StrUtil.isNotBlank(path)) { + String[] ossIds = path.split(","); + deleteOssIds.addAll(Arrays.stream(ossIds).map(Long::parseLong).toList()); + } + } + // 删除数据库记录 + boolean result = this.removeByIds(deleteIds); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + // 删除文件 + Boolean ossResult = ossService.deleteWithValidByIds(deleteOssIds, true); + if (!ossResult) { + throw new ServiceException("文件存储修改失败", HttpStatus.ERROR); + } + } + // 11. 保存 + boolean result = this.saveBatch(constructionUserFileList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存施工人员文件存储 + * + * @param req 保存参数 + * @return 是否保存成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean saveFileList(SubConstructionUserFileSaveReq req) { + // 1. 参数校验 + // 判断参数是否为空 + Long userId = req.getUserId(); + List fileList = req.getFileList(); + if (userId == null || CollUtil.isEmpty(fileList)) { + throw new ServiceException("施工人员文件存储参数错误", HttpStatus.BAD_REQUEST); + } + // 校验修改用户是否存在 + SubConstructionUser constructionUser = constructionUserService.getById(userId); + if (constructionUser == null) { + throw new ServiceException("施工人员不存在", HttpStatus.NOT_FOUND); + } + // 判断登录用户是否有用户所在项目的操作权限 + Long projectId = constructionUser.getProjectId(); + Long loginUser = LoginHelper.getUserId(); + projectService.validAuth(projectId, loginUser); + // 2. 查询当前用户的所有文件记录(一次性查询,避免多次访问数据库) + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(SubConstructionUserFile.class) + .eq(SubConstructionUserFile::getUserId, userId); + List constructionUserFileList = this.list(lqw); + // 3. 构建 Map 方便查找 + Map existingFileMap = constructionUserFileList.stream() + .collect(Collectors.toMap(SubConstructionUserFile::getFileType, Function.identity())); + // 4. 处理新增或更新的数据 + List saveOrUpdateList = new ArrayList<>(); + // 处理删除的数据 + List deleteList = new ArrayList<>(); + for (SubConstructionUserFileReq fileReq : fileList) { + String fileType = fileReq.getFileType(); + String fileId = fileReq.getFileId(); + if (existingFileMap.containsKey(fileType)) { + // 如果存在,则更新 + SubConstructionUserFile existingFile = existingFileMap.get(fileType); + // 如果文件id相同,则不更新 + if (StringUtils.equals(existingFile.getPath(), fileId)) { + continue; + } + // 如果文件id为空,则删除 + if (StringUtils.isBlank(fileId)) { + deleteList.add(existingFile.getId()); + continue; + } + existingFile.setPath(fileId); + saveOrUpdateList.add(existingFile); + } else { + // 如果不存在,且存在文件id则更新 + if (StringUtils.isNotBlank(fileId)) { + SubConstructionUserFile newFile = new SubConstructionUserFile(); + newFile.setUserId(userId); + newFile.setFileType(fileType); + newFile.setPath(fileId); + saveOrUpdateList.add(newFile); + } + } + } + // 5. 批量保存或更新 + if (CollUtil.isNotEmpty(saveOrUpdateList)) { + boolean result = this.saveOrUpdateBatch(saveOrUpdateList); + if (!result) { + throw new ServiceException("保存或更新施工人员文件存储失败", HttpStatus.ERROR); + } + } + // 6. 批量删除 + if (CollUtil.isNotEmpty(deleteList)) { + boolean result = this.removeBatchByIds(deleteList); + if (!result) { + throw new ServiceException("删除施工人员文件存储失败", HttpStatus.ERROR); + } + } + return true; + } + + /** + * 获取施工人员文件存储查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubConstructionUserFileQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long userId = req.getUserId(); + String fileType = req.getFileType(); + String remark = req.getRemark(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(remark), SubConstructionUserFile::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), SubConstructionUserFile::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(userId), SubConstructionUserFile::getUserId, userId); + lqw.eq(StringUtils.isNotBlank(fileType), SubConstructionUserFile::getFileType, fileType); + return lqw; + } + + /** + * 获取施工人员查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildTemplateQueryWrapper(SubConstructionUserFileTemplateReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String userName = req.getUserName(); + Long contractorId = req.getContractorId(); + Long teamId = req.getTeamId(); + String typeOfWork = req.getTypeOfWork(); + String clock = req.getClock(); + List userIdList = req.getUserIdList(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), SubConstructionUser::getUserName, userName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubConstructionUser::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubConstructionUser::getContractorId, contractorId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), SubConstructionUser::getTeamId, teamId); + lqw.eq(StringUtils.isNotBlank(typeOfWork), SubConstructionUser::getTypeOfWork, typeOfWork); + lqw.eq(StringUtils.isNotBlank(clock), SubConstructionUser::getClock, clock); + if (CollUtil.isNotEmpty(userIdList)) { + lqw.in(SubConstructionUser::getId, userIdList); + } + // 根据项目id获取黑名单施工人员 + List blacklistUserIdList = constructionBlacklistService.lambdaQuery() + .eq(BusConstructionBlacklist::getProjectId, projectId) + .list().stream().map(BusConstructionBlacklist::getUserId).toList(); + if (CollUtil.isNotEmpty(blacklistUserIdList)) { + lqw.notIn(SubConstructionUser::getId, blacklistUserIdList); + } + return lqw; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java new file mode 100644 index 0000000..89d004e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java @@ -0,0 +1,959 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.DesensitizedUtil; +import cn.hutool.core.util.IdcardUtil; +import cn.hutool.core.util.PhoneUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.DateConstant; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.utils.IdCardEncryptorUtil; +import org.dromara.contractor.constant.SubConstructionUserConstant; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.domain.SubConstructionUserFile; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.dto.constructionuser.*; +import org.dromara.contractor.domain.enums.SubConstructionUserFileStatusEnum; +import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo; +import org.dromara.contractor.domain.vo.constructionuser.*; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; +import org.dromara.contractor.mapper.SubConstructionUserMapper; +import org.dromara.contractor.service.ISubConstructionUserFileService; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.project.domain.BusWorkWage; +import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum; +import org.dromara.project.domain.enums.BusAttendanceCommuterEnum; +import org.dromara.project.domain.enums.BusConstructionUserAttendanceStatusEnum; +import org.dromara.project.service.*; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysDictTypeService; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.YearMonth; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 施工人员Service业务层处理 + * + * @author lilemy + * @date 2025-03-07 + */ +@Service +public class SubConstructionUserServiceImpl extends ServiceImpl + implements ISubConstructionUserService { + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private ISubContractorService contractorService; + + @Lazy + @Resource + private IBusProjectTeamMemberService projectTeamMemberService; + + @Resource + private ISysOssService ossService; + + @Lazy + @Resource + private IBusConstructionBlacklistService constructionBlacklistService; + + @Lazy + @Resource + private IBusWorkWageService workWageService; + + @Lazy + @Resource + private ISubConstructionUserFileService constructionUserFileService; + + @Resource + private ISysDictTypeService dictTypeService; + + @Lazy + @Resource + private IBusAttendanceService attendanceService; + + @Resource + private IdCardEncryptorUtil idCardEncryptorUtil; + + /** + * 查询施工人员 + * + * @param id 主键 + * @return 施工人员 + */ + @Override + public SubConstructionUserVo queryById(Long id) { + SubConstructionUser constructionUser = this.getById(id); + if (constructionUser == null) { + throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(constructionUser); + } + + /** + * 分页查询施工人员列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员分页列表 + */ + @Override + public TableDataInfo queryPageList(SubConstructionUserQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(getVoPage(result)); + } + + /** + * 分页查询施工人员考勤列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员考勤分页列表 + */ + @Override + public TableDataInfo queryPageAttendanceList(SubConstructionUserAttendanceQueryReq req, + PageQuery pageQuery) { + return TableDataInfo.build(getAttendanceTotalVoPage(req, pageQuery)); + } + + /** + * 查询施工人员月考勤列表 + * + * @param req 查询条件 + * @return 施工人员考勤月列表 + */ + @Override + public List queryAttendanceMonthList(SubConstructionUserAttendanceMonthReq req) { + Long id = req.getUserId(); + String clockMonth = req.getClockMonth(); + if (this.getById(id) == null) { + throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); + } + // 解析月份 + YearMonth yearMonth; + if (StringUtils.isNotBlank(clockMonth)) { + // 校验月份格式 + if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { + throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); + } + yearMonth = YearMonth.parse(clockMonth); + } else { + // 如果月份为空,则默认查询当前月份 + yearMonth = YearMonth.now(); + } + // 计算当月第一天 / 最后一天 + Date start = DateUtils.toDate(yearMonth.atDay(1)); + Date end = DateUtils.toDate(yearMonth.atEndOfMonth()); + // 查询当月考勤记录 + List dateList = attendanceService.lambdaQuery() + .eq(BusAttendance::getUserId, id) + .between(BusAttendance::getClockDate, start, end) + .list(); + Map> dateListMap = dateList.stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); + // 获取所有打卡图片id + List picIds = dateList.stream().map(BusAttendance::getFacePic).filter(Objects::nonNull).map(Long::valueOf).toList(); + Map> ossIdUrlMap = ossService.listByIds(picIds) + .stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + // 遍历每天,计算考勤状态 + List respList = new ArrayList<>(); + dateListMap.forEach((date, attendanceList) -> { + SubConstructionUserAttendanceMonthVo resp = new SubConstructionUserAttendanceMonthVo(); + resp.setId(id); + resp.setClockDate(date); + // 获取考勤记录 + SubConstructionUserAttendanceByDay day = SubConstructionUserAttendanceByDay.build(attendanceList); + // 填充打卡图片url + if (day != null) { + if (day.getUpClockPicId() != null) { + day.setUpClockPic(ossIdUrlMap.get(day.getUpClockPicId()).getFirst().getUrl()); + } + if (day.getDownClockPicId() != null) { + day.setDownClockPic(ossIdUrlMap.get(day.getDownClockPicId()).getFirst().getUrl()); + } + } + String clockInStatus = null; + String clockOutStatus = null; + String clockAllDayStatus = null; + String status; + for (BusAttendance attendance : attendanceList) { + // 获取上下班状态 + if (BusAttendanceCommuterEnum.CLOCKIN.getValue().equals(attendance.getCommuter())) { + clockInStatus = attendance.getClockStatus(); + } else if (BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getCommuter())) { + clockOutStatus = attendance.getClockStatus(); + } else { + clockAllDayStatus = attendance.getClockStatus(); + } + } + // 统计当天考勤状态 + if (BusAttendanceClockStatusEnum.LEAVE.getValue().equals(clockAllDayStatus)) { + status = BusConstructionUserAttendanceStatusEnum.LEAVE.getValue(); + } else if (BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus) + && BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { + status = BusConstructionUserAttendanceStatusEnum.UNCLOCK.getValue(); + } else if (BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus) + || BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { + status = BusConstructionUserAttendanceStatusEnum.ONECLOCK.getValue(); + } else { + status = BusConstructionUserAttendanceStatusEnum.NORMAL.getValue(); + } + resp.setStatus(status); + resp.setClockList(day); + respList.add(resp); + }); + // 按打卡日期正序排列 + respList.sort(Comparator.comparing(SubConstructionUserAttendanceMonthVo::getClockDate)); + return respList; + } + + /** + * 查询符合条件的施工人员列表 + * + * @param req 查询条件 + * @return 施工人员列表 + */ + @Override + public List queryList(SubConstructionUserQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + List constructionUserVoList = this.list(lqw).stream().map(this::getVo).toList(); + // 关联项目信息 + Set projectIdList = constructionUserVoList.stream().map(SubConstructionUserVo::getProjectId) + .collect(Collectors.toSet()); + Map> projectIdProjectMap = projectService.listByIds(projectIdList).stream() + .collect(Collectors.groupingBy(BusProject::getId)); + List constructionUserExportVoList = new ArrayList<>(); + if (CollUtil.isNotEmpty(constructionUserVoList)) { + constructionUserExportVoList = constructionUserVoList.stream().map(constructionUserVo -> { + BusConstructionUserExportVo constructionUserExportVo = new BusConstructionUserExportVo(); + BeanUtils.copyProperties(constructionUserVo, constructionUserExportVo); + // 关联分包公司信息 + constructionUserExportVo.setContractorName(constructionUserVo.getContractorVo().getName()); + // 关联项目信息 + Long projectId = constructionUserVo.getProjectId(); + String projectName = null; + if (projectIdProjectMap.containsKey(projectId)) { + projectName = projectService.getVo(projectIdProjectMap.get(projectId).getFirst()).getProjectName(); + } + constructionUserExportVo.setProjectName(projectName); + return constructionUserExportVo; + }).toList(); + } + return constructionUserExportVoList; + } + + /** + * 获取施工人员大屏数据 + * + * @param req 查询条件 + * @return 施工人员大屏数据 + */ + @Override + public SubConstructionUserGisVo getGisData(SubConstructionUserGisReq req) { + // 参数校验 + Long projectId = req.getProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + // 获取大屏数据 + SubConstructionUserGisVo resp = new SubConstructionUserGisVo(); + // 获取施工人员总数 + Long count = this.lambdaQuery() + .eq(SubConstructionUser::getProjectId, projectId).count(); + resp.setPeopleCount(count); + // 获取考勤数据 + List attendancePeopleList = attendanceService.listAttendancePeopleByProjectId(projectId); + resp.setAttendanceCount((long) attendancePeopleList.size()); + // 计算考勤率 + resp.setAttendanceRate(count == 0 ? "0" : String.format("%.2f", attendancePeopleList.size() * 100.0 / count)); + return resp; + } + + /** + * 新增施工人员 + * + * @param req 施工人员 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(SubConstructionUserCreateReq req) { + // 将实体类和 DTO 进行转换 + SubConstructionUser constructionUser = new SubConstructionUser(); + BeanUtils.copyProperties(req, constructionUser); + // 数据校验 + validEntityBeforeSave(constructionUser, true); + Long userId = LoginHelper.getUserId(); + projectService.validAuth(req.getProjectId(), userId); + // 对身份证号码进行加密 + String encrypt = idCardEncryptorUtil.encrypt(req.getSfzNumber()); + constructionUser.setSfzNumber(encrypt); + // 操作数据库 + boolean save = this.save(constructionUser); + if (!save) { + throw new ServiceException("新增施工人员失败,数据库异常", HttpStatus.ERROR); + } + return constructionUser.getId(); + } + + /** + * 修改施工人员 + * + * @param req 施工人员 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(SubConstructionUserUpdateReq req) { + // 将实体类和 DTO 进行转换 + SubConstructionUser constructionUser = new SubConstructionUser(); + BeanUtils.copyProperties(req, constructionUser); + // 数据校验 + validEntityBeforeSave(constructionUser, false); + // 判断是否存在 + SubConstructionUser oldConstructionUser = this.getById(constructionUser.getId()); + if (oldConstructionUser == null) { + throw new ServiceException("修改施工人员失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断当前操作用户是否有权限 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(oldConstructionUser.getProjectId(), userId); + // 操作数据库 + return this.updateById(constructionUser); + } + + /** + * 修改施工人员工资 + * + * @param req 修改施工人员工资对象 + * @return 是否修改成功 + */ + @Override + public Boolean updateSalary(SubConstructionUserUpdateSalaryReq req) { + Long id = req.getId(); + Long salary = req.getSalary(); + // 判断对应施工人员是否存在 + SubConstructionUser oldConstructionUser = this.getById(id); + if (oldConstructionUser == null) { + throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); + } + // 判断当前操作用户是否有权限 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(oldConstructionUser.getProjectId(), userId); + SubConstructionUser constructionUser = new SubConstructionUser(); + constructionUser.setId(id); + // 修改薪水 + constructionUser.setSalary(Objects.requireNonNullElse(salary, 0L)); + // 操作数据库 + return this.updateById(constructionUser); + } + + /** + * 修改施工人员打卡状态 + * + * @param req 修改施工人员打卡状态对象 + * @return 是否修改成功 + */ + @Override + public Boolean updateClock(SubConstructionUserUpdateClockReq req) { + Long id = req.getId(); + String clock = req.getClock(); + // 判断对应施工人员是否存在 + SubConstructionUser oldConstructionUser = this.getById(id); + if (oldConstructionUser == null) { + throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); + } + // 判断当前操作用户是否有权限 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(oldConstructionUser.getProjectId(), userId); + if (clock.equals(oldConstructionUser.getClock())) { + return true; + } + SubConstructionUser constructionUser = new SubConstructionUser(); + constructionUser.setId(id); + constructionUser.setClock(clock); + return this.updateById(constructionUser); + } + + /** + * 修改施工人员项目(人员迁移) + * + * @param req 修改施工人员项目对象 + * @return 是否修改成功 + */ + @Override + public Boolean changeUserProject(SubConstructionUserChangeProjectReq req) { + Long id = req.getId(); + // 判断对应施工人员是否存在 + SubConstructionUser constructionUser = this.getById(id); + if (constructionUser == null) { + throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); + } + // 判断当前操作用户是否有权限 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(List.of(constructionUser.getProjectId(), req.getProjectId()), userId); + // 判断用户是否还存在于班组 + Long count = projectTeamMemberService.lambdaQuery().eq(BusProjectTeamMember::getMemberId, id).count(); + if (count > 0) { + throw new ServiceException("施工人员还未退场,不能修改", HttpStatus.BAD_REQUEST); + } + // 数据校验 + if (req.getProjectId().equals(constructionUser.getProjectId())) { + throw new ServiceException("已在当前项目下,请勿重复修改", HttpStatus.BAD_REQUEST); + } + if (req.getContractorId().equals(constructionUser.getContractorId())) { + throw new ServiceException("已在当前分包公司下,请勿重复修改", HttpStatus.BAD_REQUEST); + } + SubConstructionUser validUser = new SubConstructionUser(); + BeanUtils.copyProperties(req, validUser); + this.validEntityBeforeSave(validUser, false); + // 操作数据库,更新数据 + LambdaUpdateWrapper lambdaUpdate = Wrappers.lambdaUpdate(SubConstructionUser.class) + .eq(SubConstructionUser::getId, id) + .set(SubConstructionUser::getProjectId, req.getProjectId()) + .set(SubConstructionUser::getContractorId, req.getContractorId()); + return this.update(lambdaUpdate); + } + + /** + * 批量修改施工人员状态 + * + * @param req 批量修改施工人员状态对象 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean batchUpdateStatus(SubConstructionUserBatchUpdateStatusReq req) { + List idList = req.getIdList(); + String status = req.getStatus(); + // 查询对应数据是否存在 + if (CollUtil.isEmpty(idList)) { + throw new ServiceException("施工人员 id 不能为空", HttpStatus.BAD_REQUEST); + } + List constructionUserList = this.listByIds(idList); + // 判断对应数据是否都存在 + if (constructionUserList.size() != idList.size()) { + throw new ServiceException("修改施工人员状态失败,数据缺失", HttpStatus.BAD_REQUEST); + } + // 判断当前操作用户是否有权限 + Long userId = LoginHelper.getUserId(); + List projectIdList = constructionUserList.stream() + .map(SubConstructionUser::getProjectId) + .distinct().toList(); + projectService.validAuth(projectIdList, userId); + // 批量修改 + List list = constructionUserList.stream() + .filter(user -> !status.equals(user.getStatus())) + .map(user -> { + SubConstructionUser constructionUser = new SubConstructionUser(); + constructionUser.setId(user.getId()); + constructionUser.setStatus(status); + return constructionUser; + }) + .toList(); + if (CollUtil.isNotEmpty(list)) { + boolean result = this.updateBatchById(list); + if (!result) { + throw new ServiceException("修改施工人员状态失败,数据库异常", HttpStatus.ERROR); + } + } + return true; + } + + /** + * 根据项目id批量修改施工人员打卡状态 + * + * @param req 批量修改施工人员打卡状态对象 + * @return 是否修改成功 + */ + @Override + public Boolean batchUpdateClockByProjectId(SubConstructionUserBatchUpdateClockReq req) { + Long projectId = req.getProjectId(); + String clock = req.getClock(); + // 校验打卡状态是否为空 + if (StringUtils.isEmpty(clock)) { + throw new ServiceException("打卡状态不能为空", HttpStatus.BAD_REQUEST); + } + // 校验项目id和对应项目是否存在 + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + // 权限校验 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(projectId, userId); + // 操作数据库,批量修改 + LambdaUpdateWrapper lambdaUpdate = Wrappers.lambdaUpdate(SubConstructionUser.class) + .eq(SubConstructionUser::getProjectId, projectId) + .set(SubConstructionUser::getClock, clock); + boolean update = this.update(lambdaUpdate); + if (!update) { + throw new ServiceException("修改施工人员打卡状态失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SubConstructionUser entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + // 校验项目id和对应项目是否存在 + Long projectId = entity.getProjectId(); + // 校验分包公司id和对应项目是否存在 + Long contractorId = entity.getContractorId(); + String typeOfWork = entity.getTypeOfWork(); + String wageMeasureUnit = entity.getWageMeasureUnit(); + String phone = entity.getPhone(); + String sfzNumber = entity.getSfzNumber(); + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (create) { + if (contractorId == null) { + throw new ServiceException("分包公司 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(typeOfWork)) { + throw new ServiceException("工种不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(wageMeasureUnit)) { + throw new ServiceException("工资计量单位不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(sfzNumber)) { + throw new ServiceException("身份证不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (contractorId != null) { + SubContractor contractor = contractorService.getById(contractorId); + if (contractor == null) { + throw new ServiceException("分包单位信息不存在", HttpStatus.NOT_FOUND); + } + Long contractorProjectId = contractor.getProjectId(); + if (!projectId.equals(contractorProjectId)) { + throw new ServiceException("分包单位不属于当前项目,请重新选择", HttpStatus.BAD_REQUEST); + } + } + if (StringUtils.isNotEmpty(wageMeasureUnit) && StringUtils.isNotEmpty(typeOfWork)) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(BusWorkWage.class) + .eq(BusWorkWage::getProjectId, projectId) + .eq(BusWorkWage::getWorkType, typeOfWork) + .eq(BusWorkWage::getWageMeasureUnit, wageMeasureUnit); + long count = workWageService.count(lqw); + if (count <= 0) { + throw new ServiceException("当前工种没有定义工资标准,请前往工种薪水设置进行设置后再选择", HttpStatus.BAD_REQUEST); + } + } + if (StringUtils.isNotEmpty(phone) && !PhoneUtil.isPhone(phone)) { + throw new ServiceException("手机号码格式不正确", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isNotEmpty(sfzNumber) && !IdcardUtil.isValidCard(sfzNumber)) { + throw new ServiceException("身份证号码格式不正确", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除施工人员信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List constructionUserList = this.listByIds(ids); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + // 获取项目id列表 + List projectIdList = constructionUserList.stream().map(SubConstructionUser::getProjectId).toList(); + // 判断是否有权限操作对应项目下的内容 + projectService.validAuth(projectIdList, userId); + // 判断待删除的人员是否存在于班组 + LambdaQueryWrapper projectTeamMemberLqw = Wrappers.lambdaQuery(BusProjectTeamMember.class) + .in(BusProjectTeamMember::getMemberId, ids); + if (projectTeamMemberService.count(projectTeamMemberLqw) > 0) { + throw new ServiceException("删除施工人员信息失败,施工人员存在于班组中", HttpStatus.BAD_REQUEST); + } + } + // 判断对应数据是否都存在 + if (constructionUserList.size() != ids.size()) { + throw new ServiceException("删除施工人员信息失败,数据缺失", HttpStatus.BAD_REQUEST); + } + // 批量删除施工人员下的文件信息 + LambdaQueryWrapper constructionUserFileLqw = Wrappers.lambdaQuery(SubConstructionUserFile.class) + .in(SubConstructionUserFile::getUserId, ids); + boolean removeFile = constructionUserFileService.remove(constructionUserFileLqw); + if (!removeFile) { + throw new ServiceException("删除施工人员信息失败,施工人员文件信息删除失败", HttpStatus.ERROR); + } + // 批量删除施工人员信息 + return this.removeBatchByIds(ids); + } + + /** + * 获取施工人员视图对象 + * + * @param constructionUser 施工人员对象 + * @return 施工人员视图对象 + */ + @Override + public SubConstructionUserVo getVo(SubConstructionUser constructionUser) { + // 对象转封装类 + SubConstructionUserVo constructionUserVo = new SubConstructionUserVo(); + if (constructionUser == null) { + return constructionUserVo; + } + BeanUtils.copyProperties(constructionUser, constructionUserVo); + // 关联查询分包公司信息信息 + Long contractorId = constructionUser.getContractorId(); + if (contractorId != null) { + constructionUserVo.setContractorVo(contractorService.queryById(contractorId)); + } + // 关联查询用户头像url + String facePic = constructionUser.getFacePic(); + if (StringUtils.isNotBlank(facePic)) { + constructionUserVo.setFacePicUrl(ossService.getById(Long.parseLong(facePic)).getUrl()); + } + // 关联查询薪水标准 + Long projectId = constructionUser.getProjectId(); + String typeOfWork = constructionUser.getTypeOfWork(); + String wageMeasureUnit = constructionUser.getWageMeasureUnit(); + if (projectId != null && StringUtils.isNotEmpty(typeOfWork) && StringUtils.isNotEmpty(wageMeasureUnit)) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(BusWorkWage.class) + .eq(BusWorkWage::getProjectId, projectId) + .eq(BusWorkWage::getWorkType, typeOfWork) + .eq(BusWorkWage::getWageMeasureUnit, wageMeasureUnit); + BusWorkWage workWage = workWageService.getOne(lqw); + if (workWage != null) { + constructionUserVo.setStandardSalary(workWage.getWage()); + } + } + // 解密身份证号码 + String decrypt = idCardEncryptorUtil.decrypt(constructionUserVo.getSfzNumber()); + String hide = DesensitizedUtil.idCardNum(decrypt, 1, 2); + constructionUserVo.setSfzNumber(hide); + // 隐藏手机号码 + String hidePhone = DesensitizedUtil.mobilePhone(constructionUserVo.getPhone()); + constructionUserVo.setPhone(hidePhone); + // 隐藏银行卡号 + String hideBank = DesensitizedUtil.bankCard(constructionUserVo.getYhkNumber()); + constructionUserVo.setYhkNumber(hideBank); + return constructionUserVo; + } + + /** + * 获取施工人员查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubConstructionUserQueryReq req) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + String userName = req.getUserName(); + Long projectId = req.getProjectId(); + Long contractorId = req.getContractorId(); + Long teamId = req.getTeamId(); + Long notTeamId = req.getNotTeamId(); + String teamName = req.getTeamName(); + String status = req.getStatus(); + String isPinch = req.getIsPinch(); + String sex = req.getSex(); + String nation = req.getNation(); + String nativePlace = req.getNativePlace(); + String yhkOpeningBank = req.getYhkOpeningBank(); + String typeOfWork = req.getTypeOfWork(); + String wageMeasureUnit = req.getWageMeasureUnit(); + String clock = req.getClock(); + String userRole = req.getUserRole(); + String notUserRole = req.getNotUserRole(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), SubConstructionUser::getUserName, userName); + lqw.like(StringUtils.isNotBlank(nation), SubConstructionUser::getNation, nation); + lqw.like(StringUtils.isNotBlank(nativePlace), SubConstructionUser::getNativePlace, nativePlace); + lqw.like(StringUtils.isNotBlank(yhkOpeningBank), SubConstructionUser::getYhkOpeningBank, yhkOpeningBank); + lqw.like(StringUtils.isNotBlank(teamName), SubConstructionUser::getTeamName, teamName); + // 精确查询 + lqw.eq(StringUtils.isNotBlank(status), SubConstructionUser::getStatus, status); + lqw.eq(ObjectUtils.isNotEmpty(id), SubConstructionUser::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubConstructionUser::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubConstructionUser::getContractorId, contractorId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), SubConstructionUser::getTeamId, teamId); + lqw.eq(StringUtils.isNotBlank(isPinch), SubConstructionUser::getIsPinch, isPinch); + lqw.eq(StringUtils.isNotBlank(sex), SubConstructionUser::getSex, sex); + lqw.eq(ObjectUtils.isNotEmpty(typeOfWork), SubConstructionUser::getTypeOfWork, typeOfWork); + lqw.eq(ObjectUtils.isNotEmpty(clock), SubConstructionUser::getClock, clock); + lqw.eq(StringUtils.isNotBlank(wageMeasureUnit), SubConstructionUser::getWageMeasureUnit, wageMeasureUnit); + lqw.eq(StringUtils.isNotBlank(userRole), SubConstructionUser::getUserRole, userRole); + // 精准查询,不等于 + if (ObjectUtils.isNotEmpty(notTeamId)) { + lqw.and(wrapper -> wrapper + .ne(SubConstructionUser::getTeamId, notTeamId) + .or().isNull(SubConstructionUser::getTeamId)); + } + // 查询当前项目下的黑名单人员 + if (projectId != null) { + List blackUserIdList = constructionBlacklistService.queryIdListByProjectId(projectId); + // 查询结果移除黑名单人员 + if (CollUtil.isNotEmpty(blackUserIdList)) { + lqw.notIn(SubConstructionUser::getId, blackUserIdList); + } + } + lqw.ne(StringUtils.isNotBlank(notUserRole), SubConstructionUser::getUserRole, notUserRole); + return lqw; + } + + /** + * 获取施工人员分页对象视图 + * + * @param constructionUserPage 施工人员分页对象 + * @return 施工人员分页对象视图 + */ + @Override + public Page getVoPage(Page constructionUserPage) { + List constructionUserList = constructionUserPage.getRecords(); + Page constructionUserVoPage = new Page<>( + constructionUserPage.getCurrent(), + constructionUserPage.getSize(), + constructionUserPage.getTotal()); + if (CollUtil.isEmpty(constructionUserList)) { + return constructionUserVoPage; + } + // 关联查询分包公司信息 + Set contractorIdSet = constructionUserList.stream().map(SubConstructionUser::getContractorId) + .collect(Collectors.toSet()); + Map> contractorIdContractorMap = contractorService.listByIds(contractorIdSet).stream() + .collect(Collectors.groupingBy(SubContractor::getId)); + // 关联查询工资标准 + LambdaQueryWrapper workWageLqw = Wrappers.lambdaQuery(BusWorkWage.class) + .in(BusWorkWage::getProjectId, constructionUserList.stream().map(SubConstructionUser::getProjectId).toList()) + .in(BusWorkWage::getWorkType, constructionUserList.stream().map(SubConstructionUser::getTypeOfWork).toList()) + .in(BusWorkWage::getWageMeasureUnit, constructionUserList.stream().map(SubConstructionUser::getWageMeasureUnit).toList()); + Map workWageMap = workWageService.list(workWageLqw).stream().collect(Collectors.toMap( + workWage -> workWage.getWorkType() + "_" + workWage.getWageMeasureUnit(), + BusWorkWage::getWage, + (wage1, wage2) -> wage1 + )); + int fileTypeSize = dictTypeService.selectDictDataByType(SubConstructionUserConstant.USER_FILE_TYPE).size(); + // 获取用户上传文件数量信息 + List userIdList = constructionUserList.stream().map(SubConstructionUser::getId).toList(); + List fileList = constructionUserFileService.lambdaQuery() + .select(SubConstructionUserFile::getId, SubConstructionUserFile::getUserId) + .in(SubConstructionUserFile::getUserId, userIdList) + .list(); + Map fileCountMap = fileList.stream() + .collect(Collectors.groupingBy( + SubConstructionUserFile::getUserId, + Collectors.counting() + )); + // 填充信息 + List constructionUserVoList = constructionUserList.stream().map(constructionUser -> { + SubConstructionUserVo constructionUserVo = new SubConstructionUserVo(); + BeanUtils.copyProperties(constructionUser, constructionUserVo); + // 关联分包公司信息 + Long contractorId = constructionUser.getContractorId(); + SubContractorVo contractor = null; + if (contractorIdContractorMap.containsKey(contractorId)) { + contractor = contractorService.getVo(contractorIdContractorMap.get(contractorId).getFirst()); + } + constructionUserVo.setContractorVo(contractor); + // 关联工资标准 + // 构造相应的 key + String key = constructionUser.getTypeOfWork() + "_" + constructionUser.getWageMeasureUnit(); + // 如果映射中存在对应的数据,则设置工资 + if (workWageMap.containsKey(key)) { + constructionUserVo.setStandardSalary(workWageMap.get(key)); + } + // 关联施工人员文件上传状态 + long count = fileCountMap.getOrDefault(constructionUser.getId(), 0L); + if (count <= 0) { + constructionUserVo.setFileUploadStatus(SubConstructionUserFileStatusEnum.NOUPLOAD.getValue()); + } else if (count < fileTypeSize) { + constructionUserVo.setFileUploadStatus(SubConstructionUserFileStatusEnum.PARTUPLOAD.getValue()); + } else if (count == fileTypeSize) { + constructionUserVo.setFileUploadStatus(SubConstructionUserFileStatusEnum.UPLOAD.getValue()); + } + // 解密身份证号码 + String decrypt = idCardEncryptorUtil.decrypt(constructionUserVo.getSfzNumber()); + String hide = DesensitizedUtil.idCardNum(decrypt, 1, 2); + constructionUserVo.setSfzNumber(hide); + // 隐藏手机号码 + String hidePhone = DesensitizedUtil.mobilePhone(constructionUserVo.getPhone()); + constructionUserVo.setPhone(hidePhone); + // 隐藏银行卡号 + String hideBank = DesensitizedUtil.bankCard(constructionUserVo.getYhkNumber()); + constructionUserVo.setYhkNumber(hideBank); + return constructionUserVo; + }).toList(); + constructionUserVoPage.setRecords(constructionUserVoList); + return constructionUserVoPage; + } + + /** + * 获取施工人员考勤分页对象视图 + * + * @param req 施工人员考勤分页查询条件 + * @return 施工人员考勤分页对象视图 + */ + @Override + public Page getAttendanceTotalVoPage(SubConstructionUserAttendanceQueryReq req, + PageQuery pageQuery) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + // 从对象中取值 + String userName = req.getUserName(); + Long projectId = req.getProjectId(); + Long teamId = req.getTeamId(); + String typeOfWork = req.getTypeOfWork(); + String clockDate = req.getClockDate(); + // 联表查询 + LambdaQueryWrapper attendanceLqw = Wrappers.lambdaQuery(BusAttendance.class) + .eq(BusAttendance::getProjectId, projectId); + if (ObjectUtils.isNotEmpty(clockDate)) { + String clockMonth = clockDate.substring(0, 7); + // 校验月份格式 + if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { + throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); + } + // 解析月份 + YearMonth yearMonth = YearMonth.parse(clockMonth); + // 判断是否大于当前月份 + if (yearMonth.isAfter(YearMonth.now())) { + throw new ServiceException("不能查看大于当前月份的记录", HttpStatus.BAD_REQUEST); + } + // 计算当月第一天 / 最后一天 + Date start = DateUtils.toDate(yearMonth.atDay(1)); + Date end = DateUtils.toDate(yearMonth.atEndOfMonth()); + attendanceLqw.between(BusAttendance::getClockDate, start, end); + List userIdList = attendanceService.list(attendanceLqw) + .stream().map(BusAttendance::getUserId).toList(); + if (CollUtil.isNotEmpty(userIdList)) { + lqw.in(SubConstructionUser::getId, userIdList); + } + } + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), SubConstructionUser::getUserName, userName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubConstructionUser::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), SubConstructionUser::getTeamId, teamId); + lqw.eq(StringUtils.isNotBlank(typeOfWork), SubConstructionUser::getTypeOfWork, typeOfWork); + // 查询当前项目下的黑名单人员 + List blackUserIdList = constructionBlacklistService.queryIdListByProjectId(projectId); + // 查询结果移除黑名单人员 + if (CollUtil.isNotEmpty(blackUserIdList)) { + lqw.notIn(SubConstructionUser::getId, blackUserIdList); + } + // 分页查询获取数据 + Page constructionUserPage = this.page(pageQuery.build(), lqw); + List constructionUserList = constructionUserPage.getRecords(); + Page constructionUserAttendanceTotalPage = new Page<>( + constructionUserPage.getCurrent(), + constructionUserPage.getSize(), + constructionUserPage.getTotal()); + if (CollUtil.isEmpty(constructionUserList)) { + return constructionUserAttendanceTotalPage; + } + // 获取施工人员id列表 + List userIdList = constructionUserList.stream().map(SubConstructionUser::getId).toList(); + // 关联查询施工人员考勤列表 + attendanceLqw.in(BusAttendance::getUserId, userIdList); + Map> userIdBusAttendanceListMap = attendanceService.list(attendanceLqw) + .stream().collect(Collectors.groupingBy(BusAttendance::getUserId)); + // 填充信息 + List userAttendanceTotalList = constructionUserList.stream().map(constructionUser -> { + SubConstructionUserAttendanceTotalVo constructionUserAttendanceTotalResp = new SubConstructionUserAttendanceTotalVo(); + Long id = constructionUser.getId(); + BeanUtils.copyProperties(constructionUser, constructionUserAttendanceTotalResp); + // 关联施工人员考勤信息 + int attendanceDays = 0; + int lateDays = 0; + int leaveEarlyDays = 0; + int unClockDays = 0; + int leaveDays = 0; + if (userIdBusAttendanceListMap.containsKey(id)) { + List attendanceList = userIdBusAttendanceListMap.get(id); + if (CollUtil.isNotEmpty(attendanceList)) { + // 1. 按打卡日期分组 + Map> dailyMap = attendanceList.stream() + .collect(Collectors.groupingBy(BusAttendance::getClockDate)); + // 2. 对每一天的记录计算状态 + for (List dailyList : dailyMap.values()) { + String clockInStatus = null; + String clockOutStatus = null; + String clockAllDayStatus = null; + // 获取上下班状态 + for (BusAttendance attendance : dailyList) { + if (BusAttendanceCommuterEnum.CLOCKIN.getValue().equals(attendance.getCommuter())) { + clockInStatus = attendance.getClockStatus(); + } else if (BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getCommuter())) { + clockOutStatus = attendance.getClockStatus(); + } else { + clockAllDayStatus = attendance.getClockStatus(); + } + } + // 统计考勤状态 + if (BusAttendanceClockStatusEnum.LATE.getValue().equals(clockInStatus)) { + lateDays++; + } + if (BusAttendanceClockStatusEnum.LEAVEEARLY.getValue().equals(clockOutStatus)) { + leaveEarlyDays++; + } + if (BusAttendanceClockStatusEnum.LEAVE.getValue().equals(clockAllDayStatus)) { + leaveDays++; + } else { + if (clockInStatus == null || BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus)) { + unClockDays++; + } + if (clockOutStatus == null || BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { + unClockDays++; + } + } + } + attendanceDays = dailyMap.size() - leaveDays; + } + } + constructionUserAttendanceTotalResp.setAttendanceDays(attendanceDays); + constructionUserAttendanceTotalResp.setLateDays(lateDays); + constructionUserAttendanceTotalResp.setLeaveEarlyDays(leaveEarlyDays); + constructionUserAttendanceTotalResp.setUnClockDays(unClockDays); + constructionUserAttendanceTotalResp.setLeaveDays(leaveDays); + return constructionUserAttendanceTotalResp; + }).toList(); + constructionUserAttendanceTotalPage.setRecords(userAttendanceTotalList); + return constructionUserAttendanceTotalPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorMaterialRecordServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorMaterialRecordServiceImpl.java new file mode 100644 index 0000000..92d0102 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorMaterialRecordServiceImpl.java @@ -0,0 +1,302 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.SubContractorMaterial; +import org.dromara.contractor.domain.SubContractorMaterialRecord; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordCreateReq; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordQueryReq; +import org.dromara.contractor.domain.dto.contractormaterialrecord.SubContractorMaterialRecordUpdateReq; +import org.dromara.contractor.domain.enums.SubContractorRecordEnum; +import org.dromara.contractor.domain.vo.contractormaterialrecord.SubContractorMaterialRecordVo; +import org.dromara.contractor.mapper.SubContractorMaterialRecordMapper; +import org.dromara.contractor.service.ISubContractorMaterialRecordService; +import org.dromara.contractor.service.ISubContractorMaterialService; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 分包方物料记录Service业务层处理 + * + * @author lilemy + * @date 2025-06-27 + */ +@Service +public class SubContractorMaterialRecordServiceImpl extends ServiceImpl + implements ISubContractorMaterialRecordService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISubContractorService contractorService; + + @Resource + private ISubContractorMaterialService contractorMaterialService; + + /** + * 查询分包方物料记录 + * + * @param id 主键 + * @return 分包方物料记录 + */ + @Override + public SubContractorMaterialRecordVo queryById(Long id) { + SubContractorMaterialRecord entity = this.getById(id); + if (entity == null) { + throw new ServiceException("分包方物料记录信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(entity); + } + + /** + * 分页查询分包方物料记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方物料记录分页列表 + */ + @Override + public TableDataInfo queryPageList(SubContractorMaterialRecordQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的分包方物料记录列表 + * + * @param req 查询条件 + * @return 分包方物料记录列表 + */ + @Override + public List queryList(SubContractorMaterialRecordQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增分包方物料记录 + * + * @param req 分包方物料记录 + * @return 新增分包方物料记录主键id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(SubContractorMaterialRecordCreateReq req) { + SubContractorMaterialRecord entry = new SubContractorMaterialRecord(); + BeanUtils.copyProperties(req, entry); + Long contractorMaterialId = req.getContractorMaterialId(); + if (contractorMaterialId == null) { + throw new ServiceException("物料id不能为空", HttpStatus.BAD_REQUEST); + } + SubContractorMaterial contractorMaterial = contractorMaterialService.getById(contractorMaterialId); + if (contractorMaterial == null) { + throw new ServiceException("分包方物料不存在", HttpStatus.NOT_FOUND); + } + // 填充默认值 + entry.setProjectId(contractorMaterial.getProjectId()); + entry.setContractorId(contractorMaterial.getContractorId()); + String recordType = req.getRecordType(); + BigDecimal recordNumber = req.getRecordNumber(); + // 同步更新工具数量 + BigDecimal number = this.computeRemainingMaterialNumber(contractorMaterial, recordType, recordNumber); + entry.setRemainingNumber(number); + boolean save = this.save(entry); + if (!save) { + throw new ServiceException("保存分包方物料记录失败", HttpStatus.ERROR); + } + return entry.getId(); + } + + /** + * 修改分包方物料记录 + * + * @param req 分包方物料记录 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(SubContractorMaterialRecordUpdateReq req) { + SubContractorMaterialRecord entry = new SubContractorMaterialRecord(); + BeanUtils.copyProperties(req, entry); + SubContractorMaterialRecord contractorMaterialEntry = this.getById(entry.getId()); + if (contractorMaterialEntry == null) { + throw new ServiceException("修改分包方物料记录失败,数据不存在", HttpStatus.NOT_FOUND); + } + SubContractorMaterial contractorMaterial = contractorMaterialService.getById(contractorMaterialEntry.getContractorMaterialId()); + if (contractorMaterial == null) { + throw new ServiceException("分包方物料不存在", HttpStatus.NOT_FOUND); + } + String recordType = contractorMaterialEntry.getRecordType(); + BigDecimal recordNumber = req.getRecordNumber(); + // 同步更新工具数量 + BigDecimal number = this.computeRemainingMaterialNumber(contractorMaterial, recordType, recordNumber); + entry.setRemainingNumber(number); + boolean result = this.updateById(entry); + if (!result) { + throw new ServiceException("修改分包方物料记录失败", HttpStatus.ERROR); + } + return true; + } + + + /** + * 校验并批量删除分包方物料记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List list = this.listByIds(ids); + if (isValid) { + List projectIdList = list.stream().map(SubContractorMaterialRecord::getProjectId).toList(); + projectService.validAuth(projectIdList, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取分包方物料记录视图对象 + * + * @param contractorMaterialRecord 分包方物料记录对象 + * @return 分包方物料记录视图对象 + */ + @Override + public SubContractorMaterialRecordVo getVo(SubContractorMaterialRecord contractorMaterialRecord) { + SubContractorMaterialRecordVo vo = new SubContractorMaterialRecordVo(); + if (contractorMaterialRecord == null) { + throw new ServiceException("数据不存在"); + } + BeanUtils.copyProperties(contractorMaterialRecord, vo); + SubContractorMaterial contractorMaterial = contractorMaterialService.getById(vo.getContractorMaterialId()); + if (contractorMaterial != null) { + vo.setContractorMaterialName(contractorMaterial.getMaterialName()); + } + SubContractor contractor = contractorService.getById(vo.getContractorId()); + if (contractor != null) { + vo.setContractorName(contractor.getName()); + } + return vo; + } + + /** + * 获取分包方物料记录查询条件封装 + * + * @param req 分包方物料记录查询条件 + * @return 分包方物料记录查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubContractorMaterialRecordQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long contractorId = req.getContractorId(); + Long contractorMaterialId = req.getContractorMaterialId(); + String recordType = req.getRecordType(); + String usedPosition = req.getUsedPosition(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubContractorMaterialRecord::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubContractorMaterialRecord::getContractorId, contractorId); + lqw.eq(ObjectUtils.isNotEmpty(contractorMaterialId), SubContractorMaterialRecord::getContractorMaterialId, contractorMaterialId); + lqw.eq(StringUtils.isNotBlank(recordType), SubContractorMaterialRecord::getRecordType, recordType); + lqw.like(StringUtils.isNotBlank(usedPosition), SubContractorMaterialRecord::getUsedPosition, usedPosition); + return lqw; + } + + /** + * 获取分包方物料记录分页对象视图 + * + * @param contractorMaterialRecordPage 分包方物料记录分页对象 + * @return 分包方物料记录分页对象视图 + */ + @Override + public Page getVoPage(Page contractorMaterialRecordPage) { + List contractorMaterialEntryList = contractorMaterialRecordPage.getRecords(); + Page contractorMaterialEntryVoPage = new Page<>( + contractorMaterialRecordPage.getCurrent(), + contractorMaterialRecordPage.getSize(), + contractorMaterialRecordPage.getTotal()); + if (CollUtil.isEmpty(contractorMaterialEntryList)) { + return contractorMaterialEntryVoPage; + } + Set contractorIdList = contractorMaterialEntryList.stream().map(SubContractorMaterialRecord::getContractorId).collect(Collectors.toSet()); + Map contractorMap = contractorService.listByIds(contractorIdList) + .stream().collect(Collectors.toMap(SubContractor::getId, v -> v)); + Set contractorMaterialIdList = contractorMaterialEntryList.stream().map(SubContractorMaterialRecord::getContractorMaterialId).collect(Collectors.toSet()); + Map contractorMaterialMap = contractorMaterialService.listByIds(contractorMaterialIdList) + .stream().collect(Collectors.toMap(SubContractorMaterial::getId, v -> v)); + List contractorMaterialEntryVoList = contractorMaterialEntryList.stream().map(entity -> { + SubContractorMaterialRecordVo vo = new SubContractorMaterialRecordVo(); + BeanUtils.copyProperties(entity, vo); + if (contractorMaterialMap.containsKey(entity.getContractorMaterialId())) { + vo.setContractorMaterialName(contractorMaterialMap.get(entity.getContractorMaterialId()).getMaterialName()); + } + if (contractorMap.containsKey(entity.getContractorId())) { + vo.setContractorName(contractorMap.get(entity.getContractorId()).getName()); + } + return vo; + }).toList(); + contractorMaterialEntryVoPage.setRecords(contractorMaterialEntryVoList); + return contractorMaterialEntryVoPage; + } + + /** + * 计算剩余库存并更新库存对象返回剩余数量 + * + * @param contractorMaterial 当前库存工具 + * @param recordType 操作类型(入库/出库) + * @param recordNumber 本次操作数量 + * @return 剩余数量 + */ + private BigDecimal computeRemainingMaterialNumber(SubContractorMaterial contractorMaterial, String recordType, BigDecimal recordNumber) { + if (recordNumber == null) { + throw new ServiceException("物料数量不能为空", HttpStatus.ERROR); + } + BigDecimal materialNumber = contractorMaterial.getMaterialNumber(); + SubContractorMaterial newContractorMaterial = new SubContractorMaterial(); + newContractorMaterial.setId(contractorMaterial.getId()); + BigDecimal result; + if (SubContractorRecordEnum.PUT.getValue().equals(recordType)) { + result = materialNumber.add(recordNumber); + } else if (SubContractorRecordEnum.OUT.getValue().equals(recordType)) { + result = materialNumber.subtract(recordNumber); + if (result.compareTo(BigDecimal.ZERO) < 0) { + throw new ServiceException("出库数量不能大于库存数量", HttpStatus.ERROR); + } + } else { + throw new ServiceException("分包方物料记录类型错误", HttpStatus.BAD_REQUEST); + } + newContractorMaterial.setMaterialNumber(result); + boolean update = contractorMaterialService.updateById(newContractorMaterial); + if (!update) { + throw new ServiceException("更新分包方物料信息异常", HttpStatus.ERROR); + } + return result; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorMaterialServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorMaterialServiceImpl.java new file mode 100644 index 0000000..bc3b2b3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorMaterialServiceImpl.java @@ -0,0 +1,246 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.SubContractorMaterial; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialCreateReq; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialQueryReq; +import org.dromara.contractor.domain.dto.contractormaterial.SubContractorMaterialUpdateReq; +import org.dromara.contractor.domain.vo.contractormaterial.SubContractorMaterialVo; +import org.dromara.contractor.mapper.SubContractorMaterialMapper; +import org.dromara.contractor.service.ISubContractorMaterialService; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 分包方物料Service业务层处理 + * + * @author lilemy + * @date 2025-06-27 + */ +@Service +public class SubContractorMaterialServiceImpl extends ServiceImpl + implements ISubContractorMaterialService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISubContractorService contractorService; + + /** + * 查询分包方物料 + * + * @param id 主键 + * @return 分包方物料 + */ + @Override + public SubContractorMaterialVo queryById(Long id) { + SubContractorMaterial contractorMaterial = this.getById(id); + if (contractorMaterial == null) { + throw new ServiceException("分包方物料信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(contractorMaterial); + } + + /** + * 分页查询分包方物料列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方物料分页列表 + */ + @Override + public TableDataInfo queryPageList(SubContractorMaterialQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的分包方物料列表 + * + * @param req 查询条件 + * @return 分包方物料列表 + */ + @Override + public List queryList(SubContractorMaterialQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增分包方物料 + * + * @param req 分包方物料 + * @return 新增分包物料主键id + */ + @Override + public Long insertByBo(SubContractorMaterialCreateReq req) { + SubContractorMaterial contractorMaterial = new SubContractorMaterial(); + BeanUtils.copyProperties(req, contractorMaterial); + validEntityBeforeSave(contractorMaterial, true); + boolean result = this.save(contractorMaterial); + if (!result) { + throw new ServiceException("分包方物料新增失败", HttpStatus.ERROR); + } + return contractorMaterial.getId(); + } + + /** + * 修改分包方物料 + * + * @param req 分包方物料 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(SubContractorMaterialUpdateReq req) { + Long id = req.getId(); + SubContractorMaterial oldContractorMaterial = this.getById(id); + if (oldContractorMaterial == null) { + throw new ServiceException("修改分包方物料失败,数据不存在", HttpStatus.NOT_FOUND); + } + SubContractorMaterial contractorMaterial = new SubContractorMaterial(); + BeanUtils.copyProperties(req, contractorMaterial); + validEntityBeforeSave(contractorMaterial, false); + boolean result = this.updateById(contractorMaterial); + if (!result) { + throw new ServiceException("修改分包方物料失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SubContractorMaterial entity, Boolean create) { + Long projectId = entity.getProjectId(); + Long contractorId = entity.getContractorId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (contractorId == null) { + throw new ServiceException("合同方 id 不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (contractorId != null && contractorService.getById(contractorId) == null) { + throw new ServiceException("对应分包方不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除分包方物料信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List contractorMaterialList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectIdList = contractorMaterialList.stream().map(SubContractorMaterial::getProjectId).distinct().toList(); + projectService.validAuth(projectIdList, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取分包方物料视图对象 + * + * @param contractorMaterial 分包方物料对象 + * @return 分包方物料视图对象 + */ + @Override + public SubContractorMaterialVo getVo(SubContractorMaterial contractorMaterial) { + SubContractorMaterialVo contractorMaterialVo = new SubContractorMaterialVo(); + if (contractorMaterial == null) { + return contractorMaterialVo; + } + BeanUtils.copyProperties(contractorMaterial, contractorMaterialVo); + Long contractorId = contractorMaterial.getContractorId(); + SubContractor contractor = contractorService.getById(contractorId); + contractorMaterialVo.setContractorName(contractor.getName()); + return contractorMaterialVo; + } + + /** + * 获取分包方物料查询条件封装 + * + * @param req 分包方物料查询条件 + * @return 分包方物料查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubContractorMaterialQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long projectId = req.getProjectId(); + Long contractorId = req.getContractorId(); + String materialName = req.getMaterialName(); + String materialType = req.getMaterialType(); + String materialModel = req.getMaterialModel(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubContractorMaterial::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubContractorMaterial::getContractorId, contractorId); + lqw.eq(StringUtils.isNotBlank(materialType), SubContractorMaterial::getMaterialModel, materialType); + lqw.like(StringUtils.isNotBlank(materialName), SubContractorMaterial::getMaterialName, materialName); + lqw.like(StringUtils.isNotBlank(materialModel), SubContractorMaterial::getMaterialModel, materialModel); + return lqw; + } + + /** + * 获取分包方物料分页对象视图 + * + * @param contractorPage 分包方物料分页对象 + * @return 分包方物料分页对象视图 + */ + @Override + public Page getVoPage(Page contractorPage) { + List contractorMaterialList = contractorPage.getRecords(); + Page contractorMaterialVoPage = new Page<>( + contractorPage.getCurrent(), + contractorPage.getSize(), + contractorPage.getTotal()); + if (CollUtil.isEmpty(contractorMaterialList)) { + return contractorMaterialVoPage; + } + Set contractorIdList = contractorMaterialList.stream().map(SubContractorMaterial::getContractorId).collect(Collectors.toSet()); + Map contractorMap = contractorService.listByIds(contractorIdList) + .stream().collect(Collectors.toMap(SubContractor::getId, v -> v)); + List contractorMaterialVoList = contractorMaterialList.stream().map(contractorMaterial -> { + SubContractorMaterialVo contractorMaterialVo = new SubContractorMaterialVo(); + BeanUtils.copyProperties(contractorMaterial, contractorMaterialVo); + Long contractorId = contractorMaterial.getContractorId(); + if (contractorMap.containsKey(contractorId)) { + contractorMaterialVo.setContractorName(contractorMap.get(contractorId).getName()); + } + return contractorMaterialVo; + }).toList(); + contractorMaterialVoPage.setRecords(contractorMaterialVoList); + return contractorMaterialVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorServiceImpl.java new file mode 100644 index 0000000..bbefb14 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorServiceImpl.java @@ -0,0 +1,366 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.PhoneUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.dto.contractor.SubContractorCreateReq; +import org.dromara.contractor.domain.dto.contractor.SubContractorQueryReq; +import org.dromara.contractor.domain.dto.contractor.SubContractorUpdateReq; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; +import org.dromara.contractor.mapper.SubContractorMapper; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.enums.SysDeptTypeEnum; +import org.dromara.system.mapper.SysDeptMapper; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 分包单位Service业务层处理 + * + * @author lilemy + * @date 2025-03-07 + */ +@Service +public class SubContractorServiceImpl extends ServiceImpl + implements ISubContractorService { + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private SysDeptMapper deptMapper; + + /** + * 查询分包单位 + * + * @param id 主键 + * @return 分包单位 + */ + @Override + public SubContractorVo queryById(Long id) { + SubContractor contractor = this.getById(id); + if (contractor == null) { + throw new ServiceException("分包单位信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(contractor); + } + + /** + * 分页查询分包单位列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包单位分页列表 + */ + @Override + public TableDataInfo queryPageList(SubContractorQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + Long deptId = LoginHelper.getDeptId(); + if (deptId != null) { + SysDept dept = deptMapper.selectById(deptId); + if (dept.getDeptType().equals(SysDeptTypeEnum.CONTRACT.getCode())) { + lqw.eq(SubContractor::getId, dept.getContractorId()); + } + } + // 查询数据库 + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的分包单位列表 + * + * @param req 查询条件 + * @return 分包单位列表 + */ + @Override + public List queryList(SubContractorQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + List list = this.list(lqw); + return list.stream().map(this::getVo).toList(); + } + + /** + * 查询未绑定部门的分包单位列表 + * + * @param projectId 项目id + * @return 分包单位列表 + */ + @Override + public List queryListNoDept(Long projectId) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(SysDept::getDeptType, SysDeptTypeEnum.CONTRACT.getCode()); + lqw.isNotNull(SysDept::getContractorId); + List depts = deptMapper.selectList(lqw); + List idList = depts.stream().map(SysDept::getContractorId).toList(); + List contractorList = this.lambdaQuery() + .eq(SubContractor::getProjectId, projectId) + .notIn(CollUtil.isNotEmpty(idList), SubContractor::getId, idList) + .list(); + return contractorList.stream().map(contractor -> { + // 对象转封装类 + SubContractorVo contractorVo = new SubContractorVo(); + BeanUtils.copyProperties(contractor, contractorVo); + return contractorVo; + }).toList(); + } + + /** + * 新增分包单位 + * + * @param req 分包单位 + * @return 新增id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(SubContractorCreateReq req) { + // 将实体类和 DTO 进行转换 + SubContractor contractor = new SubContractor(); + BeanUtils.copyProperties(req, contractor); + // 数据转换 + Map fileMap = req.getFileMap(); + String fileMapStr = JSONUtil.toJsonStr(fileMap); + contractor.setFiles(fileMapStr); + // 数据校验 + validEntityBeforeSave(contractor, true); + String name = req.getName(); + Long count = this.lambdaQuery().eq(SubContractor::getName, name).count(); + if (count > 0) { + throw new ServiceException("分包单位名称重复", HttpStatus.BAD_REQUEST); + } + Long projectId = req.getProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + boolean save = this.save(contractor); + if (!save) { + throw new ServiceException("新增施工人员失败,数据库异常", HttpStatus.ERROR); + } + return contractor.getId(); + } + + /** + * 修改分包单位 + * + * @param req 分包单位 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(SubContractorUpdateReq req) { + // 将实体类和 DTO 进行转换 + SubContractor contractor = new SubContractor(); + BeanUtils.copyProperties(req, contractor); + // 数据转换 + Map fileMap = req.getFileMap(); + String fileMapStr = JSONUtil.toJsonStr(fileMap); + contractor.setFiles(fileMapStr); + // 数据校验 + validEntityBeforeSave(contractor, false); + // 判断是否存在 + SubContractor oldContractor = this.getById(contractor.getId()); + if (oldContractor == null) { + throw new ServiceException("修改施工人员失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断名称是否重复 + if (!oldContractor.getName().equals(req.getName())) { + Long count = this.lambdaQuery().eq(SubContractor::getName, req.getName()).count(); + if (count > 0) { + throw new ServiceException("分包单位名称重复", HttpStatus.BAD_REQUEST); + } + } + // 操作数据库 + return this.updateById(contractor); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SubContractor entity, Boolean create) { + // 做一些数据校验,如唯一约束 + String name = entity.getName(); + String principal = entity.getPrincipal(); + String principalPhone = entity.getPrincipalPhone(); + String custodianPhone = entity.getCustodianPhone(); + if (create) { + if (StringUtils.isBlank(name)) { + throw new ServiceException("分包单位名称不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(principal)) { + throw new ServiceException("分包单位负责人不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(principalPhone)) { + throw new ServiceException("分包单位负责人手机号不能为空", HttpStatus.BAD_REQUEST); + } + } + if (StringUtils.isNotBlank(principalPhone) && !PhoneUtil.isPhone(principalPhone)) { + throw new ServiceException("负责人手机号格式不正确", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isNotBlank(custodianPhone) && !PhoneUtil.isPhone(custodianPhone)) { + throw new ServiceException("管理人手机号格式不正确", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除分包单位信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List contractorList = this.listByIds(ids); + // 做一些业务上的校验,判断是否需要校验 + if (isValid) { + // 仅当前项目下的用户可以删除 + List projectIdList = contractorList.stream().map(SubContractor::getProjectId).toList(); + projectService.validAuth(projectIdList, userId); + // 判断当前分包公司下是否还包含施工人员 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(SubConstructionUser::getContractorId, ids); + if (constructionUserService.count(queryWrapper) > 0) { + throw new ServiceException("删除分包单位失败,删除分包单位下存在施工人员", HttpStatus.BAD_REQUEST); + } + // 判断当前分包公司是否绑定了部门 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.in(SysDept::getContractorId, ids); + List deptList = deptMapper.selectList(lqw); + if (CollUtil.isNotEmpty(deptList)) { + Map contractorMap = contractorList.stream() + .collect(Collectors.toMap(SubContractor::getId, Function.identity())); + Set contractorNames = new HashSet<>(); + for (SysDept dept : deptList) { + Long contractorId = dept.getContractorId(); + SubContractor contractor = contractorMap.get(contractorId); + if (contractor != null) { + contractorNames.add(contractor.getName()); + } + } + if (CollUtil.isNotEmpty(contractorNames)) { + String joinedNames = String.join(",", contractorNames); + throw new ServiceException("删除分包单位失败,以下单位已绑定部门:" + joinedNames, HttpStatus.BAD_REQUEST); + } + } + } + // 判断对应数据是否都存在 + if (contractorList.size() != ids.size()) { + throw new ServiceException("删除分包单位失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取分包公司视图对象 + * + * @param contractor 分包公司对象 + * @return 分包公司视图对象 + */ + @Override + public SubContractorVo getVo(SubContractor contractor) { + // 对象转封装类 + SubContractorVo contractorVo = new SubContractorVo(); + if (contractor == null) { + return contractorVo; + } + BeanUtils.copyProperties(contractor, contractorVo); + // 关联对象存储文件信息 + String files = contractor.getFiles(); + if (StringUtils.isEmpty(files)) { + return contractorVo; + } + Map fileMap = new HashMap<>(); + JSONObject parseObj = JSONUtil.parseObj(files); + parseObj.forEach((key, value) -> fileMap.put(key, (Long) value)); + contractorVo.setFileMap(fileMap); + return contractorVo; + } + + /** + * 获取分包公司查询条件封装 + * + * @param req 分包公司查询条件 + * @return 分包公司查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubContractorQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + String name = req.getName(); + Long projectId = req.getProjectId(); + String principal = req.getPrincipal(); + String principalPhone = req.getPrincipalPhone(); + String custodian = req.getCustodian(); + String custodianPhone = req.getCustodianPhone(); + String contractorType = req.getContractorType(); + String remark = req.getRemark(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), SubContractor::getName, name); + lqw.like(StringUtils.isNotBlank(principal), SubContractor::getPrincipal, principal); + lqw.like(StringUtils.isNotBlank(principalPhone), SubContractor::getPrincipalPhone, principalPhone); + lqw.like(StringUtils.isNotBlank(custodian), SubContractor::getCustodian, custodian); + lqw.like(StringUtils.isNotBlank(custodianPhone), SubContractor::getCustodianPhone, custodianPhone); + lqw.like(StringUtils.isNotBlank(remark), SubContractor::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), SubContractor::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubContractor::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(contractorType), SubContractor::getContractorType, contractorType); + return lqw; + } + + /** + * 获取分包公司分页对象视图 + * + * @param contractorPage 分包公司分页对象 + * @return 分包公司分页对象视图 + */ + @Override + public Page getVoPage(Page contractorPage) { + List contractorList = contractorPage.getRecords(); + Page contractorVoPage = new Page<>( + contractorPage.getCurrent(), + contractorPage.getSize(), + contractorPage.getTotal()); + if (CollUtil.isEmpty(contractorList)) { + return contractorVoPage; + } + List contractorVoList = contractorList.stream().map(this::getVo).toList(); + contractorVoPage.setRecords(contractorVoList); + return contractorVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorToolRecordServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorToolRecordServiceImpl.java new file mode 100644 index 0000000..6aefa54 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorToolRecordServiceImpl.java @@ -0,0 +1,305 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.SubContractorTool; +import org.dromara.contractor.domain.SubContractorToolRecord; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordCreateReq; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordQueryReq; +import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordUpdateReq; +import org.dromara.contractor.domain.enums.SubContractorRecordEnum; +import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo; +import org.dromara.contractor.mapper.SubContractorToolRecordMapper; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.contractor.service.ISubContractorToolRecordService; +import org.dromara.contractor.service.ISubContractorToolService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 分包方工器具记录Service业务层处理 + * + * @author lilemy + * @date 2025-06-26 + */ +@Service +public class SubContractorToolRecordServiceImpl extends ServiceImpl + implements ISubContractorToolRecordService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISubContractorService contractorService; + + @Resource + private ISubContractorToolService contractorToolService; + + /** + * 查询分包方工器具记录 + * + * @param id 主键 + * @return 分包方工器具记录 + */ + @Override + public SubContractorToolRecordVo queryById(Long id) { + SubContractorToolRecord entity = this.getById(id); + if (entity == null) { + throw new ServiceException("分包方工器具记录信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(entity); + } + + /** + * 分页查询分包方工器具记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方工器具记录分页列表 + */ + @Override + public TableDataInfo queryPageList(SubContractorToolRecordQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的分包方工器具记录列表 + * + * @param req 查询条件 + * @return 分包方工器具记录列表 + */ + @Override + public List queryList(SubContractorToolRecordQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增分包方工器具记录 + * + * @param req 分包方工器具记录 + * @return 新增分包方工器具记录主键id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(SubContractorToolRecordCreateReq req) { + SubContractorToolRecord entry = new SubContractorToolRecord(); + BeanUtils.copyProperties(req, entry); + Long contractorToolId = req.getContractorToolId(); + if (contractorToolId == null) { + throw new ServiceException("工器具id不能为空", HttpStatus.BAD_REQUEST); + } + SubContractorTool contractorTool = contractorToolService.getById(contractorToolId); + if (contractorTool == null) { + throw new ServiceException("分包方工器具不存在", HttpStatus.NOT_FOUND); + } + // 填充默认值 + entry.setProjectId(contractorTool.getProjectId()); + entry.setContractorId(contractorTool.getContractorId()); + String recordType = req.getRecordType(); + BigDecimal recordNumber = req.getRecordNumber(); + // 同步更新工具数量 + BigDecimal number = this.computeRemainingToolNumber(contractorTool, recordType, recordNumber); + entry.setRemainingNumber(number); + boolean save = this.save(entry); + if (!save) { + throw new ServiceException("保存分包方工器具记录失败", HttpStatus.ERROR); + } + return entry.getId(); + } + + /** + * 修改分包方工器具记录 + * + * @param req 分包方工器具记录 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(SubContractorToolRecordUpdateReq req) { + SubContractorToolRecord entry = new SubContractorToolRecord(); + BeanUtils.copyProperties(req, entry); + SubContractorToolRecord contractorToolEntry = this.getById(entry.getId()); + if (contractorToolEntry == null) { + throw new ServiceException("修改分包方工器具记录失败,数据不存在", HttpStatus.NOT_FOUND); + } + SubContractorTool contractorTool = contractorToolService.getById(contractorToolEntry.getContractorToolId()); + if (contractorTool == null) { + throw new ServiceException("分包方工器具不存在", HttpStatus.NOT_FOUND); + } + String recordType = contractorToolEntry.getRecordType(); + BigDecimal recordNumber = req.getRecordNumber(); + // 同步更新工具数量 + BigDecimal number = this.computeRemainingToolNumber(contractorTool, recordType, recordNumber); + entry.setRemainingNumber(number); + boolean result = this.updateById(entry); + if (!result) { + throw new ServiceException("修改分包方工器具记录失败", HttpStatus.ERROR); + } + return true; + } + + + /** + * 校验并批量删除分包方工器具记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List list = this.listByIds(ids); + if (isValid) { + List projectIdList = list.stream().map(SubContractorToolRecord::getProjectId).toList(); + projectService.validAuth(projectIdList, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取分包方工器具记录视图对象 + * + * @param subContractorToolRecord 分包方工器具记录对象 + * @return 分包方工器具记录视图对象 + */ + @Override + public SubContractorToolRecordVo getVo(SubContractorToolRecord subContractorToolRecord) { + SubContractorToolRecordVo vo = new SubContractorToolRecordVo(); + if (subContractorToolRecord == null) { + throw new ServiceException("数据不存在"); + } + BeanUtils.copyProperties(subContractorToolRecord, vo); + SubContractorTool contractorTool = contractorToolService.getById(vo.getContractorToolId()); + if (contractorTool != null) { + vo.setContractorToolName(contractorTool.getToolName()); + } + SubContractor contractor = contractorService.getById(vo.getContractorId()); + if (contractor != null) { + vo.setContractorName(contractor.getName()); + } + return vo; + } + + /** + * 获取分包方工器具记录查询条件封装 + * + * @param req 分包方工器具记录查询条件 + * @return 分包方工器具记录查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubContractorToolRecordQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long contractorId = req.getContractorId(); + Long contractorToolId = req.getContractorToolId(); + String checkNum = req.getCheckNum(); + String checkDept = req.getCheckDept(); + String recordType = req.getRecordType(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubContractorToolRecord::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubContractorToolRecord::getContractorId, contractorId); + lqw.eq(ObjectUtils.isNotEmpty(contractorToolId), SubContractorToolRecord::getContractorToolId, contractorToolId); + lqw.eq(StringUtils.isNotBlank(recordType), SubContractorToolRecord::getRecordType, recordType); + lqw.like(StringUtils.isNotBlank(checkNum), SubContractorToolRecord::getCheckNum, checkNum); + lqw.like(StringUtils.isNotBlank(checkDept), SubContractorToolRecord::getCheckDept, checkDept); + return lqw; + } + + /** + * 获取分包方工器具记录分页对象视图 + * + * @param contractorToolRecordPage 分包方工器具记录分页对象 + * @return 分包方工器具记录分页对象视图 + */ + @Override + public Page getVoPage(Page contractorToolRecordPage) { + List contractorToolEntryList = contractorToolRecordPage.getRecords(); + Page contractorToolEntryVoPage = new Page<>( + contractorToolRecordPage.getCurrent(), + contractorToolRecordPage.getSize(), + contractorToolRecordPage.getTotal()); + if (CollUtil.isEmpty(contractorToolEntryList)) { + return contractorToolEntryVoPage; + } + Set contractorIdList = contractorToolEntryList.stream().map(SubContractorToolRecord::getContractorId).collect(Collectors.toSet()); + Map contractorMap = contractorService.listByIds(contractorIdList) + .stream().collect(Collectors.toMap(SubContractor::getId, v -> v)); + Set contractorToolIdList = contractorToolEntryList.stream().map(SubContractorToolRecord::getContractorToolId).collect(Collectors.toSet()); + Map contractorToolMap = contractorToolService.listByIds(contractorToolIdList) + .stream().collect(Collectors.toMap(SubContractorTool::getId, v -> v)); + List contractorToolEntryVoList = contractorToolEntryList.stream().map(entity -> { + SubContractorToolRecordVo vo = new SubContractorToolRecordVo(); + BeanUtils.copyProperties(entity, vo); + if (contractorToolMap.containsKey(entity.getContractorToolId())) { + vo.setContractorToolName(contractorToolMap.get(entity.getContractorToolId()).getToolName()); + } + if (contractorMap.containsKey(entity.getContractorId())) { + vo.setContractorName(contractorMap.get(entity.getContractorId()).getName()); + } + return vo; + }).toList(); + contractorToolEntryVoPage.setRecords(contractorToolEntryVoList); + return contractorToolEntryVoPage; + } + + /** + * 计算剩余库存并更新库存对象返回剩余数量 + * + * @param contractorTool 当前库存工具 + * @param recordType 操作类型(入库/出库) + * @param recordNumber 本次操作数量 + * @return 剩余数量 + */ + private BigDecimal computeRemainingToolNumber(SubContractorTool contractorTool, String recordType, BigDecimal recordNumber) { + if (recordNumber == null) { + throw new ServiceException("工器具数量不能为空", HttpStatus.ERROR); + } + BigDecimal toolNumber = contractorTool.getToolNumber(); + SubContractorTool newContractorTool = new SubContractorTool(); + newContractorTool.setId(contractorTool.getId()); + BigDecimal result; + if (SubContractorRecordEnum.PUT.getValue().equals(recordType)) { + result = toolNumber.add(recordNumber); + } else if (SubContractorRecordEnum.OUT.getValue().equals(recordType)) { + result = toolNumber.subtract(recordNumber); + if (result.compareTo(BigDecimal.ZERO) < 0) { + throw new ServiceException("出库数量不能大于库存数量", HttpStatus.ERROR); + } + } else { + throw new ServiceException("分包方工器具记录类型错误", HttpStatus.BAD_REQUEST); + } + newContractorTool.setToolNumber(result); + boolean update = contractorToolService.updateById(newContractorTool); + if (!update) { + throw new ServiceException("更新分包方工器具信息异常", HttpStatus.ERROR); + } + return result; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorToolServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorToolServiceImpl.java new file mode 100644 index 0000000..08808f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubContractorToolServiceImpl.java @@ -0,0 +1,246 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.SubContractorTool; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolCreateReq; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolQueryReq; +import org.dromara.contractor.domain.dto.contractortool.SubContractorToolUpdateReq; +import org.dromara.contractor.domain.vo.contractortool.SubContractorToolVo; +import org.dromara.contractor.mapper.SubContractorToolMapper; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.contractor.service.ISubContractorToolService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 分包方工器具Service业务层处理 + * + * @author lilemy + * @date 2025-06-26 + */ +@Service +public class SubContractorToolServiceImpl extends ServiceImpl + implements ISubContractorToolService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISubContractorService contractorService; + + /** + * 查询分包方工器具 + * + * @param id 主键 + * @return 分包方工器具 + */ + @Override + public SubContractorToolVo queryById(Long id) { + SubContractorTool contractorTool = this.getById(id); + if (contractorTool == null) { + throw new ServiceException("分包方工器具信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(contractorTool); + } + + /** + * 分页查询分包方工器具列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包方工器具分页列表 + */ + @Override + public TableDataInfo queryPageList(SubContractorToolQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的分包方工器具列表 + * + * @param req 查询条件 + * @return 分包方工器具列表 + */ + @Override + public List queryList(SubContractorToolQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增分包方工器具 + * + * @param req 分包方工器具 + * @return 新增分包工器具主键id + */ + @Override + public Long insertByBo(SubContractorToolCreateReq req) { + SubContractorTool contractorTool = new SubContractorTool(); + BeanUtils.copyProperties(req, contractorTool); + validEntityBeforeSave(contractorTool, true); + boolean result = this.save(contractorTool); + if (!result) { + throw new ServiceException("分包方工器具新增失败", HttpStatus.ERROR); + } + return contractorTool.getId(); + } + + /** + * 修改分包方工器具 + * + * @param req 分包方工器具 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(SubContractorToolUpdateReq req) { + Long id = req.getId(); + SubContractorTool oldContractorTool = this.getById(id); + if (oldContractorTool == null) { + throw new ServiceException("修改分包方工器具失败,数据不存在", HttpStatus.NOT_FOUND); + } + SubContractorTool contractorTool = new SubContractorTool(); + BeanUtils.copyProperties(req, contractorTool); + validEntityBeforeSave(contractorTool, false); + boolean result = this.updateById(contractorTool); + if (!result) { + throw new ServiceException("修改分包方工器具失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SubContractorTool entity, Boolean create) { + Long projectId = entity.getProjectId(); + Long contractorId = entity.getContractorId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (contractorId == null) { + throw new ServiceException("合同方 id 不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (contractorId != null && contractorService.getById(contractorId) == null) { + throw new ServiceException("对应分包方不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除分包方工器具信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List contractorToolList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectIdList = contractorToolList.stream().map(SubContractorTool::getProjectId).distinct().toList(); + projectService.validAuth(projectIdList, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取分包方工器具视图对象 + * + * @param contractorTool 分包方工器具对象 + * @return 分包方工器具视图对象 + */ + @Override + public SubContractorToolVo getVo(SubContractorTool contractorTool) { + SubContractorToolVo contractorToolVo = new SubContractorToolVo(); + if (contractorTool == null) { + return contractorToolVo; + } + BeanUtils.copyProperties(contractorTool, contractorToolVo); + Long contractorId = contractorTool.getContractorId(); + SubContractor contractor = contractorService.getById(contractorId); + contractorToolVo.setContractorName(contractor.getName()); + return contractorToolVo; + } + + /** + * 获取分包方工器具查询条件封装 + * + * @param req 分包方工器具查询条件 + * @return 分包方工器具查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubContractorToolQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long projectId = req.getProjectId(); + Long contractorId = req.getContractorId(); + String toolName = req.getToolName(); + String toolType = req.getToolType(); + String toolModel = req.getToolModel(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubContractorTool::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubContractorTool::getContractorId, contractorId); + lqw.eq(StringUtils.isNotBlank(toolType), SubContractorTool::getToolType, toolType); + lqw.like(StringUtils.isNotBlank(toolName), SubContractorTool::getToolName, toolName); + lqw.like(StringUtils.isNotBlank(toolModel), SubContractorTool::getToolModel, toolModel); + return lqw; + } + + /** + * 获取分包方工器具分页对象视图 + * + * @param contractorPage 分包方工器具分页对象 + * @return 分包方工器具分页对象视图 + */ + @Override + public Page getVoPage(Page contractorPage) { + List contractorToolList = contractorPage.getRecords(); + Page contractorToolVoPage = new Page<>( + contractorPage.getCurrent(), + contractorPage.getSize(), + contractorPage.getTotal()); + if (CollUtil.isEmpty(contractorToolList)) { + return contractorToolVoPage; + } + Set contractorIdList = contractorToolList.stream().map(SubContractorTool::getContractorId).collect(Collectors.toSet()); + Map contractorMap = contractorService.listByIds(contractorIdList) + .stream().collect(Collectors.toMap(SubContractor::getId, v -> v)); + List contractorToolVoList = contractorToolList.stream().map(contractorTool -> { + SubContractorToolVo contractorToolVo = new SubContractorToolVo(); + BeanUtils.copyProperties(contractorTool, contractorToolVo); + Long contractorId = contractorTool.getContractorId(); + if (contractorMap.containsKey(contractorId)) { + contractorToolVo.setContractorName(contractorMap.get(contractorId).getName()); + } + return contractorToolVo; + }).toList(); + contractorToolVoPage.setRecords(contractorToolVoList); + return contractorToolVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubSubcontractServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubSubcontractServiceImpl.java new file mode 100644 index 0000000..3a59fd2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubSubcontractServiceImpl.java @@ -0,0 +1,279 @@ +package org.dromara.contractor.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.SubSubcontract; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractCreateReq; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractQueryReq; +import org.dromara.contractor.domain.dto.subcontract.SubSubcontractUpdateReq; +import org.dromara.contractor.domain.vo.subcontract.SubSubcontractVo; +import org.dromara.contractor.mapper.SubSubcontractMapper; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.contractor.service.ISubSubcontractService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 分包合同Service业务层处理 + * + * @author lilemy + * @date 2025-06-25 + */ +@Slf4j +@Service +public class SubSubcontractServiceImpl extends ServiceImpl + implements ISubSubcontractService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISubContractorService contractorService; + + @Resource + private ISysOssService ossService; + + /** + * 查询分包合同 + * + * @param id 主键 + * @return 分包合同 + */ + @Override + public SubSubcontractVo queryById(Long id) { + SubSubcontract subcontract = this.getById(id); + if (subcontract == null) { + throw new ServiceException("分包合同信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(subcontract); + } + + /** + * 分页查询分包合同列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 分包合同分页列表 + */ + @Override + public TableDataInfo queryPageList(SubSubcontractQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的分包合同列表 + * + * @param req 查询条件 + * @return 分包合同列表 + */ + @Override + public List queryList(SubSubcontractQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增分包合同 + * + * @param req 分包合同 + * @return 新增主键id + */ + @Override + public Long insertByBo(SubSubcontractCreateReq req) { + SubSubcontract subcontract = new SubSubcontract(); + BeanUtils.copyProperties(req, subcontract); + validEntityBeforeSave(subcontract); + Long count = this.lambdaQuery() + .eq(SubSubcontract::getProjectId, req.getProjectId()) + .eq(SubSubcontract::getContractorId, req.getContractorId()) + .eq(SubSubcontract::getContractFileId, req.getContractFileId()) + .count(); + if (count > 0) { + throw new ServiceException("已关联该项目合同", HttpStatus.BAD_REQUEST); + } + boolean save = this.save(subcontract); + if (!save) { + throw new ServiceException("分包合同新增失败", HttpStatus.ERROR); + } + return subcontract.getId(); + } + + /** + * 修改分包合同 + * + * @param req 分包合同 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(SubSubcontractUpdateReq req) { + SubSubcontract subcontract = new SubSubcontract(); + BeanUtils.copyProperties(req, subcontract); + validEntityBeforeSave(subcontract); + Long id = req.getId(); + SubSubcontract oldSubcontract = this.getById(id); + if (oldSubcontract == null) { + throw new ServiceException("修改分包合同失败,数据不存在", HttpStatus.NOT_FOUND); + } + Long count = this.lambdaQuery() + .eq(SubSubcontract::getProjectId, req.getProjectId()) + .eq(SubSubcontract::getContractorId, req.getContractorId()) + .eq(SubSubcontract::getContractFileId, req.getContractFileId()) + .count(); + if (count > 0) { + throw new ServiceException("已关联该项目合同", HttpStatus.BAD_REQUEST); + } + boolean result = this.updateById(subcontract); + if (!result) { + throw new ServiceException("修改分包合同失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SubSubcontract entity) { + Long projectId = entity.getProjectId(); + Long contractorId = entity.getContractorId(); + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (contractorId == null) { + throw new ServiceException("合同方id不能为空", HttpStatus.BAD_REQUEST); + } + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + SubContractor contractor = contractorService.getById(contractorId); + if (contractor == null) { + throw new ServiceException("对应合同方不存在", HttpStatus.NOT_FOUND); + } + if (!contractor.getProjectId().equals(projectId)) { + throw new ServiceException("分包方不属于当前项目,请重新选择", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除分包合同信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List list = this.listByIds(ids); + if (isValid) { + List projectIdList = list.stream().map(SubSubcontract::getProjectId).toList(); + projectService.validAuth(projectIdList, userId); + } + // 关联删除文件 + Set fileIdList = list.stream().map(SubSubcontract::getContractFileId).collect(Collectors.toSet()); + Boolean result = ossService.deleteWithValidByIds(fileIdList, false); + if (!result) { + log.error("删除文件:{}失败", fileIdList); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取分包合同视图 + * + * @param subcontract 分包合同 + * @return 分包合同视图 + */ + @Override + public SubSubcontractVo getVo(SubSubcontract subcontract) { + // 封装对象 + SubSubcontractVo subcontractVo = new SubSubcontractVo(); + if (subcontract == null) { + return subcontractVo; + } + BeanUtils.copyProperties(subcontract, subcontractVo); + return subcontractVo; + } + + /** + * 获取用户和项目关联对象查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SubSubcontractQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long projectId = req.getProjectId(); + Long contractorId = req.getContractorId(); + String contractNumber = req.getContractNumber(); + String contractName = req.getContractName(); + String contractType = req.getContractType(); + lqw.like(StringUtils.isNotBlank(contractNumber), SubSubcontract::getContractNumber, contractNumber); + lqw.like(StringUtils.isNotBlank(contractName), SubSubcontract::getContractName, contractName); + lqw.eq(ObjectUtils.isNotEmpty(projectId), SubSubcontract::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubSubcontract::getContractorId, contractorId); + lqw.eq(StringUtils.isNotBlank(contractType), SubSubcontract::getContractType, contractType); + return lqw; + } + + /** + * 获取分包合同分页视图 + * + * @param subcontractPage 分包合同分页 + * @return 分包合同分页视图 + */ + @Override + public Page getVoPage(Page subcontractPage) { + List subcontractList = subcontractPage.getRecords(); + Page subcontractVoPage = new Page<>( + subcontractPage.getCurrent(), + subcontractPage.getSize(), + subcontractPage.getTotal() + ); + if (CollUtil.isEmpty(subcontractList)) { + return subcontractVoPage; + } + // 获取分包商信息 + Set contractorIdList = subcontractList.stream().map(SubSubcontract::getContractorId).collect(Collectors.toSet()); + Map contractorMap = contractorService.listByIds(contractorIdList) + .stream().collect(Collectors.toMap(SubContractor::getId, v -> v)); + List subcontractVoList = subcontractList.stream().map(entity -> { + SubSubcontractVo subcontractVo = new SubSubcontractVo(); + BeanUtils.copyProperties(entity, subcontractVo); + Long contractorId = entity.getContractorId(); + if (contractorMap.containsKey(contractorId)) { + SubContractor contractor = contractorMap.get(contractorId); + subcontractVo.setContractorName(contractor.getName()); + } + return subcontractVo; + }).toList(); + subcontractVoPage.setRecords(subcontractVoList); + return subcontractVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/controller/BusContactformtemplateController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/controller/BusContactformtemplateController.java new file mode 100644 index 0000000..705d96d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/controller/BusContactformtemplateController.java @@ -0,0 +1,120 @@ +package org.dromara.cory.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.cory.domain.bo.BusContactformtemplateBo; +import org.dromara.cory.domain.vo.BusContactformtemplateVo; +import org.dromara.cory.service.IBusContactformtemplateService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 联系单模板 + * + * @author Lion Li + * @date 2025-07-03 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/cory/contactformtemplate") +public class BusContactformtemplateController extends BaseController { + + private final IBusContactformtemplateService busContactformtemplateService; + + /** + * 查询联系单模板列表 + */ + @SaCheckPermission("cory:contactformtemplate:list") + @GetMapping("/list") + public TableDataInfo list(BusContactformtemplateBo bo, PageQuery pageQuery) { + return busContactformtemplateService.queryPageList(bo, pageQuery); + } + + /** + * 查询联系单模板列表(不分页) + */ + @SaCheckPermission(value = {"cory:contactformtemplate:listNoPage", "cory:contactformtemplate:list"}, mode = SaMode.OR) + @GetMapping("/listNoPage") + public R> listNoPage(BusContactformtemplateBo bo) { + return R.ok(busContactformtemplateService.queryList(bo)); + } + + + /** + * 导出联系单模板列表 + */ + @SaCheckPermission("cory:contactformtemplate:export") + @Log(title = "联系单模板", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusContactformtemplateBo bo, HttpServletResponse response) { + List list = busContactformtemplateService.queryList(bo); + ExcelUtil.exportExcel(list, "联系单模板", BusContactformtemplateVo.class, response); + } + + /** + * 获取联系单模板详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("cory:contactformtemplate:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busContactformtemplateService.queryById(id)); + } + + /** + * 新增联系单模板 + */ + @SaCheckPermission("cory:contactformtemplate:add") + @Log(title = "联系单模板", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add( + BusContactformtemplateBo bo, + @RequestPart("file") MultipartFile file) { + return toAjax(busContactformtemplateService.insertByBo(bo, file)); + } + + + /** + * 修改联系单模板 + */ + @SaCheckPermission("cory:contactformtemplate:edit") + @Log(title = "联系单模板", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusContactformtemplateBo bo) { + return toAjax(busContactformtemplateService.updateByBo(bo)); + } + + /** + * 删除联系单模板 + * + * @param ids 主键串 + */ + @SaCheckPermission("cory:contactformtemplate:remove") + @Log(title = "联系单模板", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busContactformtemplateService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/controller/BusContactnoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/controller/BusContactnoticeController.java new file mode 100644 index 0000000..574d981 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/controller/BusContactnoticeController.java @@ -0,0 +1,106 @@ +package org.dromara.cory.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.cory.domain.bo.BusContactnoticeBo; +import org.dromara.cory.domain.vo.BusContactnoticeVo; +import org.dromara.cory.service.IBusContactnoticeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 联系单 + * + * @author Lion Li + * @date 2025-07-03 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/cory/contactnotice") +public class BusContactnoticeController extends BaseController { + + private final IBusContactnoticeService busContactnoticeService; + + /** + * 查询联系单列表 + */ + @SaCheckPermission("cory:contactnotice:list") + @GetMapping("/list") + public TableDataInfo list(BusContactnoticeBo bo, PageQuery pageQuery) { + return busContactnoticeService.queryPageList(bo, pageQuery); + } + + /** + * 导出联系单列表 + */ + @SaCheckPermission("cory:contactnotice:export") + @Log(title = "联系单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusContactnoticeBo bo, HttpServletResponse response) { + List list = busContactnoticeService.queryList(bo); + ExcelUtil.exportExcel(list, "联系单", BusContactnoticeVo.class, response); + } + + /** + * 获取联系单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("cory:contactnotice:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busContactnoticeService.queryById(id)); + } + + /** + * 新增联系单 + */ + @SaCheckPermission("cory:contactnotice:add") + @Log(title = "联系单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusContactnoticeBo bo) { + return R.ok(busContactnoticeService.insertByBo(bo)); + } + + /** + * 修改联系单 + */ + @SaCheckPermission("cory:contactnotice:edit") + @Log(title = "联系单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusContactnoticeBo bo) { + return R.ok(busContactnoticeService.updateByBo(bo)); + } + + /** + * 删除联系单 + * + * @param ids 主键串 + */ + @SaCheckPermission("cory:contactnotice:remove") + @Log(title = "联系单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busContactnoticeService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/BusContactformtemplate.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/BusContactformtemplate.java new file mode 100644 index 0000000..a389478 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/BusContactformtemplate.java @@ -0,0 +1,64 @@ +package org.dromara.cory.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 联系单模板对象 bus_contactformtemplate + * + * @author Lion Li + * @date 2025-07-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_contactformtemplate") +public class BusContactformtemplate extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增ID + */ + @TableId(value = "id") + private Long id; + + /** + * 项目ID + */ + private String projectId; + + /** + * 模板名称 + */ + private String name; + + /** + * 模板路径 + */ + private String path; + + /** + * 缩略图 + */ + private String thumbnail; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/BusContactnotice.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/BusContactnotice.java new file mode 100644 index 0000000..74928b8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/BusContactnotice.java @@ -0,0 +1,56 @@ +package org.dromara.cory.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 联系单对象 bus_contactnotice + * + * @author Lion Li + * @date 2025-07-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_contactnotice") +public class BusContactnotice extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增ID + */ + @TableId(value = "id") + private Long id; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 模板类型 + */ + private Long type; + + /** + * 文档内容 + */ + private String detail; + + /** + * 备注 + */ + private String remark; + + /** + * 状态 + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/bo/BusContactformtemplateBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/bo/BusContactformtemplateBo.java new file mode 100644 index 0000000..df8e895 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/bo/BusContactformtemplateBo.java @@ -0,0 +1,59 @@ +package org.dromara.cory.domain.bo; + +import com.baomidou.mybatisplus.annotation.TableId; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.cory.domain.BusContactformtemplate; + +import java.util.List; + +/** + * 联系单模板业务对象 bus_contactformtemplate + * + * @author Lion Li + * @date 2025-07-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = BusContactformtemplate.class, reverseConvertGenerate = false) +public class BusContactformtemplateBo extends BaseEntity { + /** + * 自增ID + */ + @TableId(value = "id") + private Long id; + + + /** + * 项目ID + */ + private String projectId; + + /** + * 模板名称 + */ + private String name; + + + /** + * 模板路径 + */ + private String path; + + /** + * 缩略图 + */ + private String thumbnail; + + /** + * 备注 + */ + private String remark; + + /** + * 根据ids查询数据(in) + */ + private List ids; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/bo/BusContactnoticeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/bo/BusContactnoticeBo.java new file mode 100644 index 0000000..0aabefa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/bo/BusContactnoticeBo.java @@ -0,0 +1,49 @@ +package org.dromara.cory.domain.bo; + +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.cory.domain.BusContactnotice; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.util.List; + +/** + * 联系单业务对象 bus_contactnotice + * + * @author Lion Li + * @date 2025-07-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = BusContactnotice.class, reverseConvertGenerate = false) +public class BusContactnoticeBo extends BaseEntity { + + /** + * 项目ID + */ + @NotNull(message = "项目ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long projectId; + + /** + * 模板类型 + */ + @NotNull(message = "模板类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long type; + + /** + * 文档内容 + */ + @NotBlank(message = "文档内容不能为空", groups = { AddGroup.class, EditGroup.class }) + private String detail; + + /** + * 根据模板id,获取对应模板的所有数据 + */ + @NotNull(message = "模板类型不能为空", groups = { QueryGroup.class }) + private List types; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/vo/BusContactformtemplateVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/vo/BusContactformtemplateVo.java new file mode 100644 index 0000000..93d962e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/vo/BusContactformtemplateVo.java @@ -0,0 +1,75 @@ +package org.dromara.cory.domain.vo; + +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.cory.domain.BusContactformtemplate; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 联系单模板视图对象 bus_contactformtemplate + * + * @author Lion Li + * @date 2025-07-03 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusContactformtemplate.class) +public class BusContactformtemplateVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增ID + */ + @ExcelProperty(value = "自增ID") + private Long id; + + /** + * 项目ID + */ + @ExcelProperty(value = "项目ID") + private String projectId; + + /** + * 模板名称 + */ + @ExcelProperty(value = "模板名称") + private String name; + + /** + * 模板路径 + */ + @ExcelProperty(value = "模板路径") + private String path; + + /** + * 缩略图 + */ + @ExcelProperty(value = "缩略图") + private String thumbnail; + + /** + * 缩略图Url + */ + @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "thumbnail") + private String thumbnailUrl; + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/vo/BusContactnoticeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/vo/BusContactnoticeVo.java new file mode 100644 index 0000000..4655bfb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/domain/vo/BusContactnoticeVo.java @@ -0,0 +1,56 @@ +package org.dromara.cory.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.cory.domain.BusContactnotice; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 联系单视图对象 bus_contactnotice + * + * @author Lion Li + * @date 2025-07-03 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusContactnotice.class) +public class BusContactnoticeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增ID + */ + @ExcelProperty(value = "自增ID") + private Long id; + + /** + * 项目ID + */ + @ExcelProperty(value = "项目ID") + private Long projectId; + + /** + * 模板类型 + */ + @ExcelProperty(value = "模板类型") + private Long type; + + /** + * 文档内容 + */ + @ExcelProperty(value = "文档内容") + private String detail; + + /** + * 状态 + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/mapper/BusContactformtemplateMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/mapper/BusContactformtemplateMapper.java new file mode 100644 index 0000000..f8ed3df --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/mapper/BusContactformtemplateMapper.java @@ -0,0 +1,15 @@ +package org.dromara.cory.mapper; + +import org.dromara.cory.domain.BusContactformtemplate; +import org.dromara.cory.domain.vo.BusContactformtemplateVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 联系单模板Mapper接口 + * + * @author Lion Li + * @date 2025-07-03 + */ +public interface BusContactformtemplateMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/mapper/BusContactnoticeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/mapper/BusContactnoticeMapper.java new file mode 100644 index 0000000..8cc96a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/mapper/BusContactnoticeMapper.java @@ -0,0 +1,15 @@ +package org.dromara.cory.mapper; + +import org.dromara.cory.domain.BusContactnotice; +import org.dromara.cory.domain.vo.BusContactnoticeVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 联系单Mapper接口 + * + * @author Lion Li + * @date 2025-07-03 + */ +public interface BusContactnoticeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/IBusContactformtemplateService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/IBusContactformtemplateService.java new file mode 100644 index 0000000..64de8d4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/IBusContactformtemplateService.java @@ -0,0 +1,71 @@ +package org.dromara.cory.service; + +import org.docx4j.openpackaging.exceptions.Docx4JException; +import org.dromara.cory.domain.vo.BusContactformtemplateVo; +import org.dromara.cory.domain.bo.BusContactformtemplateBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +/** + * 联系单模板Service接口 + * + * @author Lion Li + * @date 2025-07-03 + */ +public interface IBusContactformtemplateService { + + /** + * 查询联系单模板 + * + * @param id 主键 + * @return 联系单模板 + */ + BusContactformtemplateVo queryById(Long id); + + /** + * 分页查询联系单模板列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 联系单模板分页列表 + */ + TableDataInfo queryPageList(BusContactformtemplateBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的联系单模板列表 + * + * @param bo 查询条件 + * @return 联系单模板列表 + */ + List queryList(BusContactformtemplateBo bo); + + /** + * 新增联系单模板 + * + * @param bo 联系单模板 + * @return 是否新增成功 + */ + Boolean insertByBo(BusContactformtemplateBo bo, MultipartFile file); + + /** + * 修改联系单模板 + * + * @param bo 联系单模板 + * @return 是否修改成功 + */ + Boolean updateByBo(BusContactformtemplateBo bo); + + /** + * 校验并批量删除联系单模板信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/IBusContactnoticeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/IBusContactnoticeService.java new file mode 100644 index 0000000..70d32bc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/IBusContactnoticeService.java @@ -0,0 +1,68 @@ +package org.dromara.cory.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.cory.domain.bo.BusContactnoticeBo; +import org.dromara.cory.domain.vo.BusContactnoticeVo; + +import java.util.Collection; +import java.util.List; + +/** + * 联系单Service接口 + * + * @author Lion Li + * @date 2025-07-03 + */ +public interface IBusContactnoticeService { + + /** + * 查询联系单 + * + * @param id 主键 + * @return 联系单 + */ + BusContactnoticeVo queryById(Long id); + + /** + * 分页查询联系单列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 联系单分页列表 + */ + TableDataInfo queryPageList(BusContactnoticeBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的联系单列表 + * + * @param bo 查询条件 + * @return 联系单列表 + */ + List queryList(BusContactnoticeBo bo); + + /** + * 新增联系单 + * + * @param bo 联系单 + * @return 是否新增成功 + */ + BusContactnoticeVo insertByBo(BusContactnoticeBo bo); + + /** + * 修改联系单 + * + * @param bo 联系单 + * @return 是否修改成功 + */ + BusContactnoticeVo updateByBo(BusContactnoticeBo bo); + + /** + * 校验并批量删除联系单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/impl/BusContactformtemplateServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/impl/BusContactformtemplateServiceImpl.java new file mode 100644 index 0000000..d8d470d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/impl/BusContactformtemplateServiceImpl.java @@ -0,0 +1,167 @@ +package org.dromara.cory.service.impl; + +import cn.hutool.core.collection.CollUtil; +import jakarta.annotation.Resource; +import org.docx4j.openpackaging.exceptions.Docx4JException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.utils.documentOperations.WordToPdfToImg; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.dromara.cory.domain.bo.BusContactformtemplateBo; +import org.dromara.cory.domain.vo.BusContactformtemplateVo; +import org.dromara.cory.domain.BusContactformtemplate; +import org.dromara.cory.mapper.BusContactformtemplateMapper; +import org.dromara.cory.service.IBusContactformtemplateService; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.Objects; + +import static org.dromara.common.constant.MinioPathConstant.ContactNotice; +import static org.dromara.common.constant.MinioPathConstant.ContactNoticeTemplate; + +/** + * 联系单模板Service业务层处理 + * + * @author Lion Li + * @date 2025-07-03 + */ +@RequiredArgsConstructor +@Service +public class BusContactformtemplateServiceImpl implements IBusContactformtemplateService { + + private final BusContactformtemplateMapper baseMapper; + + @Autowired + private ISysOssService ossService; + + @Autowired + private WordToPdfToImg wordToPdfToImg; + + + /** + * 查询联系单模板 + * + * @param id 主键 + * @return 联系单模板 + */ + @Override + public BusContactformtemplateVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询联系单模板列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 联系单模板分页列表 + */ + @Override + public TableDataInfo queryPageList(BusContactformtemplateBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的联系单模板列表 + * + * @param bo 查询条件 + * @return 联系单模板列表 + */ + @Override + public List queryList(BusContactformtemplateBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(BusContactformtemplateBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(BusContactformtemplate::getId); + lqw.like(StringUtils.isNotBlank(bo.getName()), BusContactformtemplate::getName, bo.getName()); + lqw.in(CollUtil.isNotEmpty(bo.getIds()), BusContactformtemplate::getId, bo.getIds()); +// lqw.eq(StringUtils.isNotBlank(bo.getPath()), BusContactformtemplate::getPath, bo.getPath()); +// lqw.eq(StringUtils.isNotBlank(bo.getThumbnail()), BusContactformtemplate::getThumbnail, bo.getThumbnail()); + return lqw; + } + + /** + * 新增联系单模板 + * + * @param bo 联系单模板 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(BusContactformtemplateBo bo,MultipartFile file) { + //1、将word文档转换成图片,随后存储到minio + try { + SysOssUploadVo wordEntity = ossService.uploadWithNoSave(file, ossService.minioFileName(ContactNoticeTemplate,file)); + if (wordEntity==null) { + throw new RuntimeException("未找到word模板文件!"); + } + SysOssUploadVo imgEntity = wordToPdfToImg.convertWordToImage(file); + if (imgEntity==null) { + throw new RuntimeException("未找到缩略图模板文件!"); + } + bo.setPath(wordEntity.getUrl()); + bo.setThumbnail(imgEntity.getUrl()); + }catch (Exception e){ +// throw new RuntimeException("word转图片错误!"+e.getMessage()); + System.out.println("word转图片错误!"+e.getMessage()); + } + //2、新增数据 + BusContactformtemplate add = MapstructUtils.convert(bo, BusContactformtemplate.class); + validEntityBeforeSave(add); + return baseMapper.insert(add) > 0; + } + + /** + * 修改联系单模板 + * + * @param bo 联系单模板 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusContactformtemplateBo bo) { + BusContactformtemplate busContactformtemplate = new BusContactformtemplate(); + busContactformtemplate.setId(bo.getId()); + busContactformtemplate.setName(bo.getName()); + return baseMapper.updateById(busContactformtemplate) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusContactformtemplate entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除联系单模板信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/impl/BusContactnoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/impl/BusContactnoticeServiceImpl.java new file mode 100644 index 0000000..a9248af --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cory/service/impl/BusContactnoticeServiceImpl.java @@ -0,0 +1,210 @@ +package org.dromara.cory.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.cory.domain.BusContactnotice; +import org.dromara.cory.domain.bo.BusContactnoticeBo; +import org.dromara.cory.domain.vo.BusContactnoticeVo; +import org.dromara.cory.mapper.BusContactnoticeMapper; +import org.dromara.cory.service.IBusContactnoticeService; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 联系单Service业务层处理 + * + * @author Lion Li + * @date 2025-07-03 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class BusContactnoticeServiceImpl implements IBusContactnoticeService { + + private final BusContactnoticeMapper baseMapper; + + /** + * 查询联系单 + * + * @param id 主键 + * @return 联系单 + */ + @Override + public BusContactnoticeVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询联系单列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 联系单分页列表 + */ + @Override + public TableDataInfo queryPageList(BusContactnoticeBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的联系单列表 + * + * @param bo 查询条件 + * @return 联系单列表 + */ + @Override + public List queryList(BusContactnoticeBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(BusContactnoticeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(BusContactnotice::getId); + lqw.eq(bo.getProjectId() != null, BusContactnotice::getProjectId, bo.getProjectId()); + lqw.eq(ObjectUtils.isNotEmpty(bo.getType()), BusContactnotice::getType, bo.getType()); + lqw.in(bo.getTypes() != null, BusContactnotice::getType, bo.getTypes()); + return lqw; + } + + /** + * 新增联系单 + * + * @param bo 联系单 + * @return 是否新增成功 + */ + @Override + public BusContactnoticeVo insertByBo(BusContactnoticeBo bo) { + BusContactnotice add = MapstructUtils.convert(bo, BusContactnotice.class); + if (add == null) { + throw new ServiceException("新增联系单失败,请求参数为空", HttpStatus.ERROR); + } + validEntityBeforeSave(add); + int insert = baseMapper.insert(add); + if (insert <= 0) { + throw new ServiceException("新增联系单失败,请稍后重试", HttpStatus.ERROR); + } + return this.queryById(add.getId()); + } + + /** + * 修改联系单 + * + * @param bo 联系单 + * @return 是否修改成功 + */ + @Override + public BusContactnoticeVo updateByBo(BusContactnoticeBo bo) { + BusContactnotice update = MapstructUtils.convert(bo, BusContactnotice.class); + if (update == null) { + throw new ServiceException("修改联系单失败,请求参数为空", HttpStatus.ERROR); + } + validEntityBeforeSave(update); + BusContactnotice busContactnotice = baseMapper.selectById(update.getId()); + if (busContactnotice == null) { + throw new ServiceException("修改联系单失败,数据不存在", HttpStatus.ERROR); + } + int result = baseMapper.updateById(update); + if (result <= 0) { + throw new ServiceException("修改联系单失败,请稍后重试", HttpStatus.ERROR); + } + return this.queryById(update.getId()); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusContactnotice entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除联系单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.endsWith('contact')") + public void processHandler(ProcessEvent processEvent) { + log.info("联系单审核任务执行了{}", processEvent.toString()); + BusContactnotice contactnotice = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId())); + contactnotice.setStatus(processEvent.getStatus()); + if (processEvent.getSubmit()) { + contactnotice.setStatus(BusinessStatusEnum.WAITING.getStatus()); + } + baseMapper.updateById(contactnotice); + } + + /** + * 执行任务创建监听 + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.endsWith('contact')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("联系单审核任务创建了{}", processTaskEvent.toString()); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @Transactional + @EventListener(condition = "#processDeleteEvent.flowCode.endsWith('contact')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,联系单审核任务执行了{}", processDeleteEvent.toString()); + BusContactnotice contactnotice = baseMapper.selectById(Convert.toLong(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(contactnotice)) { + return; + } + this.deleteWithValidByIds(Collections.singleton(contactnotice.getId()), true); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/constant/DesDesignConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/constant/DesDesignConstant.java new file mode 100644 index 0000000..6125d5a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/constant/DesDesignConstant.java @@ -0,0 +1,39 @@ +package org.dromara.design.constant; + +import org.dromara.common.core.utils.DateUtils; +import org.dromara.design.domain.DesDesignChange; + +import java.text.SimpleDateFormat; + +/** + * @author lilemy + * @date 2025/7/3 19:42 + */ +public interface DesDesignConstant { + + /** + * 设计变更申请单模版路径 + */ + String DESIGN_CHANGE_TEMPLATE_PATH = "template/设计变更申请单模版.docx"; + + /** + * 设计变更申请单文件路径 + */ + String DESIGN_CHANGE_FILE_URL = "docs/design/change/"; + + /** + * 设计变更申请单文件名 + */ + static String getDesignChangeFileUrl(DesDesignChange designChange) { + String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(designChange.getUpdateTime()); + return String.format("%s%s/%s", DESIGN_CHANGE_FILE_URL, designChange.getId(), timestamp); + } + + /** + * 设计变更申请单文件名 + */ + static String getDesignChangeFileName(DesDesignChange designChange) { + String createDate = DateUtils.formatDate(designChange.getCreateTime()); + return String.format("设计变更申请单(%s).docx", createDate); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/constant/DesTechnicalStandardConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/constant/DesTechnicalStandardConstant.java new file mode 100644 index 0000000..931f78e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/constant/DesTechnicalStandardConstant.java @@ -0,0 +1,41 @@ +package org.dromara.design.constant; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/2 15:08 + */ +public interface DesTechnicalStandardConstant { + + /** + * 顶级目录前缀 + */ + String TOP_FOLDER_PREFIX = "doc/design/knowledge/"; + + /** + * 顶级目录名称 + */ + String TOP_FOLDER_NAME = "技术标准管理"; + + /** + * 二级目录名称 + */ + List SECOND_LEVEL_FOLDER_NAME = List.of("设计输入条件", "设计原则", "业主需求清单"); + + /** + * 图片后缀列表 + */ + List PICTURE_SUFFIX_LIST = List.of("jpeg", "jpg", "png", "webp"); + + /** + * 获取顶级目录前缀 + * + * @param projectId 项目id + * @return 顶级目录前缀 + */ + static String getTopFolderPrefix(Long projectId) { + return String.format("%s%s/", TOP_FOLDER_PREFIX, projectId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesDesignChangeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesDesignChangeController.java new file mode 100644 index 0000000..2c0dd3b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesDesignChangeController.java @@ -0,0 +1,107 @@ +package org.dromara.design.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.design.domain.dto.designchange.DesDesignChangeCreateReq; +import org.dromara.design.domain.dto.designchange.DesDesignChangeQueryReq; +import org.dromara.design.domain.dto.designchange.DesDesignChangeUpdateReq; +import org.dromara.design.domain.vo.designchange.DesDesignChangeVo; +import org.dromara.design.service.IDesDesignChangeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设计变更管理 + * + * @author lilemy + * @date 2025-07-03 + */ +@Validated +@RestController +@RequestMapping("/design/designChange") +public class DesDesignChangeController extends BaseController { + + @Resource + private IDesDesignChangeService desDesignChangeService; + + /** + * 查询设计变更管理列表 + */ + @SaCheckPermission("design:designChange:list") + @GetMapping("/list") + public TableDataInfo list(DesDesignChangeQueryReq req, PageQuery pageQuery) { + return desDesignChangeService.queryPageList(req, pageQuery); + } + + /** + * 根据主键导出设计变更单 + */ + @SaCheckPermission("design:designChange:export") + @Log(title = "设计变更管理", businessType = BusinessType.EXPORT) + @PostMapping("/export/word") + public void exportWordById(@NotNull(message = "主键不能为空") Long id, + HttpServletResponse response) { + desDesignChangeService.exportWordById(id, response); + } + + /** + * 获取设计变更管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("design:designChange:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(desDesignChangeService.queryById(id)); + } + + /** + * 新增设计变更管理 + */ + @SaCheckPermission("design:designChange:add") + @Log(title = "设计变更管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DesDesignChangeCreateReq req) { + return R.ok(desDesignChangeService.insertByBo(req)); + } + + /** + * 修改设计变更管理 + */ + @SaCheckPermission("design:designChange:edit") + @Log(title = "设计变更管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DesDesignChangeUpdateReq req) { + return R.ok(desDesignChangeService.updateByBo(req)); + } + + /** + * 删除设计变更管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("design:designChange:remove") + @Log(title = "设计变更管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(desDesignChangeService.deleteByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesDrawingController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesDrawingController.java new file mode 100644 index 0000000..928ce4b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesDrawingController.java @@ -0,0 +1,93 @@ +package org.dromara.design.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.design.domain.dto.drawing.DesDrawingCreateReq; +import org.dromara.design.domain.dto.drawing.DesDrawingQueryReq; +import org.dromara.design.domain.dto.drawing.DesDrawingUpdateReq; +import org.dromara.design.domain.vo.drawing.DesDrawingVo; +import org.dromara.design.service.IDesDrawingService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 图纸管理 + * + * @author lilemy + * @date 2025-07-02 + */ +@Validated +@RestController +@RequestMapping("/design/drawing") +public class DesDrawingController extends BaseController { + + @Resource + private IDesDrawingService desDrawingService; + + /** + * 查询图纸管理列表 + */ + @SaCheckPermission("design:drawing:list") + @GetMapping("/list") + public TableDataInfo list(DesDrawingQueryReq req, PageQuery pageQuery) { + return desDrawingService.queryPageList(req, pageQuery); + } + + /** + * 获取图纸管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("design:drawing:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(desDrawingService.queryById(id)); + } + + /** + * 新增图纸管理 + */ + @SaCheckPermission("design:drawing:add") + @Log(title = "图纸管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@RequestBody DesDrawingCreateReq req) { + return R.ok(desDrawingService.insertByBo(req)); + } + + /** + * 修改图纸管理 + */ + @SaCheckPermission("design:drawing:edit") + @Log(title = "图纸管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@RequestBody DesDrawingUpdateReq req) { + return R.ok(desDrawingService.updateByBo(req)); + } + + /** + * 删除图纸管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("design:drawing:remove") + @Log(title = "图纸管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(desDrawingService.deleteByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesSpecialSchemeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesSpecialSchemeController.java new file mode 100644 index 0000000..39685aa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesSpecialSchemeController.java @@ -0,0 +1,94 @@ +package org.dromara.design.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeCreateReq; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeQueryReq; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeUpdateReq; +import org.dromara.design.domain.vo.specialscheme.DesSpecialSchemeVo; +import org.dromara.design.service.IDesSpecialSchemeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 专项方案管理 + * + * @author lilemy + * @date 2025-07-03 + */ +@Validated +@RestController +@RequestMapping("/design/specialScheme") +public class DesSpecialSchemeController extends BaseController { + + @Resource + private IDesSpecialSchemeService desSpecialSchemeService; + + /** + * 查询专项方案管理列表 + */ + @SaCheckPermission("design:specialScheme:list") + @GetMapping("/list") + public TableDataInfo list(DesSpecialSchemeQueryReq req, PageQuery pageQuery) { + return desSpecialSchemeService.queryPageList(req, pageQuery); + } + + /** + * 获取专项方案管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("design:specialScheme:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(desSpecialSchemeService.queryById(id)); + } + + /** + * 新增专项方案管理 + */ + @SaCheckPermission("design:specialScheme:add") + @Log(title = "专项方案管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@RequestBody DesSpecialSchemeCreateReq req) { + return R.ok(desSpecialSchemeService.insertByBo(req)); + } + + /** + * 修改专项方案管理 + */ + @SaCheckPermission("design:specialScheme:edit") + @Log(title = "专项方案管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DesSpecialSchemeUpdateReq req) { + return R.ok(desSpecialSchemeService.updateByBo(req)); + } + + /** + * 删除专项方案管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("design:specialScheme:remove") + @Log(title = "专项方案管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(desSpecialSchemeService.deleteByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesTechnicalStandardController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesTechnicalStandardController.java new file mode 100644 index 0000000..1b0b8a8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesTechnicalStandardController.java @@ -0,0 +1,160 @@ +package org.dromara.design.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileCreateReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileQueryReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileUpdateReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardQueryReq; +import org.dromara.design.domain.vo.technicalstandard.DesTechnicalStandardVo; +import org.dromara.design.service.IDesTechnicalStandardService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 技术标准管理 + * + * @author lilemy + * @date 2025-07-02 + */ +@Validated +@RestController +@RequestMapping("/design/technicalStandard") +public class DesTechnicalStandardController extends BaseController { + + @Resource + private IDesTechnicalStandardService desTechnicalStandardService; + + /** + * 分页查询技术标准管理文件列表 + */ + @SaCheckPermission("design:technicalStandard:list") + @GetMapping("/file/page") + public TableDataInfo queryFilePageList(DesTechnicalStandardFileQueryReq req, PageQuery pageQuery) { + return desTechnicalStandardService.queryFilePageByFolderId(req, pageQuery); + } + + /** + * 查询技术标准管理文件列表 + */ + @SaCheckPermission("design:technicalStandard:list") + @GetMapping("/file/list/{folderId}") + public R> queryFileListByFolderId(@NotNull(message = "主键不能为空") + @PathVariable Long folderId) { + return R.ok(desTechnicalStandardService.queryFileListByFolderId(folderId)); + } + + /** + * 查询技术标准管理文件树列表 + */ + @SaCheckPermission("design:technicalStandard:list") + @GetMapping("/folder/tree/list") + public R>> queryFolderTreeList(DesTechnicalStandardQueryReq req) { + List> list = desTechnicalStandardService.queryFolderTreeList(req); + return R.ok(list); + } + + /** + * 查询技术标准管理回收站文件列表 + */ + @SaCheckPermission("design:technicalStandard:list") + @GetMapping("/recycleBin/list") + public TableDataInfo queryRecycleBinPageList(DesTechnicalStandardQueryReq req, PageQuery pageQuery) { + return desTechnicalStandardService.queryRecycleBinPageList(req, pageQuery); + } + + /** + * 获取技术标准管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("design:technicalStandard:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(desTechnicalStandardService.queryById(id)); + } + + /** + * 新增技术标准管理文件 + */ + @SaCheckPermission("design:technicalStandard:add") + @Log(title = "技术标准管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/file") + public R add(@RequestPart("file") MultipartFile file, DesTechnicalStandardFileCreateReq req) { + return R.ok(desTechnicalStandardService.insertFile(file, req)); + } + + /** + * 修改技术标准管理 + */ + @SaCheckPermission("design:technicalStandard:edit") + @Log(title = "技术标准管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/file") + public R edit(@RequestBody DesTechnicalStandardFileUpdateReq req) { + return R.ok(desTechnicalStandardService.updateFile(req)); + } + + /** + * 删除技术标准管理文件 + * + * @param id 主键 + */ + @SaCheckPermission("design:technicalStandard:remove") + @Log(title = "技术标准管理", businessType = BusinessType.DELETE) + @DeleteMapping("/file/{id}") + public R remove(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(desTechnicalStandardService.deleteFileById(id)); + } + + /** + * 批量删除技术标准管理回收站文件信息 + * + * @param ids 主键串 + */ + @SaCheckPermission("design:technicalStandard:remove") + @Log(title = "技术标准管理", businessType = BusinessType.DELETE) + @DeleteMapping("/file/recycleBin/{ids}") + public R removeRecycleBin(@NotNull(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(desTechnicalStandardService.deleteRecycleBinFileBatchByIds(List.of(ids))); + } + + /** + * 根据主键id批量恢复 + */ + @SaCheckPermission("design:technicalStandard:recovery") + @Log(title = "技术标准管理", businessType = BusinessType.UPDATE) + @PostMapping("/recovery/{ids}") + public R recoveryBatchById(@NotNull(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(desTechnicalStandardService.recoveryBatchById(List.of(ids))); + } + + /** + * 畅写在线修改保存回调 + */ + @SaCheckPermission("design:technicalStandard:edit") + @PostMapping("/changxie/callback/{id}") + public void singleFileUploads(@NotNull(message = "主键不能为空") + @PathVariable Long id, HttpServletRequest request, HttpServletResponse response) { + desTechnicalStandardService.singleFileUploads(id, request, response); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesDesignChange.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesDesignChange.java new file mode 100644 index 0000000..e55005e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesDesignChange.java @@ -0,0 +1,112 @@ +package org.dromara.design.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 设计变更管理对象 des_design_change + * + * @author lilemy + * @date 2025-07-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("des_design_change") +public class DesDesignChange extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 申请单编号 + */ + private String formNo; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 提出单位 + */ + private String submitUnit; + + /** + * 专业 + */ + private String specialty; + + /** + * 提出日期 + */ + private Date submitDate; + + /** + * 卷册名称 + */ + private String volumeName; + + /** + * 卷册号 + */ + private String volumeNo; + + /** + * 附图 + */ + private String attachmentPic; + + /** + * 变更原因 + */ + private String changeReason; + + /** + * 变更内容 + */ + private String changeContent; + + /** + * 变更费用估算 + */ + private String costEstimation; + + /** + * 变更费用估算计算表 + */ + private String costEstimationFile; + + /** + * 变更文件 + */ + private String fileId; + + /** + * 审核状态 + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesDrawing.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesDrawing.java new file mode 100644 index 0000000..de2d39a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesDrawing.java @@ -0,0 +1,97 @@ +package org.dromara.design.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 图纸管理对象 des_drawing + * + * @author lilemy + * @date 2025-07-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("des_drawing") +public class DesDrawing extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件访问路径 + */ + private Long fileUrl; + + /** + * 文件类型(1过程图纸 2蓝图 3变更图纸) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 原文件id + */ + private Long originalFileId; + + /** + * 是否最新(0否 1是) + */ + private String newest; + + /** + * 审核状态 + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private Date deletedAt; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesSpecialScheme.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesSpecialScheme.java new file mode 100644 index 0000000..7834e67 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesSpecialScheme.java @@ -0,0 +1,82 @@ +package org.dromara.design.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 专项方案管理对象 des_special_scheme + * + * @author lilemy + * @date 2025-07-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("des_special_scheme") +public class DesSpecialScheme extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件访问路径 + */ + private Long fileUrl; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 审核状态 + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private Date deletedAt; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesTechnicalStandard.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesTechnicalStandard.java new file mode 100644 index 0000000..bf1a877 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/DesTechnicalStandard.java @@ -0,0 +1,92 @@ +package org.dromara.design.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 技术标准管理对象 des_technical_standard + * + * @author lilemy + * @date 2025-07-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("des_technical_standard") +public class DesTechnicalStandard extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件访问路径 + */ + private String fileUrl; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 审核状态 + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private Date deletedAt; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeCreateReq.java new file mode 100644 index 0000000..3f6def4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeCreateReq.java @@ -0,0 +1,101 @@ +package org.dromara.design.domain.dto.designchange; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/7/3 18:48 + */ +@Data +public class DesDesignChangeCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8811234168299834882L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 申请单编号 + */ + private String formNo; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 提出单位 + */ + private String submitUnit; + + /** + * 专业 + */ + private String specialty; + + /** + * 提出日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date submitDate; + + /** + * 卷册名称 + */ + private String volumeName; + + /** + * 卷册号 + */ + private String volumeNo; + + /** + * 附图 + */ + private String attachmentPic; + + /** + * 变更原因 + */ + private String changeReason; + + /** + * 变更内容 + */ + private String changeContent; + + /** + * 变更费用估算 + */ + private String costEstimation; + + /** + * 变更费用估算计算表 + */ + private String costEstimationFile; + + /** + * 变更文件 + */ + private String fileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeQueryReq.java new file mode 100644 index 0000000..99bd23b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeQueryReq.java @@ -0,0 +1,66 @@ +package org.dromara.design.domain.dto.designchange; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/7/3 18:48 + */ +@Data +public class DesDesignChangeQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -270854871043405421L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 申请单编号 + */ + private String formNo; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 提出单位 + */ + private String submitUnit; + + /** + * 专业 + */ + private String specialty; + + /** + * 提出日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date submitDate; + + /** + * 卷册名称 + */ + private String volumeName; + + /** + * 卷册号 + */ + private String volumeNo; + + /** + * 审核状态 + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeUpdateReq.java new file mode 100644 index 0000000..3eab45b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/designchange/DesDesignChangeUpdateReq.java @@ -0,0 +1,101 @@ +package org.dromara.design.domain.dto.designchange; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/7/3 18:49 + */ +@Data +public class DesDesignChangeUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1764866203240580206L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 申请单编号 + */ + private String formNo; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 提出单位 + */ + private String submitUnit; + + /** + * 专业 + */ + private String specialty; + + /** + * 提出日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date submitDate; + + /** + * 卷册名称 + */ + private String volumeName; + + /** + * 卷册号 + */ + private String volumeNo; + + /** + * 附图 + */ + private String attachmentPic; + + /** + * 变更原因 + */ + private String changeReason; + + /** + * 变更内容 + */ + private String changeContent; + + /** + * 变更费用估算 + */ + private String costEstimation; + + /** + * 变更费用估算计算表 + */ + private String costEstimationFile; + + /** + * 变更文件 + */ + private String fileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingCreateReq.java new file mode 100644 index 0000000..9cce36a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingCreateReq.java @@ -0,0 +1,48 @@ +package org.dromara.design.domain.dto.drawing; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/2 19:31 + */ +@Data +public class DesDrawingCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 7092100999544181672L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件类型(1过程图纸 2蓝图 3变更图纸) + */ + private String fileType; + + /** + * 文件路径 + */ + private Long fileUrl; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingQueryReq.java new file mode 100644 index 0000000..2f457d3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingQueryReq.java @@ -0,0 +1,48 @@ +package org.dromara.design.domain.dto.drawing; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/2 19:32 + */ +@Data +public class DesDrawingQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8149145849259291103L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件类型(1过程图纸 2蓝图 3变更图纸) + */ + private String fileType; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 是否最新(0否 1是) + */ + private String newest; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingUpdateReq.java new file mode 100644 index 0000000..e870905 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/drawing/DesDrawingUpdateReq.java @@ -0,0 +1,43 @@ +package org.dromara.design.domain.dto.drawing; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/2 19:31 + */ +@Data +public class DesDrawingUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6833934408939323557L; + + /** + * 主键id + */ + private Long id; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private Long fileUrl; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeCreateReq.java new file mode 100644 index 0000000..e7c6093 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeCreateReq.java @@ -0,0 +1,43 @@ +package org.dromara.design.domain.dto.specialscheme; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/3 11:27 + */ +@Data +public class DesSpecialSchemeCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6963615629792446908L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件id + */ + private Long fileUrl; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeQueryReq.java new file mode 100644 index 0000000..91f30e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.design.domain.dto.specialscheme; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/3 11:28 + */ +@Data +public class DesSpecialSchemeQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6490770086658766211L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeUpdateReq.java new file mode 100644 index 0000000..5b9b468 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/specialscheme/DesSpecialSchemeUpdateReq.java @@ -0,0 +1,43 @@ +package org.dromara.design.domain.dto.specialscheme; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/3 11:29 + */ +@Data +public class DesSpecialSchemeUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6314226629118163829L; + + /** + * 主键id + */ + private Long id; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private Long fileUrl; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileCreateReq.java new file mode 100644 index 0000000..450f004 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileCreateReq.java @@ -0,0 +1,33 @@ +package org.dromara.design.domain.dto.technicalstandard; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/2 14:54 + */ +@Data +public class DesTechnicalStandardFileCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8966480198606343837L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileQueryReq.java new file mode 100644 index 0000000..3a5bc30 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileQueryReq.java @@ -0,0 +1,33 @@ +package org.dromara.design.domain.dto.technicalstandard; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/2 14:55 + */ +@Data +public class DesTechnicalStandardFileQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8469150974619675423L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件夹id + */ + private Long folderId; + + /** + * 文件名 + */ + private String fileName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileUpdateReq.java new file mode 100644 index 0000000..f47835a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardFileUpdateReq.java @@ -0,0 +1,38 @@ +package org.dromara.design.domain.dto.technicalstandard; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/2 14:58 + */ +@Data +public class DesTechnicalStandardFileUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8139865110310278870L; + + /** + * 主键id + */ + private Long id; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardQueryReq.java new file mode 100644 index 0000000..aa92d7d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/technicalstandard/DesTechnicalStandardQueryReq.java @@ -0,0 +1,28 @@ +package org.dromara.design.domain.dto.technicalstandard; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/2 15:01 + */ +@Data +public class DesTechnicalStandardQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3045536128635208498L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件名 + */ + private String fileName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/designchange/DesDesignChangeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/designchange/DesDesignChangeVo.java new file mode 100644 index 0000000..0968738 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/designchange/DesDesignChangeVo.java @@ -0,0 +1,132 @@ +package org.dromara.design.domain.vo.designchange; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.design.domain.DesDesignChange; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 设计变更管理视图对象 des_design_change + * + * @author lilemy + * @date 2025-07-03 + */ +@Data +@AutoMapper(target = DesDesignChange.class) +public class DesDesignChangeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 申请单编号 + */ + private String formNo; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 提出单位 + */ + private String submitUnit; + + /** + * 专业 + */ + private String specialty; + + /** + * 提出日期 + */ + private Date submitDate; + + /** + * 卷册名称 + */ + private String volumeName; + + /** + * 卷册号 + */ + private String volumeNo; + + /** + * 附图 + */ + private String attachmentPic; + + /** + * 附图列表 + */ + private List attachmentPicList; + + /** + * 变更原因 + */ + private String changeReason; + + /** + * 变更内容 + */ + private String changeContent; + + /** + * 变更费用估算 + */ + private String costEstimation; + + /** + * 变更费用估算计算表 + */ + private String costEstimationFile; + + /** + * 变更费用估算计算表列表 + */ + private List costEstimationFileList; + + /** + * 变更文件 + */ + private String fileId; + + /** + * 变更文件 + */ + private SysOssVo file; + + /** + * 审核状态 + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/drawing/DesDrawingVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/drawing/DesDrawingVo.java new file mode 100644 index 0000000..8c5f979 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/drawing/DesDrawingVo.java @@ -0,0 +1,91 @@ +package org.dromara.design.domain.vo.drawing; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.design.domain.DesDrawing; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 图纸管理视图对象 des_drawing + * + * @author lilemy + * @date 2025-07-02 + */ +@Data +@AutoMapper(target = DesDrawing.class) +public class DesDrawingVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件访问路径 + */ + private Long fileUrl; + + /** + * 文件类型(1过程图纸 2蓝图 3变更图纸) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 文件 + */ + private SysOssVo file; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 是否最新(0否 1是) + */ + private String newest; + + /** + * 审核状态 + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/specialscheme/DesSpecialSchemeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/specialscheme/DesSpecialSchemeVo.java new file mode 100644 index 0000000..45ac6d7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/specialscheme/DesSpecialSchemeVo.java @@ -0,0 +1,81 @@ +package org.dromara.design.domain.vo.specialscheme; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.design.domain.DesSpecialScheme; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 专项方案管理视图对象 des_special_scheme + * + * @author lilemy + * @date 2025-07-03 + */ +@Data +@AutoMapper(target = DesSpecialScheme.class) +public class DesSpecialSchemeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 版本号 + */ + private String versionNumber; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件访问路径 + */ + private Long fileUrl; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 文件 + */ + private SysOssVo file; + + /** + * 审核状态 + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/technicalstandard/DesTechnicalStandardVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/technicalstandard/DesTechnicalStandardVo.java new file mode 100644 index 0000000..0158127 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/technicalstandard/DesTechnicalStandardVo.java @@ -0,0 +1,90 @@ +package org.dromara.design.domain.vo.technicalstandard; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.design.domain.DesTechnicalStandard; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 技术标准管理视图对象 des_technical_standard + * + * @author lilemy + * @date 2025-07-02 + */ +@Data +@AutoMapper(target = DesTechnicalStandard.class) +public class DesTechnicalStandardVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件访问路径 + */ + private String fileUrl; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + + /** + * 审核状态 + */ + private String status; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesChangeReasonTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesChangeReasonTypeEnum.java new file mode 100644 index 0000000..284843a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesChangeReasonTypeEnum.java @@ -0,0 +1,42 @@ +package org.dromara.design.enums; + +import lombok.Getter; + +import java.util.Objects; + +/** + * @author lilemy + * @date 2025/7/3 19:46 + */ +@Getter +public enum DesChangeReasonTypeEnum { + + LEAK("设计漏项", "1"), + IMPROVE("设计改进", "2"), + ERROR("设计差错", "3"), + INTERFACE("接口差错", "4"), + OWNER("业主要求", "5"), + CONTRACTOR("施工承包商要求", "6"), + CONFLICT("外部资料与最终情况不符", "7"), + OTHER("材料代用或其他", "8"); + + private final String text; + + private final String value; + + + DesChangeReasonTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + + // 根据 value 获取对应的 text + public static String getTextByValue(String value) { + for (DesChangeReasonTypeEnum type : values()) { + if (Objects.equals(type.getValue(), value)) { + return type.getText(); + } + } + return null; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesDrawingFileTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesDrawingFileTypeEnum.java new file mode 100644 index 0000000..66a9c3a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesDrawingFileTypeEnum.java @@ -0,0 +1,39 @@ +package org.dromara.design.enums; + +import lombok.Getter; + +import java.util.Objects; + +/** + * @author lilemy + * @date 2025/7/2 20:13 + */ +@Getter +public enum DesDrawingFileTypeEnum { + + PROCESS_DRAWING("过程图纸", "1", "changedrawing"), + BLUEPRINT("蓝图", "2", "blueprintdrawing"), + CHANGE_DRAWING("变更图纸", "3", "processdrawing"); + + private final String text; + + private final String value; + + private final String code; + + DesDrawingFileTypeEnum(String text, String value, String code) { + this.text = text; + this.value = value; + this.code = code; + } + + // 根据 value 获取对应的 text + public static String getTextByValue(String value) { + for (DesDrawingFileTypeEnum type : values()) { + if (Objects.equals(type.getValue(), value)) { + return type.getText(); + } + } + return null; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesDrawingNewestEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesDrawingNewestEnum.java new file mode 100644 index 0000000..d0fbd92 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/enums/DesDrawingNewestEnum.java @@ -0,0 +1,23 @@ +package org.dromara.design.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/7/2 20:07 + */ +@Getter +public enum DesDrawingNewestEnum { + + YES("1", "是"), + NO("0", "否"); + + private final String code; + + private final String message; + + DesDrawingNewestEnum(String code, String message) { + this.code = code; + this.message = message; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesDesignChangeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesDesignChangeMapper.java new file mode 100644 index 0000000..edbaf4c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesDesignChangeMapper.java @@ -0,0 +1,15 @@ +package org.dromara.design.mapper; + +import org.dromara.design.domain.DesDesignChange; +import org.dromara.design.domain.vo.designchange.DesDesignChangeVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设计变更管理Mapper接口 + * + * @author lilemy + * @date 2025-07-03 + */ +public interface DesDesignChangeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesDrawingMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesDrawingMapper.java new file mode 100644 index 0000000..21ab40c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesDrawingMapper.java @@ -0,0 +1,15 @@ +package org.dromara.design.mapper; + +import org.dromara.design.domain.DesDrawing; +import org.dromara.design.domain.vo.drawing.DesDrawingVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 图纸管理Mapper接口 + * + * @author lilemy + * @date 2025-07-02 + */ +public interface DesDrawingMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesSpecialSchemeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesSpecialSchemeMapper.java new file mode 100644 index 0000000..28dd6a7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesSpecialSchemeMapper.java @@ -0,0 +1,15 @@ +package org.dromara.design.mapper; + +import org.dromara.design.domain.DesSpecialScheme; +import org.dromara.design.domain.vo.specialscheme.DesSpecialSchemeVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 专项方案管理Mapper接口 + * + * @author lilemy + * @date 2025-07-03 + */ +public interface DesSpecialSchemeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesTechnicalStandardMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesTechnicalStandardMapper.java new file mode 100644 index 0000000..7694a5d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/mapper/DesTechnicalStandardMapper.java @@ -0,0 +1,15 @@ +package org.dromara.design.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.design.domain.DesTechnicalStandard; +import org.dromara.design.domain.vo.technicalstandard.DesTechnicalStandardVo; + +/** + * 技术标准管理Mapper接口 + * + * @author lilemy + * @date 2025-07-02 + */ +public interface DesTechnicalStandardMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesDesignChangeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesDesignChangeService.java new file mode 100644 index 0000000..c40c6f8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesDesignChangeService.java @@ -0,0 +1,105 @@ +package org.dromara.design.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.design.domain.DesDesignChange; +import org.dromara.design.domain.dto.designchange.DesDesignChangeCreateReq; +import org.dromara.design.domain.dto.designchange.DesDesignChangeQueryReq; +import org.dromara.design.domain.dto.designchange.DesDesignChangeUpdateReq; +import org.dromara.design.domain.vo.designchange.DesDesignChangeVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设计变更管理Service接口 + * + * @author lilemy + * @date 2025-07-03 + */ +public interface IDesDesignChangeService extends IService { + + /** + * 查询设计变更管理 + * + * @param id 主键 + * @return 设计变更管理 + */ + DesDesignChangeVo queryById(Long id); + + /** + * 分页查询设计变更管理列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设计变更管理分页列表 + */ + TableDataInfo queryPageList(DesDesignChangeQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设计变更管理列表 + * + * @param req 查询条件 + * @return 设计变更管理列表 + */ + List queryList(DesDesignChangeQueryReq req); + + /** + * 根据主键id导出设计变更单 + * + * @param id 设计变更主键id + */ + void exportWordById(Long id, HttpServletResponse response); + + /** + * 新增设计变更管理 + * + * @param req 设计变更管理 + * @return 新增设计变更管理主键id + */ + DesDesignChangeVo insertByBo(DesDesignChangeCreateReq req); + + /** + * 修改设计变更管理 + * + * @param req 设计变更管理 + * @return 是否修改成功 + */ + DesDesignChangeVo updateByBo(DesDesignChangeUpdateReq req); + + /** + * 校验并批量删除设计变更管理信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteByIds(Collection ids); + + /** + * 构建设计变更管理封装对象 + * + * @param designChange 设计变更管理 + * @return 设计变更管理封装对象 + */ + DesDesignChangeVo getVo(DesDesignChange designChange); + + /** + * 构建查询条件 + * + * @param req 查询条件 + * @return 查询条件 + */ + LambdaQueryWrapper buildQueryWrapper(DesDesignChangeQueryReq req); + + /** + * 获取设计变更管理对象视图 + * + * @param designChangePage 设计变更管理对象 + * @return 设计变更管理对象视图 + */ + Page getVoPage(Page designChangePage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesDrawingService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesDrawingService.java new file mode 100644 index 0000000..7db065b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesDrawingService.java @@ -0,0 +1,106 @@ +package org.dromara.design.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.design.domain.DesDrawing; +import org.dromara.design.domain.dto.drawing.DesDrawingCreateReq; +import org.dromara.design.domain.dto.drawing.DesDrawingQueryReq; +import org.dromara.design.domain.dto.drawing.DesDrawingUpdateReq; +import org.dromara.design.domain.vo.drawing.DesDrawingVo; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * 图纸管理Service接口 + * + * @author lilemy + * @date 2025-07-02 + */ +public interface IDesDrawingService extends IService { + + /** + * 查询图纸管理 + * + * @param id 主键 + * @return 图纸管理 + */ + DesDrawingVo queryById(Long id); + + /** + * 分页查询图纸管理列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 图纸管理分页列表 + */ + TableDataInfo queryPageList(DesDrawingQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的图纸管理列表 + * + * @param req 查询条件 + * @return 图纸管理列表 + */ + List queryList(DesDrawingQueryReq req); + + /** + * 新增图纸管理 + * + * @param req 图纸管理 + * @return 新增图纸管理主键id + */ + DesDrawingVo insertByBo(DesDrawingCreateReq req); + + /** + * 修改图纸管理 + * + * @param req 图纸管理 + * @return 图纸管理 + */ + DesDrawingVo updateByBo(DesDrawingUpdateReq req); + + /** + * 校验并批量删除图纸管理信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteByIds(Collection ids); + + /** + * 构建图纸管理封装对象 + * + * @param drawing 图纸管理 + * @return 图纸管理封装对象 + */ + DesDrawingVo getVo(DesDrawing drawing); + + /** + * 构建查询条件 + * + * @param req 查询条件 + * @return 查询条件 + */ + LambdaQueryWrapper buildQueryWrapper(DesDrawingQueryReq req); + + /** + * 获取图纸管理对象视图 + * + * @param drawingPage 图纸管理对象 + * @return 图纸管理对象视图 + */ + Page getVoPage(Page drawingPage); + + /** + * 异步添加二维码到PDF + * + * @param drawing 图纸管理对象 + * @return 是否添加成功 + */ + CompletableFuture addQRCodeToPDF(DesDrawing drawing); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesSpecialSchemeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesSpecialSchemeService.java new file mode 100644 index 0000000..8eeac85 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesSpecialSchemeService.java @@ -0,0 +1,97 @@ +package org.dromara.design.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.design.domain.DesSpecialScheme; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeCreateReq; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeQueryReq; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeUpdateReq; +import org.dromara.design.domain.vo.specialscheme.DesSpecialSchemeVo; + +import java.util.Collection; +import java.util.List; + +/** + * 专项方案管理Service接口 + * + * @author lilemy + * @date 2025-07-03 + */ +public interface IDesSpecialSchemeService extends IService { + + /** + * 查询图纸管理 + * + * @param id 主键 + * @return 图纸管理 + */ + DesSpecialSchemeVo queryById(Long id); + + /** + * 分页查询图纸管理列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 图纸管理分页列表 + */ + TableDataInfo queryPageList(DesSpecialSchemeQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的图纸管理列表 + * + * @param req 查询条件 + * @return 图纸管理列表 + */ + List queryList(DesSpecialSchemeQueryReq req); + + /** + * 新增图纸管理 + * + * @param req 图纸管理 + * @return 新增图纸管理 + */ + DesSpecialSchemeVo insertByBo(DesSpecialSchemeCreateReq req); + + /** + * 修改图纸管理 + * + * @param req 图纸管理 + * @return 图纸管理 + */ + DesSpecialSchemeVo updateByBo(DesSpecialSchemeUpdateReq req); + + /** + * 校验并批量删除图纸管理信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteByIds(Collection ids); + + /** + * 构建图纸管理封装对象 + * + * @param specialScheme 图纸管理 + * @return 图纸管理封装对象 + */ + DesSpecialSchemeVo getVo(DesSpecialScheme specialScheme); + + /** + * 构建查询条件 + * + * @param req 查询条件 + * @return 查询条件 + */ + LambdaQueryWrapper buildQueryWrapper(DesSpecialSchemeQueryReq req); + + /** + * 获取图纸管理对象视图 + * + * @param specialSchemePage 图纸管理对象 + * @return 图纸管理对象视图 + */ + Page getVoPage(Page specialSchemePage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesTechnicalStandardService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesTechnicalStandardService.java new file mode 100644 index 0000000..30b9107 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesTechnicalStandardService.java @@ -0,0 +1,152 @@ +package org.dromara.design.service; + +import cn.hutool.core.lang.tree.Tree; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.design.domain.DesTechnicalStandard; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileCreateReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileQueryReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileUpdateReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardQueryReq; +import org.dromara.design.domain.vo.technicalstandard.DesTechnicalStandardVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; + +/** + * 技术标准管理Service接口 + * + * @author lilemy + * @date 2025-07-02 + */ +public interface IDesTechnicalStandardService extends IService { + + /** + * 查询技术标准管理 + * + * @param id 主键 + * @return 技术标准管理 + */ + DesTechnicalStandardVo queryById(Long id); + + /** + * 查询技术标准管理文件夹树列表 + * + * @param req 查询参数 + * @return 技术标准管理文件夹树列表 + */ + List> queryFolderTreeList(DesTechnicalStandardQueryReq req); + + /** + * 分页查询文件夹下的技术标准管理文件列表 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 技术标准管理文件列表 + */ + TableDataInfo queryFilePageByFolderId(DesTechnicalStandardFileQueryReq req, PageQuery pageQuery); + + /** + * 查询文件夹下的技术标准管理文件列表 + * + * @param folderId 文件夹id + * @return 技术标准管理文件列表 + */ + List queryFileListByFolderId(Long folderId); + + /** + * 查询回收站中的文件 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 回收站中的文件 + */ + TableDataInfo queryRecycleBinPageList(DesTechnicalStandardQueryReq req, PageQuery pageQuery); + + /** + * 新增技术标准管理文件 + * + * @param file 文件 + * @param req 技术标准管理 + * @return 是否新增成功 + */ + DesTechnicalStandardVo insertFile(MultipartFile file, DesTechnicalStandardFileCreateReq req); + + /** + * 新增技术标准管理文件夹 + * + * @param projectId 项目id + * @return 是否新增成功 + */ + Boolean insertFolderByTemplate(Long projectId); + + /** + * 修改技术标准管理文件 + * + * @param req 技术标准管理 + * @return 是否修改成功 + */ + DesTechnicalStandardVo updateFile(DesTechnicalStandardFileUpdateReq req); + + /** + * 删除技术标准管理文件信息 + * + * @param id 待删除文件的主键 + * @return 是否删除成功 + */ + Boolean deleteFileById(Long id); + + /** + * 批量删除技术标准管理回收站文件信息 + * + * @param ids 待删除文件主键集合 + * @return 是否删除成功 + */ + Boolean deleteRecycleBinFileBatchByIds(Collection ids); + + /** + * 批量恢复质量会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean recoveryBatchById(Collection ids); + + /** + * 构建前端所需要下拉树结构 + * + * @param documentList 文档列表 + * @return 下拉树结构列表 + */ + List> buildTreeSelect(List documentList); + + /** + * 构建文档封装对象 + * + * @param document 文档 + * @return 文档封装对象 + */ + DesTechnicalStandardVo getVo(DesTechnicalStandard document); + + /** + * 获取文档对象视图 + * + * @param documentPage 文档对象 + * @return 文档对象视图 + */ + Page getVoPage(Page documentPage); + + /** + * 畅写在线文件修改 + * + * @param id 文档id + * @param request 请求 + * @param response 响应 + */ + void singleFileUploads(Long id, HttpServletRequest request, HttpServletResponse response); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesDesignChangeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesDesignChangeServiceImpl.java new file mode 100644 index 0000000..fd1c9b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesDesignChangeServiceImpl.java @@ -0,0 +1,592 @@ +package org.dromara.design.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.xwpf.usermodel.*; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.exception.OssException; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.utils.DocumentUtil; +import org.dromara.design.constant.DesDesignConstant; +import org.dromara.design.domain.DesDesignChange; +import org.dromara.design.domain.dto.designchange.DesDesignChangeCreateReq; +import org.dromara.design.domain.dto.designchange.DesDesignChangeQueryReq; +import org.dromara.design.domain.dto.designchange.DesDesignChangeUpdateReq; +import org.dromara.design.domain.vo.designchange.DesDesignChangeVo; +import org.dromara.design.mapper.DesDesignChangeMapper; +import org.dromara.design.service.IDesDesignChangeService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.event.EventListener; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipOutputStream; + +/** + * 设计变更管理Service业务层处理 + * + * @author lilemy + * @date 2025-07-03 + */ +@Slf4j +@Service +public class DesDesignChangeServiceImpl extends ServiceImpl + implements IDesDesignChangeService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + /** + * 查询设计变更管理 + * + * @param id 主键 + * @return 设计变更管理 + */ + @Override + public DesDesignChangeVo queryById(Long id) { + DesDesignChange designChange = this.getById(id); + if (designChange == null) { + throw new ServiceException("设计变更不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(designChange); + } + + /** + * 分页查询设计变更管理列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设计变更管理分页列表 + */ + @Override + public TableDataInfo queryPageList(DesDesignChangeQueryReq req, PageQuery pageQuery) { + Page changePage = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(changePage)); + } + + /** + * 查询符合条件的设计变更管理列表 + * + * @param req 查询条件 + * @return 设计变更管理列表 + */ + @Override + public List queryList(DesDesignChangeQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 根据主键id导出设计变更单 + * + * @param id 设计变更主键id + */ + @Override + public void exportWordById(Long id, HttpServletResponse response) { + DesDesignChange designChange = this.getById(id); + if (designChange == null) { + throw new ServiceException("设计变更单不存在", HttpStatus.NOT_FOUND); + } + if (!designChange.getStatus().equals(BusinessStatusEnum.FINISH.getStatus())) { + throw new ServiceException("当前设计变更单审核未完成,无法下载", HttpStatus.CONFLICT); + } + Map replacementMap = getReplacementMap(designChange); + Path targetDir = Paths.get(DesDesignConstant.getDesignChangeFileUrl(designChange)); + // 如果存在目录则直接返回,不存在则生成文件并返回 + if (!Files.exists(targetDir)) { + // 清理旧文件 + String baseUrl = DesDesignConstant.DESIGN_CHANGE_FILE_URL + designChange.getId(); + try { + Path dirPath = Paths.get(baseUrl); + if (Files.exists(dirPath)) { + FileUtils.deleteDirectory(dirPath); + } + } catch (IOException e) { + log.error("文件目录:{},清理失败", baseUrl, e); + } + // 生成文件 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(DesDesignConstant.DESIGN_CHANGE_TEMPLATE_PATH)) { + if (is == null) { + throw new ServiceException("模板文件不存在"); + } + try (XWPFDocument document = new XWPFDocument(is)) { + // 替换段落中的文本 + for (XWPFParagraph paragraph : document.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, designChange); + } + // 替换表格中的文本(如果模板中有表格) + for (XWPFTable table : document.getTables()) { + for (XWPFTableRow row : table.getRows()) { + for (XWPFTableCell cell : row.getTableCells()) { + for (XWPFParagraph paragraph : cell.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, designChange); + } + } + } + } + // 创建目标目录 + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); + } + // 组合目标文件名 + String fileName = DesDesignConstant.getDesignChangeFileName(designChange); + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) { + document.write(fos); + } + } + } catch (IOException | InvalidFormatException e) { + throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + } + } + // 设置响应头,返回ZIP文件 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + DocumentUtil.zipDirectory(targetDir, targetDir, zos); + zos.flush(); + } catch (Exception e) { + throw new OssException("生成ZIP文件失败,错误信息: " + e.getMessage()); + } + } + + /** + * 新增设计变更管理 + * + * @param req 设计变更管理 + * @return 新增设计变更管理主键id + */ + @Override + public DesDesignChangeVo insertByBo(DesDesignChangeCreateReq req) { + DesDesignChange entity = new DesDesignChange(); + BeanUtils.copyProperties(req, entity); + validEntityBeforeSave(entity, true); + boolean save = this.save(entity); + if (!save) { + throw new ServiceException("新增设计变更单失败", HttpStatus.ERROR); + } + return this.getVo(this.getById(entity.getId())); + } + + /** + * 修改设计变更管理 + * + * @param req 设计变更管理 + * @return 是否修改成功 + */ + @Override + public DesDesignChangeVo updateByBo(DesDesignChangeUpdateReq req) { + DesDesignChange oldDesignChange = this.getById(req.getId()); + if (oldDesignChange == null) { + throw new ServiceException("设计变更单不存在", HttpStatus.NOT_FOUND); + } + DesDesignChange entity = new DesDesignChange(); + BeanUtils.copyProperties(req, entity); + validEntityBeforeSave(entity, false); + boolean result = this.updateById(entity); + if (!result) { + throw new ServiceException("修改设计变更单失败", HttpStatus.ERROR); + } + return this.getVo(this.getById(entity.getId())); + } + + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DesDesignChange entity, Boolean create) { + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设计变更管理信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteByIds(Collection ids) { + List designChangeList = this.listByIds(ids); + if (CollUtil.isEmpty(designChangeList)) { + return true; + } + // 关联删除附件 + List fileIdList = designChangeList.stream() + .map(DesDesignChange::getFileId) + .filter(Objects::nonNull) + .map(Long::parseLong) + .toList(); + List picList = designChangeList.stream() + .map(DesDesignChange::getAttachmentPic) + .filter(Objects::nonNull) + .flatMap(s -> Arrays.stream(s.split(","))) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .map(Long::parseLong) + .toList(); + List costEstimationFileIdList = designChangeList.stream() + .map(DesDesignChange::getCostEstimationFile) + .filter(Objects::nonNull) + .flatMap(s -> Arrays.stream(s.split(","))) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .map(Long::parseLong) + .toList(); + List ossIdList = Stream.of(fileIdList, picList, costEstimationFileIdList) + .flatMap(Collection::stream) + .distinct() + .toList(); + if (CollUtil.isNotEmpty(ossIdList)) { + ossService.deleteWithValidByIds(ossIdList, true); + } + return removeBatchByIds(ids); + } + + /** + * 构建设计变更管理封装对象 + * + * @param designChange 设计变更管理 + * @return 设计变更管理封装对象 + */ + @Override + public DesDesignChangeVo getVo(DesDesignChange designChange) { + DesDesignChangeVo vo = new DesDesignChangeVo(); + if (designChange == null) { + return vo; + } + BeanUtils.copyProperties(designChange, vo); + List allFileIdList = new ArrayList<>(); + // 1. 添加单个 fileId(前提是非空) + String fileId = designChange.getFileId(); + if (StringUtils.isNotBlank(fileId)) { + allFileIdList.add(Long.valueOf(fileId)); + } + // 2. 添加 attachmentPic 多个 ID + String attachmentPic = designChange.getAttachmentPic(); + if (StringUtils.isNotBlank(attachmentPic)) { + String[] attachmentPicStr = attachmentPic.split(","); + for (String idStr : attachmentPicStr) { + if (StringUtils.isNotBlank(idStr)) { + allFileIdList.add(Long.valueOf(idStr.trim())); + } + } + } + // 3. 添加 costEstimationFile 多个 ID + String costEstimationFile = designChange.getCostEstimationFile(); + if (StringUtils.isNotBlank(costEstimationFile)) { + String[] costEstimationFileStr = costEstimationFile.split(","); + for (String idStr : costEstimationFileStr) { + if (StringUtils.isNotBlank(idStr)) { + allFileIdList.add(Long.valueOf(idStr.trim())); + } + } + } + if (CollUtil.isNotEmpty(allFileIdList)) { + // 获取文件对象 + List ossVoList = ossService.listByIds(allFileIdList); + Map ossMap = ossVoList.stream() + .collect(Collectors.toMap(SysOssVo::getOssId, Function.identity(), (a, b) -> a)); + // 1. 处理 file(单个) + if (StringUtils.isNotBlank(fileId)) { + Long file = Long.valueOf(fileId); + SysOssVo fileVo = ossMap.get(file); + vo.setFile(fileVo); + } + // 2. 处理 attachmentPicList(多个) + if (StringUtils.isNotBlank(attachmentPic)) { + List attachmentList = Arrays.stream(attachmentPic.split(",")) + .map(String::trim) + .filter(StringUtils::isNotBlank) + .map(Long::valueOf) + .map(ossMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + vo.setAttachmentPicList(attachmentList); + } + // 3. 处理 costEstimationFileList(多个) + if (StringUtils.isNotBlank(costEstimationFile)) { + List costList = Arrays.stream(costEstimationFile.split(",")) + .map(String::trim) + .filter(StringUtils::isNotBlank) + .map(Long::valueOf) + .map(ossMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + vo.setCostEstimationFileList(costList); + } + } + return vo; + } + + /** + * 构建查询条件 + * + * @param req 查询条件 + * @return 查询条件 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(DesDesignChangeQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String formNo = req.getFormNo(); + String projectName = req.getProjectName(); + String submitUnit = req.getSubmitUnit(); + String specialty = req.getSpecialty(); + Date submitDate = req.getSubmitDate(); + String volumeName = req.getVolumeName(); + String volumeNo = req.getVolumeNo(); + String status = req.getStatus(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), DesDesignChange::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(formNo), DesDesignChange::getFormNo, formNo); + lqw.eq(ObjectUtils.isNotEmpty(submitDate), DesDesignChange::getSubmitDate, submitDate); + lqw.eq(StringUtils.isNotEmpty(status), DesDesignChange::getStatus, status); + lqw.like(StringUtils.isNotEmpty(projectName), DesDesignChange::getProjectName, projectName); + lqw.like(StringUtils.isNotEmpty(submitUnit), DesDesignChange::getSubmitUnit, submitUnit); + lqw.like(StringUtils.isNotEmpty(specialty), DesDesignChange::getSpecialty, specialty); + lqw.like(StringUtils.isNotEmpty(volumeName), DesDesignChange::getVolumeName, volumeName); + lqw.like(StringUtils.isNotEmpty(volumeNo), DesDesignChange::getVolumeNo, volumeNo); + return lqw; + } + + /** + * 获取设计变更管理对象视图 + * + * @param designChangePage 设计变更管理对象 + * @return 设计变更管理对象视图 + */ + @Override + public Page getVoPage(Page designChangePage) { + List designChangeList = designChangePage.getRecords(); + Page designChangeVoPage = new Page<>( + designChangePage.getCurrent(), + designChangePage.getSize(), + designChangePage.getTotal()); + if (CollUtil.isEmpty(designChangeList)) { + return designChangeVoPage; + } + Set ossIdList = designChangeList.stream().map(DesDesignChange::getFileId).filter(Objects::nonNull).map(Long::parseLong).collect(Collectors.toSet()); + List ossVoList = ossService.listByIds(ossIdList); + Map ossVoMap = ossVoList.stream().collect(Collectors.toMap(SysOssVo::getOssId, Function.identity(), (a, b) -> a)); + List designChangeVoList = designChangeList.stream().map(designChange -> { + DesDesignChangeVo designChangeVo = new DesDesignChangeVo(); + BeanUtils.copyProperties(designChange, designChangeVo); + String fileId = designChange.getFileId(); + if (StringUtils.isNotBlank(fileId)) { + SysOssVo file = ossVoMap.get(Long.valueOf(fileId)); + designChangeVo.setFile(file); + } + return designChangeVo; + }).toList(); + designChangeVoPage.setRecords(designChangeVoList); + return designChangeVoPage; + } + + /** + * 根据实体获取Word的文本Map + * + * @param designChange 质量-检查工单对象 + * @return Map + */ + private Map getReplacementMap(DesDesignChange designChange) { + Map replacementMap = new HashMap<>(); + replacementMap.put("${formNo}", designChange.getFormNo()); + replacementMap.put("${projectName}", designChange.getProjectName()); + replacementMap.put("${submitUnit}", designChange.getSubmitUnit()); + replacementMap.put("${specialty}", designChange.getSpecialty()); + Date submitDate = designChange.getSubmitDate(); + String date = DateUtil.format(submitDate, "yyyy年MM月dd日"); + replacementMap.put("${submitDate}", date); + replacementMap.put("${attachmentPic}", designChange.getAttachmentPic()); + replacementMap.put("${volumeName}", designChange.getVolumeName()); + replacementMap.put("${volumeNo}", designChange.getVolumeNo()); + String[] reasonList = designChange.getChangeReason().split(","); + Set reasonSet = new HashSet<>(Arrays.asList(reasonList)); + for (int i = 1; i <= 8; i++) { + if (reasonSet.contains(String.valueOf(i))) { + replacementMap.put("${changeReason" + i + "}", "√"); + } else { + replacementMap.put("${changeReason" + i + "}", " "); + } + } + replacementMap.put("${changeContent}", designChange.getChangeContent()); + replacementMap.put("${costEstimation}", designChange.getCostEstimation()); + replacementMap.put("${costEstimationFile}", designChange.getCostEstimationFile()); + return replacementMap; + } + + /** + * 替换段落中所有文本运行的占位符内容,对于 checkFile 和 rectificationFile + * 插入图片或超链接(附件)展示。 + * + * @param paragraph 当前段落 + * @param replacements 占位符与替换内容的映射 + * @param document 当前文档,用于插入图片或创建超链接 + */ + private void replaceInParagraph(XWPFParagraph paragraph, + Map replacements, + XWPFDocument document, + DesDesignChange designChange) + throws InvalidFormatException, IOException { + // 先拷贝 paragraph 里所有的 run + List runs = new ArrayList<>(paragraph.getRuns()); + // 在拷贝上遍历,修改原 paragraph(增删 run)都不会抛 CME + for (XWPFRun run : runs) { + String text = run.getText(0); + if (text != null) { + // 针对每个占位符进行检查 + for (Map.Entry entry : replacements.entrySet()) { + String placeholder = entry.getKey(); + String value = entry.getValue(); + if (text.contains(placeholder)) { + // 针对 file 进行特殊处理 + if (placeholder.equals("${costEstimationFile}") || placeholder.equals("${attachmentPic}")) { + // 判断该 run 中的文本是否仅包含该占位符(建议模板中独占一行) + if (text.trim().equals(placeholder)) { + // 清空原有文本 + run.setText("", 0); + // 根据附件的后缀决定以图片或超链接展示 + if (StringUtils.isBlank(value)) { + continue; + } + // 获取附件的ossId + List ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = DesDesignConstant.getDesignChangeFileUrl(designChange) + "/file"; + for (SysOssVo ossVo : ossVoList) { + String lowerVal = ossVo.getUrl().toLowerCase(); + OssClient storage = OssFactory.instance(ossVo.getService()); + String fileDownload = storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + if (lowerVal.endsWith(".png") || lowerVal.endsWith(".jpg") || lowerVal.endsWith(".jpeg") || lowerVal.endsWith(".gif")) { + try { + DocumentUtil.insertImageDynamic(run, fileDownload, document, 50); + } catch (Exception e) { + throw new ServiceException("插入图片失败"); + } + } else { + // —— 非图片:插入超链接 —— + XWPFHyperlinkRun link = paragraph.createHyperlinkRun(ossVo.getUrl()); + link.setText(ossVo.getOriginalName()); + link.setColor("0000FF"); + link.setUnderline(UnderlinePatterns.SINGLE); + } + } + } else { + // 如果占位符与其它文本混合,可进行文本替换,提示附件展示请单独使用占位符 + text = text.replace(placeholder, "[附件]"); + run.setText(text, 0); + } + } else { + // 普通文本占位符直接替换 + if (StringUtils.isBlank(value)) { + // 如果填入值为空,清空原有文本 + run.setText("", 0); + continue; + } + text = text.replace(placeholder, value); + run.setText(text, 0); + } + } + } + } + } + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.endsWith('designchanged')") + public void processHandler(ProcessEvent processEvent) { + log.info("设计变更文件审核任务执行了{}", processEvent.toString()); + DesDesignChange designChange = this.getById(Convert.toLong(processEvent.getBusinessId())); + designChange.setStatus(processEvent.getStatus()); + if (processEvent.getSubmit()) { + designChange.setStatus(BusinessStatusEnum.WAITING.getStatus()); + } + this.updateById(designChange); + } + + /** + * 执行任务创建监听 + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.endsWith('designchanged')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("设计变更文件审核任务创建了{}", processTaskEvent.toString()); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @Transactional + @EventListener(condition = "#processDeleteEvent.flowCode.endsWith('designchanged')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,设计变更文件审核任务执行了{}", processDeleteEvent.toString()); + DesDesignChange designChange = this.getById(Convert.toLong(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(designChange)) { + return; + } + this.deleteByIds(Collections.singleton(designChange.getId())); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesDrawingServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesDrawingServiceImpl.java new file mode 100644 index 0000000..cbae353 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesDrawingServiceImpl.java @@ -0,0 +1,401 @@ +package org.dromara.design.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.itextpdf.text.DocumentException; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.utils.PdfBoxQrCodeGenerator; +import org.dromara.design.domain.DesDrawing; +import org.dromara.design.domain.dto.drawing.DesDrawingCreateReq; +import org.dromara.design.domain.dto.drawing.DesDrawingQueryReq; +import org.dromara.design.domain.dto.drawing.DesDrawingUpdateReq; +import org.dromara.design.domain.vo.drawing.DesDrawingVo; +import org.dromara.design.enums.DesDrawingFileTypeEnum; +import org.dromara.design.enums.DesDrawingNewestEnum; +import org.dromara.design.mapper.DesDrawingMapper; +import org.dromara.design.service.IDesDrawingService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.FileNameMap; +import java.net.URLConnection; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +/** + * 图纸管理Service业务层处理 + * + * @author lilemy + * @date 2025-07-02 + */ +@Slf4j +@Service +public class DesDrawingServiceImpl extends ServiceImpl + implements IDesDrawingService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + @Resource + private WorkflowService workflowService; + + @Lazy + @Resource + private IDesDrawingService self; + + /** + * 查询图纸管理 + * + * @param id 主键 + * @return 图纸管理 + */ + @Override + public DesDrawingVo queryById(Long id) { + DesDrawing drawing = this.getById(id); + if (drawing == null) { + throw new ServiceException("图纸不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(drawing); + } + + /** + * 分页查询图纸管理列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 图纸管理分页列表 + */ + @Override + public TableDataInfo queryPageList(DesDrawingQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的图纸管理列表 + * + * @param req 查询条件 + * @return 图纸管理列表 + */ + @Override + public List queryList(DesDrawingQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增图纸管理 + * + * @param req 图纸管理 + * @return 新增图纸管理主键id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public DesDrawingVo insertByBo(DesDrawingCreateReq req) { + Long fileUrl = req.getFileUrl(); + if (fileUrl == null) { + throw new ServiceException("图纸文件不能为空", HttpStatus.BAD_REQUEST); + } + SysOssVo ossVo = ossService.getById(fileUrl); + // 数据校验 + if (ObjectUtils.isEmpty(ossVo)) { + throw new ServiceException("图纸文件不能为空", HttpStatus.BAD_REQUEST); + } + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); + } + String fileType = req.getFileType(); + String enumText = DesDrawingFileTypeEnum.getTextByValue(fileType); + if (StringUtils.isBlank(enumText)) { + throw new ServiceException("图纸文件类型错误", HttpStatus.BAD_REQUEST); + } + // 文件信息赋值 + DesDrawing desDrawing = new DesDrawing(); + desDrawing.setProjectId(projectId); + desDrawing.setOriginalName(ossVo.getOriginalName()); + String name = req.getFileName(); + if (StringUtils.isBlank(name)) { + name = FileUtil.getPrefix(ossVo.getOriginalName()); + } + desDrawing.setFileName(name); + desDrawing.setFileUrl(fileUrl); + desDrawing.setOriginalFileId(fileUrl); + desDrawing.setFileSuffix(ossVo.getFileSuffix()); + desDrawing.setVersionNumber(req.getVersionNumber()); + desDrawing.setFileType(fileType); + desDrawing.setNewest(DesDrawingNewestEnum.YES.getCode()); + // 修改数据库中最新版本文件状态 + DesDrawing oldNewestDrawing = this.lambdaQuery() + .eq(DesDrawing::getProjectId, projectId) + .eq(DesDrawing::getNewest, DesDrawingNewestEnum.YES.getCode()) + .eq(DesDrawing::getFileType, fileType) + .one(); + if (oldNewestDrawing != null) { + oldNewestDrawing.setNewest(DesDrawingNewestEnum.NO.getCode()); + boolean result = this.updateById(oldNewestDrawing); + if (!result) { + throw new ServiceException("数据库中图纸状态更新异常"); + } + } + boolean result = this.save(desDrawing); + if (!result) { + throw new ServiceException("保存新图纸失败"); + } + return this.getVo(this.getById(desDrawing.getId())); + } + + /** + * 修改图纸管理 + * + * @param req 图纸管理 + * @return 图纸管理 + */ + @Override + public DesDrawingVo updateByBo(DesDrawingUpdateReq req) { + Long id = req.getId(); + DesDrawing oldDrawing = this.getById(id); + if (oldDrawing == null) { + throw new ServiceException("图纸不存在", HttpStatus.NOT_FOUND); + } + DesDrawing desDrawing = new DesDrawing(); + BeanUtils.copyProperties(req, desDrawing); + if (req.getFileUrl() != null && !req.getFileUrl().equals(oldDrawing.getFileUrl())) { + Long fileUrl = req.getFileUrl(); + SysOssVo ossVo = ossService.getById(fileUrl); + // 数据校验 + if (ObjectUtils.isEmpty(ossVo)) { + throw new ServiceException("图纸文件不能为空", HttpStatus.BAD_REQUEST); + } + desDrawing.setFileUrl(fileUrl); + desDrawing.setOriginalFileId(fileUrl); + } + boolean result = this.updateById(desDrawing); + if (!result) { + throw new ServiceException("修改图纸失败", HttpStatus.ERROR); + } + return this.getVo(this.getById(id)); + } + + /** + * 校验并批量删除图纸管理信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteByIds(Collection ids) { + List drawingList = this.listByIds(ids); + if (CollUtil.isEmpty(drawingList)) { + throw new ServiceException("参数错误,请勿删除不存在的图纸", HttpStatus.BAD_REQUEST); + } + workflowService.deleteInstance((List) ids); + // 删除oss文件 + Set fileIdList = drawingList.stream().map(DesDrawing::getFileUrl).collect(Collectors.toSet()); + ossService.deleteWithValidByIds(fileIdList, false); + return removeBatchByIds(ids); + } + + /** + * 构建图纸管理封装对象 + * + * @param drawing 图纸管理 + * @return 图纸管理封装对象 + */ + @Override + public DesDrawingVo getVo(DesDrawing drawing) { + DesDrawingVo vo = new DesDrawingVo(); + if (drawing == null) { + return vo; + } + SysOssVo ossVo = ossService.getById(drawing.getFileUrl()); + BeanUtils.copyProperties(drawing, vo); + vo.setFile(ossVo); + return vo; + } + + /** + * 构建查询条件 + * + * @param req 查询条件 + * @return 查询条件 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(DesDrawingQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String fileName = req.getFileName(); + String fileType = req.getFileType(); + String fileStatus = req.getFileStatus(); + String originalName = req.getOriginalName(); + String newest = req.getNewest(); + lqw.like(StringUtils.isNotBlank(fileName), DesDrawing::getFileName, fileName); + lqw.like(StringUtils.isNotBlank(originalName), DesDrawing::getOriginalName, originalName); + lqw.eq(ObjectUtils.isNotEmpty(projectId), DesDrawing::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(fileType), DesDrawing::getFileType, fileType); + lqw.eq(StringUtils.isNotBlank(fileStatus), DesDrawing::getFileStatus, fileStatus); + lqw.eq(StringUtils.isNotBlank(newest), DesDrawing::getNewest, newest); + lqw.orderByDesc(DesDrawing::getNewest); + lqw.orderByDesc(DesDrawing::getCreateTime); + return lqw; + } + + /** + * 获取图纸管理对象视图 + * + * @param drawingPage 图纸管理对象 + * @return 图纸管理对象视图 + */ + @Override + public Page getVoPage(Page drawingPage) { + List drawingList = drawingPage.getRecords(); + Page drawingVoPage = new Page<>( + drawingPage.getCurrent(), + drawingPage.getSize(), + drawingPage.getTotal()); + if (CollUtil.isEmpty(drawingList)) { + return drawingVoPage; + } + List ossVoList = ossService.listByIds(drawingList.stream().map(DesDrawing::getFileUrl).toList()); + Map> ossMap = ossVoList.stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + List drawingVoList = drawingList.stream().map(entity -> { + DesDrawingVo drawingVo = new DesDrawingVo(); + BeanUtils.copyProperties(entity, drawingVo); + drawingVo.setFile(ossMap.get(entity.getFileUrl()).getFirst()); + return drawingVo; + }).toList(); + drawingVoPage.setRecords(drawingVoList); + return drawingVoPage; + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.endsWith('drawing')") + public void processHandler(ProcessEvent processEvent) { + log.info("图纸审核任务执行了{}", processEvent.toString()); + DesDrawing drawing = this.getById(Convert.toLong(processEvent.getBusinessId())); + drawing.setStatus(processEvent.getStatus()); + if (processEvent.getSubmit()) { + drawing.setStatus(BusinessStatusEnum.WAITING.getStatus()); + } + this.updateById(drawing); + // 如果审核已完成 + if (BusinessStatusEnum.FINISH.getStatus().equals(processEvent.getStatus())) { + log.info("图纸审核任务已完成: {}", processEvent); + self.addQRCodeToPDF(drawing) + .thenAccept(result -> log.info("图纸[{}-{}]添加二维码成功", drawing.getFileName(), drawing.getId())) + .exceptionally(ex -> { + log.error("图纸[{}-{}]添加二维码失败", drawing.getFileName(), drawing.getId(), ex); + return null; + }); + } + } + + /** + * 执行任务创建监听 + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.endsWith('drawing')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("图纸审核任务创建了{}", processTaskEvent.toString()); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @EventListener(condition = "#processDeleteEvent.flowCode.endsWith('drawing')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,图纸审核任务执行了{}", processDeleteEvent.toString()); + DesDrawing drawing = this.getById(Convert.toLong(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(drawing)) { + return; + } + Long fileUrl = drawing.getFileUrl(); + ossService.deleteWithValidByIds(fileUrl == null ? Collections.emptyList() : Collections.singletonList(fileUrl), false); + this.removeById(drawing.getId()); + } + + /** + * 异步添加二维码到PDF + * + * @param drawing 图纸管理对象 + * @return 是否添加成功 + */ + @Async + @Override + public CompletableFuture addQRCodeToPDF(DesDrawing drawing) { + Long fileUrl = drawing.getOriginalFileId(); + if (fileUrl == null) { + return CompletableFuture.completedFuture(false); + } + SysOssVo ossVo = ossService.getById(fileUrl); + // 整合二维码需要显示的数据 + String params = "ID:[" + drawing.getId() + "] finish"; + byte[] bytes = PdfBoxQrCodeGenerator.generateQRCodeBytes(params); + try { + ByteArrayOutputStream baos = PdfBoxQrCodeGenerator.addQRCodeToPDF(ossVo.getUrl(), bytes, 1, 1510, 900); + FileNameMap fileNameMap = URLConnection.getFileNameMap(); + String originalName = drawing.getOriginalName(); + String contentType = fileNameMap.getContentTypeFor(originalName); + SysOssVo upload = ossService.upload(new ByteArrayInputStream(baos.toByteArray()), originalName, contentType, baos.size()); + drawing.setFileUrl(upload.getOssId()); + } catch (IOException | DocumentException e) { + log.error("图纸管理 => 审核结束,向文件添加二维码失败", e); + return CompletableFuture.completedFuture(false); + } + this.updateById(drawing); + return CompletableFuture.completedFuture(true); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesSpecialSchemeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesSpecialSchemeServiceImpl.java new file mode 100644 index 0000000..6dcf4ef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesSpecialSchemeServiceImpl.java @@ -0,0 +1,303 @@ +package org.dromara.design.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.design.domain.DesSpecialScheme; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeCreateReq; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeQueryReq; +import org.dromara.design.domain.dto.specialscheme.DesSpecialSchemeUpdateReq; +import org.dromara.design.domain.vo.specialscheme.DesSpecialSchemeVo; +import org.dromara.design.mapper.DesSpecialSchemeMapper; +import org.dromara.design.service.IDesSpecialSchemeService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 专项方案管理Service业务层处理 + * + * @author lilemy + * @date 2025-07-03 + */ +@Slf4j +@Service +public class DesSpecialSchemeServiceImpl extends ServiceImpl + implements IDesSpecialSchemeService { + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + @Resource + private WorkflowService workflowService; + + /** + * 查询专项方案管理 + * + * @param id 主键 + * @return 专项方案管理 + */ + @Override + public DesSpecialSchemeVo queryById(Long id) { + DesSpecialScheme specialScheme = this.getById(id); + if (specialScheme == null) { + throw new ServiceException("专项方案不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(specialScheme); + } + + /** + * 分页查询专项方案管理列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 专项方案管理分页列表 + */ + @Override + public TableDataInfo queryPageList(DesSpecialSchemeQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的专项方案管理列表 + * + * @param req 查询条件 + * @return 专项方案管理列表 + */ + @Override + public List queryList(DesSpecialSchemeQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增专项方案管理 + * + * @param req 专项方案管理 + * @return 新增专项方案管理 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public DesSpecialSchemeVo insertByBo(DesSpecialSchemeCreateReq req) { + Long fileUrl = req.getFileUrl(); + SysOssVo ossVo = ossService.getById(fileUrl); + // 数据校验 + if (ObjectUtils.isEmpty(ossVo)) { + throw new ServiceException("专项方案文件不能为空", HttpStatus.BAD_REQUEST); + } + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); + } + // 文件信息赋值 + DesSpecialScheme desSpecialScheme = new DesSpecialScheme(); + desSpecialScheme.setProjectId(projectId); + desSpecialScheme.setOriginalName(ossVo.getOriginalName()); + String name = req.getFileName(); + if (StringUtils.isBlank(name)) { + name = FileUtil.getPrefix(ossVo.getOriginalName()); + } + desSpecialScheme.setFileName(name); + desSpecialScheme.setFileUrl(fileUrl); + desSpecialScheme.setFileSuffix(ossVo.getFileSuffix()); + desSpecialScheme.setVersionNumber(req.getVersionNumber()); + boolean result = this.save(desSpecialScheme); + if (!result) { + throw new ServiceException("保存新专项方案失败"); + } + return this.getVo(this.getById(desSpecialScheme.getId())); + } + + /** + * 修改专项方案管理 + * + * @param req 专项方案管理 + * @return 是否修改成功 + */ + @Override + public DesSpecialSchemeVo updateByBo(DesSpecialSchemeUpdateReq req) { + Long id = req.getId(); + DesSpecialScheme oldSpecialScheme = this.getById(id); + if (oldSpecialScheme == null) { + throw new ServiceException("专项方案不存在", HttpStatus.NOT_FOUND); + } + DesSpecialScheme desSpecialScheme = new DesSpecialScheme(); + BeanUtils.copyProperties(req, desSpecialScheme); + boolean result = this.updateById(desSpecialScheme); + if (!result) { + throw new ServiceException("修改专项方案失败", HttpStatus.ERROR); + } + return this.getVo(this.getById(id)); + } + + /** + * 校验并批量删除专项方案管理信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteByIds(Collection ids) { + List specialSchemeList = this.listByIds(ids); + if (CollUtil.isEmpty(specialSchemeList)) { + throw new ServiceException("参数错误,请勿删除不存在的专项方案", HttpStatus.BAD_REQUEST); + } + workflowService.deleteInstance((List) ids); + // 删除oss文件 + Set fileIdList = specialSchemeList.stream().map(DesSpecialScheme::getFileUrl).collect(Collectors.toSet()); + ossService.deleteWithValidByIds(fileIdList, false); + return removeBatchByIds(ids); + } + + /** + * 构建专项方案管理封装对象 + * + * @param specialScheme 专项方案管理 + * @return 专项方案管理封装对象 + */ + @Override + public DesSpecialSchemeVo getVo(DesSpecialScheme specialScheme) { + DesSpecialSchemeVo vo = new DesSpecialSchemeVo(); + if (specialScheme == null) { + return vo; + } + BeanUtils.copyProperties(specialScheme, vo); + SysOssVo ossVo = ossService.getById(specialScheme.getFileUrl()); + vo.setFile(ossVo); + return vo; + } + + /** + * 构建查询条件 + * + * @param req 查询条件 + * @return 查询条件 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(DesSpecialSchemeQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String fileName = req.getFileName(); + String fileStatus = req.getFileStatus(); + String originalName = req.getOriginalName(); + lqw.like(StringUtils.isNotBlank(fileName), DesSpecialScheme::getFileName, fileName); + lqw.like(StringUtils.isNotBlank(originalName), DesSpecialScheme::getOriginalName, originalName); + lqw.eq(ObjectUtils.isNotEmpty(projectId), DesSpecialScheme::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(fileStatus), DesSpecialScheme::getFileStatus, fileStatus); + lqw.orderByDesc(DesSpecialScheme::getCreateTime); + return lqw; + } + + /** + * 获取专项方案管理对象视图 + * + * @param specialSchemePage 专项方案管理对象 + * @return 专项方案管理对象视图 + */ + @Override + public Page getVoPage(Page specialSchemePage) { + List specialSchemeList = specialSchemePage.getRecords(); + Page specialSchemeVoPage = new Page<>( + specialSchemePage.getCurrent(), + specialSchemePage.getSize(), + specialSchemePage.getTotal()); + if (CollUtil.isEmpty(specialSchemeList)) { + return specialSchemeVoPage; + } + List ossVoList = ossService.listByIds(specialSchemeList.stream().map(DesSpecialScheme::getFileUrl).toList()); + Map> ossMap = ossVoList.stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + List specialSchemeVoList = specialSchemeList.stream().map(entity -> { + DesSpecialSchemeVo specialSchemeVo = new DesSpecialSchemeVo(); + BeanUtils.copyProperties(entity, specialSchemeVo); + specialSchemeVo.setFile(ossMap.get(entity.getFileUrl()).getFirst()); + return specialSchemeVo; + }).toList(); + specialSchemeVoPage.setRecords(specialSchemeVoList); + return specialSchemeVoPage; + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.endsWith('specialscheme')") + public void processHandler(ProcessEvent processEvent) { + log.info("专项方案审核任务执行了{}", processEvent.toString()); + DesSpecialScheme specialScheme = this.getById(Convert.toLong(processEvent.getBusinessId())); + specialScheme.setStatus(processEvent.getStatus()); + if (processEvent.getSubmit()) { + specialScheme.setStatus(BusinessStatusEnum.WAITING.getStatus()); + } + this.updateById(specialScheme); + } + + /** + * 执行任务创建监听 + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.endsWith('specialscheme')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("专项方案审核任务创建了{}", processTaskEvent.toString()); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @EventListener(condition = "#processDeleteEvent.flowCode.endsWith('specialscheme')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,专项方案审核任务执行了{}", processDeleteEvent.toString()); + DesSpecialScheme specialScheme = this.getById(Convert.toLong(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(specialScheme)) { + return; + } + this.removeById(specialScheme.getId()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesTechnicalStandardServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesTechnicalStandardServiceImpl.java new file mode 100644 index 0000000..c91d35a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesTechnicalStandardServiceImpl.java @@ -0,0 +1,579 @@ +package org.dromara.design.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.enums.DocumentStatusEnum; +import org.dromara.common.enums.DocumentTypeEnum; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.design.constant.DesTechnicalStandardConstant; +import org.dromara.design.domain.DesTechnicalStandard; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileCreateReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileQueryReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardFileUpdateReq; +import org.dromara.design.domain.dto.technicalstandard.DesTechnicalStandardQueryReq; +import org.dromara.design.domain.vo.technicalstandard.DesTechnicalStandardVo; +import org.dromara.design.mapper.DesTechnicalStandardMapper; +import org.dromara.design.service.IDesTechnicalStandardService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 技术标准管理Service业务层处理 + * + * @author lilemy + * @date 2025-07-02 + */ +@Slf4j +@Service +public class DesTechnicalStandardServiceImpl extends ServiceImpl + implements IDesTechnicalStandardService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + /** + * 查询质量知识库 + * + * @param id 主键 + * @return 质量知识库 + */ + @Override + public DesTechnicalStandardVo queryById(Long id) { + DesTechnicalStandard entity = this.getById(id); + if (entity == null) { + throw new ServiceException("技术标准管理文件或文件夹不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(entity); + } + + /** + * 查询技术标准管理文件夹树列表 + * + * @param req 查询参数 + * @return 技术标准管理文件夹树列表 + */ + @Override + public List> queryFolderTreeList(DesTechnicalStandardQueryReq req) { + Long projectId = req.getProjectId(); + List folderList = this.lambdaQuery() + .eq(DesTechnicalStandard::getProjectId, projectId) + .eq(DesTechnicalStandard::getFileType, DocumentTypeEnum.FOLDER.getValue()) + .eq(DesTechnicalStandard::getFileStatus, DocumentStatusEnum.NORMAL.getValue()) + .list(); + return this.buildTreeSelect(folderList); + } + + /** + * 查询文件夹下的技术标准管理文件列表 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 技术标准管理文件列表 + */ + @Override + public TableDataInfo queryFilePageByFolderId(DesTechnicalStandardFileQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long folderId = req.getFolderId(); + if (folderId != null) { + DesTechnicalStandard folder = this.getById(folderId); + if (folder == null) { + throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND); + } + if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) { + throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST); + } + lqw.eq(DesTechnicalStandard::getPid, folderId); + } + lqw.eq(ObjectUtils.isNotEmpty(req.getProjectId()), DesTechnicalStandard::getProjectId, req.getProjectId()); + lqw.ne(DesTechnicalStandard::getFileType, DocumentTypeEnum.FOLDER.getValue()); + lqw.eq(DesTechnicalStandard::getFileStatus, DocumentStatusEnum.NORMAL.getValue()); + lqw.like(StringUtils.isNotBlank(req.getFileName()), DesTechnicalStandard::getFileName, req.getFileName()); + Page documentPage = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(documentPage)); + } + + /** + * 查询文件夹下的技术标准管理文件列表 + * + * @param folderId 文件夹id + * @return 技术标准管理文件列表 + */ + @Override + public List queryFileListByFolderId(Long folderId) { + DesTechnicalStandard folder = this.getById(folderId); + if (folder == null) { + throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND); + } + if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) { + throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST); + } + List list = this.lambdaQuery() + .eq(DesTechnicalStandard::getPid, folderId) + .ne(DesTechnicalStandard::getFileType, DocumentTypeEnum.FOLDER.getValue()) + .eq(DesTechnicalStandard::getFileStatus, DocumentStatusEnum.NORMAL.getValue()) + .list(); + return list.stream().map(this::getVo).toList(); + } + + /** + * 查询回收站中的文件 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 回收站中的文件 + */ + @Override + public TableDataInfo queryRecycleBinPageList(DesTechnicalStandardQueryReq req, PageQuery pageQuery) { + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(DesTechnicalStandard::getProjectId, projectId); + lqw.eq(DesTechnicalStandard::getFileStatus, DocumentStatusEnum.DELETE.getValue()); + lqw.like(StringUtils.isNotBlank(req.getFileName()), DesTechnicalStandard::getFileName, req.getFileName()); + lqw.orderByDesc(DesTechnicalStandard::getDeletedAt); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 新增技术标准管理文件 + * + * @param file 文件 + * @param req 质量知识库 + * @return 是否新增成功 + */ + @Override + public DesTechnicalStandardVo insertFile(MultipartFile file, DesTechnicalStandardFileCreateReq req) { + // 数据校验 + if (ObjectUtils.isEmpty(file)) { + throw new ServiceException("技术标准管理文件不能为空", HttpStatus.BAD_REQUEST); + } + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); + } + // 拼接文件名 + String originalFilename = file.getOriginalFilename(); + String suffix = FileUtil.getSuffix(originalFilename); + if (StringUtils.isBlank(suffix)) { + throw new ServiceException("技术标准管理文件格式错误", HttpStatus.BAD_REQUEST); + } + String date = DateUtils.getDate(); + String uuid = IdUtil.fastSimpleUUID(); + String fileName = String.format("%s_%s.%s", date, uuid, suffix); + // 拼接文件路径 + Long pid = req.getPid(); + if (pid == null || pid == 0) { + throw new ServiceException("不能在根目录上传文件", HttpStatus.BAD_REQUEST); + } + DesTechnicalStandard pDesTechnicalStandard = this.getById(pid); + // 校验父级目录 + validParentFolder(pDesTechnicalStandard, projectId); + String filePath = pDesTechnicalStandard.getFilePath() + "/" + fileName; + // 上传文件 + SysOssUploadVo ossUploadVo = ossService.uploadWithNoSave(file, filePath); + // 保存文件信息 + DesTechnicalStandard desTechnicalStandard = new DesTechnicalStandard(); + desTechnicalStandard.setFilePath(filePath); + desTechnicalStandard.setFileUrl(ossUploadVo.getUrl()); + desTechnicalStandard.setFileSuffix(suffix); + if (DesTechnicalStandardConstant.PICTURE_SUFFIX_LIST.contains(suffix)) { + desTechnicalStandard.setFileType(DocumentTypeEnum.PICTURE.getValue()); + } else { + desTechnicalStandard.setFileType(DocumentTypeEnum.FILE.getValue()); + } + desTechnicalStandard.setFileName(FileUtil.getPrefix(originalFilename)); + desTechnicalStandard.setOriginalName(originalFilename); + desTechnicalStandard.setProjectId(projectId); + desTechnicalStandard.setPid(pid); + boolean save = this.save(desTechnicalStandard); + if (!save) { + throw new ServiceException("新增文件失败,数据库异常", HttpStatus.ERROR); + } + return this.getVo(this.getById(desTechnicalStandard.getId())); + } + + /** + * 新增技术标准管理文件夹 + * + * @param projectId 项目id + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertFolderByTemplate(Long projectId) { + // 创建顶级目录 + String prefix = DesTechnicalStandardConstant.getTopFolderPrefix(projectId); + String topPath = prefix + DesTechnicalStandardConstant.TOP_FOLDER_NAME; + DesTechnicalStandard topFolder = new DesTechnicalStandard(); + topFolder.setProjectId(projectId); + topFolder.setPid(0L); + topFolder.setFileName(DesTechnicalStandardConstant.TOP_FOLDER_NAME); + topFolder.setFilePath(topPath); + topFolder.setFileType(DocumentTypeEnum.FOLDER.getValue()); + boolean save = this.save(topFolder); + if (!save) { + throw new ServiceException("新增顶级目录失败,数据库异常", HttpStatus.ERROR); + } + // 创建二级目录 + Long pid = topFolder.getId(); + List documents = DesTechnicalStandardConstant.SECOND_LEVEL_FOLDER_NAME.stream().map(name -> { + DesTechnicalStandard folder = new DesTechnicalStandard(); + String path = topPath + "/" + name; + folder.setProjectId(projectId); + folder.setPid(pid); + folder.setFileName(name); + folder.setFilePath(path); + folder.setFileType(DocumentTypeEnum.FOLDER.getValue()); + return folder; + }).toList(); + return this.saveBatch(documents); + } + + /** + * 修改技术标准管理文件 + * + * @param req 质量知识库 + * @return 是否修改成功 + */ + @Override + public DesTechnicalStandardVo updateFile(DesTechnicalStandardFileUpdateReq req) { + Long id = req.getId(); + DesTechnicalStandard oldDocument = this.getById(id); + if (oldDocument == null) { + throw new ServiceException("修改技术标准管理文件失败,数据不存在", HttpStatus.NOT_FOUND); + } + DesTechnicalStandard document = new DesTechnicalStandard(); + BeanUtils.copyProperties(req, document); + boolean result = this.updateById(document); + if (!result) { + throw new ServiceException("修改技术标准管理文件失败", HttpStatus.ERROR); + } + return this.getVo(this.getById(id)); + } + + /** + * 删除技术标准管理文件信息 + * + * @param id 待删除文件的主键 + * @return 是否删除成功 + */ + @Override + public Boolean deleteFileById(Long id) { + DesTechnicalStandard document = this.getById(id); + if (document == null) { + throw new ServiceException("文件不存在", HttpStatus.ERROR); + } + if (!document.getFileStatus().equals(DocumentStatusEnum.NORMAL.getValue())) { + throw new ServiceException("文件已删除", HttpStatus.ERROR); + } + if (document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) { + throw new ServiceException("文件夹不能删除", HttpStatus.ERROR); + } + DesTechnicalStandard deleteDocument = new DesTechnicalStandard(); + deleteDocument.setId(document.getId()); + deleteDocument.setDeletedAt(new Date()); + deleteDocument.setFileStatus(DocumentStatusEnum.DELETE.getValue()); + return this.updateById(deleteDocument); + } + + /** + * 批量删除质量知识库回收站文件信息 + * + * @param ids 待删除文件主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteRecycleBinFileBatchByIds(Collection ids) { + Long userId = LoginHelper.getUserId(); + List documentList = this.listByIds(ids); + if (CollUtil.isEmpty(documentList)) { + throw new ServiceException("文件不存在", HttpStatus.ERROR); + } + Set projectIdList = documentList.stream().map(DesTechnicalStandard::getProjectId).collect(Collectors.toSet()); + projectService.validAuth(projectIdList, userId); + boolean result = this.removeBatchByIds(ids); + if (!result) { + throw new ServiceException("文件删除失败", HttpStatus.ERROR); + } + // 删除oss文件 + OssClient storage = OssFactory.instance(); + for (DesTechnicalStandard document : documentList) { + if (!document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) { + storage.delete(document.getFileUrl()); + } + } + return true; + } + + /** + * 批量恢复质量会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean recoveryBatchById(Collection ids) { + List allParentIdsRecursively = getAllParentIdsRecursively(ids); + // 需要更新状态的文件集合 + allParentIdsRecursively.addAll(ids); + List updateList = allParentIdsRecursively.stream().map(id -> { + DesTechnicalStandard documentSafetyMeeting = new DesTechnicalStandard(); + documentSafetyMeeting.setId(id); + documentSafetyMeeting.setFileStatus(DocumentStatusEnum.NORMAL.getValue()); + return documentSafetyMeeting; + }).toList(); + boolean result = this.updateBatchById(updateList); + if (!result) { + throw new ServiceException("恢复文件失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param documentList 文档列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildTreeSelect(List documentList) { + if (CollUtil.isEmpty(documentList)) { + return CollUtil.newArrayList(); + } + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (DesTechnicalStandard d : documentList) { + Long parentId = d.getPid(); + DesTechnicalStandard document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId)); + if (ObjectUtil.isNull(document)) { + List> trees = TreeBuildUtils.build(documentList, parentId, (desTechnicalStandard, tree) -> + tree.setId(desTechnicalStandard.getId()) + .setParentId(desTechnicalStandard.getPid()) + .setName(desTechnicalStandard.getFileName())); + Tree tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId())); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 构建文档封装对象 + * + * @param document 文档 + * @return 文档封装对象 + */ + @Override + public DesTechnicalStandardVo getVo(DesTechnicalStandard document) { + DesTechnicalStandardVo vo = new DesTechnicalStandardVo(); + if (document == null) { + return vo; + } + BeanUtils.copyProperties(document, vo); + return vo; + } + + /** + * 获取文档对象视图 + * + * @param documentPage 文档对象 + * @return 文档对象视图 + */ + @Override + public Page getVoPage(Page documentPage) { + List documentList = documentPage.getRecords(); + Page documentVoPage = new Page<>( + documentPage.getCurrent(), + documentPage.getSize(), + documentPage.getTotal()); + if (CollUtil.isEmpty(documentList)) { + return documentVoPage; + } + List documentVoList = documentList.stream().map(entity -> { + DesTechnicalStandardVo documentVo = new DesTechnicalStandardVo(); + BeanUtils.copyProperties(entity, documentVo); + return documentVo; + }).toList(); + documentVoPage.setRecords(documentVoList); + return documentVoPage; + } + + /** + * 畅写在线文件修改 + * + * @param id 文档id + * @param request 请求 + * @param response 响应 + */ + @Override + public void singleFileUploads(Long id, HttpServletRequest request, HttpServletResponse response) { + try { + PrintWriter writer = response.getWriter(); + Scanner scanner = new Scanner(request.getInputStream(), "GBK").useDelimiter("\\A"); + String body = scanner.hasNext() ? scanner.next() : ""; + JSONObject jsonObj = JSONUtil.parseObj(body); + if (jsonObj.getInt("status") == 2 || jsonObj.getInt("status") == 6) { + String downloadUri = (String) jsonObj.get("url"); + DesTechnicalStandard document = this.getById(id); + String filePath = document.getFilePath(); + ossService.uploadFileUrlWithNoSave(downloadUri, filePath); + } else if (jsonObj.getInt("status") == 3 || jsonObj.getInt("status") == 7) { + writer.write("{\"error\":-1}"); + } + writer.write("{\"error\":0}"); + } catch (IOException e) { + throw new ServiceException("质量知识库在线修改文件失败," + e); + } + } + + /** + * 校验父级目录是否存在 + * + * @param desTechnicalStandard 父级目录 + * @param projectId 当前项目id + */ + private void validParentFolder(DesTechnicalStandard desTechnicalStandard, Long projectId) { + // 判断父级目录是否存在 + if (desTechnicalStandard == null) { + throw new ServiceException("父级目录不存在", HttpStatus.NOT_FOUND); + } + // 判断父级目录是否是文件夹 + if (!DocumentTypeEnum.FOLDER.getValue().equals(desTechnicalStandard.getFileType())) { + throw new ServiceException("父级目录不是文件夹", HttpStatus.BAD_REQUEST); + } + // 判断是否为同一个项目 + if (!desTechnicalStandard.getProjectId().equals(projectId)) { + throw new ServiceException("父级目录不属于当前项目", HttpStatus.BAD_REQUEST); + } + } + + /** + * 递归查询所有父级 id + * + * @param ids id 列表 + * @return 父级 id 列表 + */ + private List getAllParentIdsRecursively(Collection ids) { + // 使用 list() 方法批量查询当前 id 列表对应的实体数据 + List fileList = this.lambdaQuery() + .in(DesTechnicalStandard::getId, ids) + .eq(DesTechnicalStandard::getFileStatus, DocumentStatusEnum.DELETE.getValue()) + .list(); + // 通过 stream 流过滤出非 0 的父 id,并去重 + List parentIdList = fileList.stream() + .map(DesTechnicalStandard::getPid) + .filter(pid -> pid != 0) + .distinct() + .collect(Collectors.toList()); + // 如果父 id 列表为空,说明递归终止,返回空列表 + if (parentIdList.isEmpty()) { + return new ArrayList<>(); + } + // 递归查询父 id 列表对应的上级父 id + List higherParentIds = getAllParentIdsRecursively(parentIdList); + // 将当前层的父 id 和上级递归得到的父 id 合并 + List allParentIds = new ArrayList<>(); + allParentIds.addAll(parentIdList); + allParentIds.addAll(higherParentIds); + // 返回合并后去重的结果 + return allParentIds.stream().distinct().collect(Collectors.toList()); + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.endsWith('technical')") + public void processHandler(ProcessEvent processEvent) { + log.info("技术标准文件审核任务执行了{}", processEvent.toString()); + DesTechnicalStandard technicalStandard = this.getById(Convert.toLong(processEvent.getBusinessId())); + technicalStandard.setStatus(processEvent.getStatus()); + if (processEvent.getSubmit()) { + technicalStandard.setStatus(BusinessStatusEnum.WAITING.getStatus()); + } + this.updateById(technicalStandard); + } + + /** + * 执行任务创建监听 + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.endsWith('technical')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("技术标准文件审核任务创建了{}", processTaskEvent.toString()); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @EventListener(condition = "#processDeleteEvent.flowCode.endsWith('technical')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,技术标准文件审核任务执行了{}", processDeleteEvent.toString()); + DesTechnicalStandard technicalStandard = this.getById(Convert.toLong(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(technicalStandard)) { + return; + } + String fileUrl = technicalStandard.getFileUrl(); + if (StringUtils.isNotBlank(fileUrl)) { + OssClient storage = OssFactory.instance(); + storage.delete(fileUrl); + } + this.removeById(technicalStandard.getId()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/controller/DroDroneConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/controller/DroDroneConfigController.java new file mode 100644 index 0000000..0ef09cd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/controller/DroDroneConfigController.java @@ -0,0 +1,105 @@ +package org.dromara.drone.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.drone.domain.vo.DroDroneConfigVo; +import org.dromara.drone.domain.bo.DroDroneConfigBo; +import org.dromara.drone.service.IDroDroneConfigService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 无人机配置 + * + * @author lilemy + * @date 2025-07-08 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/drone/droneConfig") +public class DroDroneConfigController extends BaseController { + + private final IDroDroneConfigService droDroneConfigService; + + /** + * 查询无人机配置列表 + */ + @SaCheckPermission("drone:droneConfig:list") + @GetMapping("/list") + public TableDataInfo list(DroDroneConfigBo bo, PageQuery pageQuery) { + return droDroneConfigService.queryPageList(bo, pageQuery); + } + + /** + * 导出无人机配置列表 + */ + @SaCheckPermission("drone:droneConfig:export") + @Log(title = "无人机配置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(DroDroneConfigBo bo, HttpServletResponse response) { + List list = droDroneConfigService.queryList(bo); + ExcelUtil.exportExcel(list, "无人机配置", DroDroneConfigVo.class, response); + } + + /** + * 获取无人机配置详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("drone:droneConfig:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(droDroneConfigService.queryById(id)); + } + + /** + * 新增无人机配置 + */ + @SaCheckPermission("drone:droneConfig:add") + @Log(title = "无人机配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DroDroneConfigBo bo) { + return toAjax(droDroneConfigService.insertByBo(bo)); + } + + /** + * 修改无人机配置 + */ + @SaCheckPermission("drone:droneConfig:edit") + @Log(title = "无人机配置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DroDroneConfigBo bo) { + return toAjax(droDroneConfigService.updateByBo(bo)); + } + + /** + * 删除无人机配置 + * + * @param ids 主键串 + */ + @SaCheckPermission("drone:droneConfig:remove") + @Log(title = "无人机配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(droDroneConfigService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/DroDroneConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/DroDroneConfig.java new file mode 100644 index 0000000..5675638 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/DroDroneConfig.java @@ -0,0 +1,66 @@ +package org.dromara.drone.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 无人机配置对象 dro_drone_config + * + * @author lilemy + * @date 2025-07-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("dro_drone_config") +public class DroDroneConfig extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 无人机服务地址 + */ + private String dockSocketUrl; + + /** + * ai识别服务地址 + */ + private String aiUrl; + + /** + * srs服务器地址 + */ + private String srsUrl; + + /** + * srs(rtmp服务端口) + */ + private String rtmpPort; + + /** + * srs(webrtc服务端口) + */ + private String rtcPort; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/bo/DroDroneConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/bo/DroDroneConfigBo.java new file mode 100644 index 0000000..0217970 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/bo/DroDroneConfigBo.java @@ -0,0 +1,77 @@ +package org.dromara.drone.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.drone.domain.DroDroneConfig; + +import java.io.Serial; + +/** + * 无人机配置业务对象 dro_drone_config + * + * @author lilemy + * @date 2025-07-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = DroDroneConfig.class, reverseConvertGenerate = false) +public class DroDroneConfigBo extends BaseEntity { + + @Serial + private static final long serialVersionUID = -814870483546946548L; + + /** + * 主键id + */ + @NotNull(message = "主键id不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long projectId; + + /** + * 无人机服务地址 + */ + @NotBlank(message = "无人机服务地址不能为空", groups = {AddGroup.class, EditGroup.class}) + private String dockSocketUrl; + + /** + * ai识别服务地址 + */ + @NotBlank(message = "ai识别服务地址不能为空", groups = {AddGroup.class, EditGroup.class}) + private String aiUrl; + + /** + * srs服务器地址 + */ + @NotBlank(message = "srs服务器地址不能为空", groups = {AddGroup.class, EditGroup.class}) + private String srsUrl; + + /** + * srs(rtmp服务端口) + */ + @NotBlank(message = "srs(rtmp服务端口)不能为空", groups = {AddGroup.class, EditGroup.class}) + private String rtmpPort; + + /** + * srs(webrtc服务端口) + */ + @NotBlank(message = "srs(webrtc服务端口)不能为空", groups = {AddGroup.class, EditGroup.class}) + private String rtcPort; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/vo/DroDroneConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/vo/DroDroneConfigVo.java new file mode 100644 index 0000000..e5ad153 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/domain/vo/DroDroneConfigVo.java @@ -0,0 +1,76 @@ +package org.dromara.drone.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.drone.domain.DroDroneConfig; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 无人机配置视图对象 dro_drone_config + * + * @author lilemy + * @date 2025-07-08 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DroDroneConfig.class) +public class DroDroneConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 无人机服务地址 + */ + @ExcelProperty(value = "无人机服务地址") + private String dockSocketUrl; + + /** + * ai识别服务地址 + */ + @ExcelProperty(value = "ai识别服务地址") + private String aiUrl; + + /** + * srs服务器地址 + */ + @ExcelProperty(value = "srs服务器地址") + private String srsUrl; + + /** + * srs(rtmp服务端口) + */ + @ExcelProperty(value = "srs(rtmp服务端口)") + private String rtmpPort; + + /** + * srs(webrtc服务端口) + */ + @ExcelProperty(value = "srs(webrtc服务端口)") + private String rtcPort; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/mapper/DroDroneConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/mapper/DroDroneConfigMapper.java new file mode 100644 index 0000000..58e9680 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/mapper/DroDroneConfigMapper.java @@ -0,0 +1,15 @@ +package org.dromara.drone.mapper; + +import org.dromara.drone.domain.DroDroneConfig; +import org.dromara.drone.domain.vo.DroDroneConfigVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 无人机配置Mapper接口 + * + * @author lilemy + * @date 2025-07-08 + */ +public interface DroDroneConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/IDroDroneConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/IDroDroneConfigService.java new file mode 100644 index 0000000..dd5217e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/IDroDroneConfigService.java @@ -0,0 +1,68 @@ +package org.dromara.drone.service; + +import org.dromara.drone.domain.vo.DroDroneConfigVo; +import org.dromara.drone.domain.bo.DroDroneConfigBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 无人机配置Service接口 + * + * @author lilemy + * @date 2025-07-08 + */ +public interface IDroDroneConfigService { + + /** + * 查询无人机配置 + * + * @param id 主键 + * @return 无人机配置 + */ + DroDroneConfigVo queryById(Long id); + + /** + * 分页查询无人机配置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 无人机配置分页列表 + */ + TableDataInfo queryPageList(DroDroneConfigBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的无人机配置列表 + * + * @param bo 查询条件 + * @return 无人机配置列表 + */ + List queryList(DroDroneConfigBo bo); + + /** + * 新增无人机配置 + * + * @param bo 无人机配置 + * @return 是否新增成功 + */ + Boolean insertByBo(DroDroneConfigBo bo); + + /** + * 修改无人机配置 + * + * @param bo 无人机配置 + * @return 是否修改成功 + */ + Boolean updateByBo(DroDroneConfigBo bo); + + /** + * 校验并批量删除无人机配置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/impl/DroDroneConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/impl/DroDroneConfigServiceImpl.java new file mode 100644 index 0000000..898ded2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/drone/service/impl/DroDroneConfigServiceImpl.java @@ -0,0 +1,129 @@ +package org.dromara.drone.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.drone.domain.DroDroneConfig; +import org.dromara.drone.domain.bo.DroDroneConfigBo; +import org.dromara.drone.domain.vo.DroDroneConfigVo; +import org.dromara.drone.mapper.DroDroneConfigMapper; +import org.dromara.drone.service.IDroDroneConfigService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 无人机配置Service业务层处理 + * + * @author lilemy + * @date 2025-07-08 + */ +@RequiredArgsConstructor +@Service +public class DroDroneConfigServiceImpl implements IDroDroneConfigService { + + private final DroDroneConfigMapper baseMapper; + + /** + * 查询无人机配置 + * + * @param id 主键 + * @return 无人机配置 + */ + @Override + public DroDroneConfigVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询无人机配置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 无人机配置分页列表 + */ + @Override + public TableDataInfo queryPageList(DroDroneConfigBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的无人机配置列表 + * + * @param bo 查询条件 + * @return 无人机配置列表 + */ + @Override + public List queryList(DroDroneConfigBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(DroDroneConfigBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(DroDroneConfig::getId); + lqw.eq(bo.getProjectId() != null, DroDroneConfig::getProjectId, bo.getProjectId()); + return lqw; + } + + /** + * 新增无人机配置 + * + * @param bo 无人机配置 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(DroDroneConfigBo bo) { + DroDroneConfig add = MapstructUtils.convert(bo, DroDroneConfig.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改无人机配置 + * + * @param bo 无人机配置 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(DroDroneConfigBo bo) { + DroDroneConfig update = MapstructUtils.convert(bo, DroDroneConfig.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DroDroneConfig entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除无人机配置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/constant/FacPhotovoltaicPanelPartsConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/constant/FacPhotovoltaicPanelPartsConstant.java new file mode 100644 index 0000000..e8a472a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/constant/FacPhotovoltaicPanelPartsConstant.java @@ -0,0 +1,15 @@ +package org.dromara.facility.constant; + +/** + * @author lilemy + * @date 2025/5/23 11:29 + */ +public interface FacPhotovoltaicPanelPartsConstant { + + String POINT = "钻孔"; + + String COLUMN = "桩基"; + + String SUPPORT = "支架"; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/constant/FacRedisKeyConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/constant/FacRedisKeyConstant.java new file mode 100644 index 0000000..78ac967 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/constant/FacRedisKeyConstant.java @@ -0,0 +1,102 @@ +package org.dromara.facility.constant; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/27 18:27 + */ +public interface FacRedisKeyConstant { + + /** + * 设施模块 Redis 缓存前缀 + */ + String FAC_REDIS_PREFIX = "fac:facility:"; + + /** + * 设施模块正在操作任务 Redis 缓存前缀 + */ + String FAC_IN_OPERATION_REDIS_KEY_PREFIX = FAC_REDIS_PREFIX + "inOperation:"; + + /** + * 设施模块类型 - 坐标 + */ + String GEO_TYPE_LOCAL = "location"; + + /** + * 设施模块类型 - 名称 + */ + String GEO_TYPE_NAME = "name"; + + /** + * 设施模块位置 GIS Redis 缓存前缀 + */ + String POSITION_GIS_REDIS_KEY_PREFIX = FAC_REDIS_PREFIX + "gis:" + "position:"; + + /** + * 批量上传桩点、支架、立柱 Redis 缓存 key + * + * @param sessionId 唯一标识 + * @param batchNum 第几批数据 + * @return Redis 缓存 key + */ + static String getBatchUploadPartsRedisKey(String sessionId, int batchNum) { + return String.format("%s%s:%s:%s", FAC_REDIS_PREFIX, "parts", sessionId, batchNum); + } + + /** + * 批量上传光伏板 Redis 缓存 key + * + * @param sessionId 唯一标识 + * @param batchNum 第几批数据 + * @param type 类型 + * @return Redis 缓存 key + */ + static String getBatchUploadPanelRedisKey(String sessionId, int batchNum, String type) { + return String.format("%s%s:%s:%s:%s", FAC_REDIS_PREFIX, "panel", sessionId, batchNum, type); + } + + /** + * 项目内进行中的任务 Redis 缓存 key 前缀 + * + * @param projectId 项目 ID + * @return Redis 缓存前缀 + */ + static String getInOperationByProjectRedisPrefix(Long projectId) { + return String.format("%s%s:%s:", FAC_IN_OPERATION_REDIS_KEY_PREFIX, "project", projectId); + } + + /** + * 当前项目下是否正在操作桩点、支架、立柱 Redis 缓存 key + * + * @param projectId 项目 ID + * @return Redis 缓存 key + */ + static String getPartsInOperationByProjectRedisKey(Long projectId) { + return String.format("%s%s", getInOperationByProjectRedisPrefix(projectId), "parts"); + } + + /** + * 当前项目下是否正在操作光伏板 Redis 缓存 key + * + * @param projectId 项目 ID + * @return Redis 缓存 key + */ + static String getPanelInOperationByProjectRedisKey(Long projectId) { + return String.format("%s%s", getInOperationByProjectRedisPrefix(projectId), "panel"); + } + + /** + * 获取操作的 Redis 缓存 key 列表 + * + * @param projectId 项目 ID + * @return Redis 缓存 key 列表 + */ + static List getInOperationRedisKeyList(Long projectId) { + return List.of( + getPartsInOperationByProjectRedisKey(projectId), + getPanelInOperationByProjectRedisKey(projectId) + ); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacBoxTransformerController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacBoxTransformerController.java new file mode 100644 index 0000000..221835c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacBoxTransformerController.java @@ -0,0 +1,121 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerCreateReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerQueryReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerUpdateReq; +import org.dromara.facility.domain.vo.boxtransformer.FacBoxTransformerVo; +import org.dromara.facility.service.IFacBoxTransformerService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-箱变 + * + * @author lilemy + * @date 2025-04-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/facility/boxTransformer") +public class FacBoxTransformerController extends BaseController { + + private final IFacBoxTransformerService facBoxTransformerService; + + /** + * 查询设施-箱变列表 + */ + @SaCheckPermission("facility:boxTransformer:list") + @GetMapping("/list") + public TableDataInfo list(FacBoxTransformerQueryReq req, PageQuery pageQuery) { + return facBoxTransformerService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-箱变列表 + */ + @SaCheckPermission("facility:boxTransformer:export") + @Log(title = "设施-箱变", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacBoxTransformerQueryReq req, HttpServletResponse response) { + List list = facBoxTransformerService.queryList(req); + ExcelUtil.exportExcel(list, "设施-箱变", FacBoxTransformerVo.class, response); + } + + /** + * 获取设施-箱变详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:boxTransformer:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facBoxTransformerService.queryById(id)); + } + + /** + * 新增设施-箱变 + */ + @SaCheckPermission("facility:boxTransformer:add") + @Log(title = "设施-箱变", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FacBoxTransformerCreateReq req) { + return R.ok(facBoxTransformerService.insertByBo(req)); + } + + /** + * 通过GeoJson新增设施-箱变 + */ + @SaCheckPermission("facility:boxTransformer:add") + @Log(title = "设施-箱变", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/geoJson") + public R insertByGeoJson(@RequestBody FacBoxTransformerCreateByGeoJsonReq req) { + return toAjax(facBoxTransformerService.insertByGeoJson(req)); + } + + /** + * 修改设施-箱变 + */ + @SaCheckPermission("facility:boxTransformer:edit") + @Log(title = "设施-箱变", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FacBoxTransformerUpdateReq req) { + return toAjax(facBoxTransformerService.updateByBo(req)); + } + + /** + * 删除设施-箱变 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:boxTransformer:remove") + @Log(title = "设施-箱变", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facBoxTransformerService.deleteWithValidByIds(List.of(ids), true)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacInverterController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacInverterController.java new file mode 100644 index 0000000..e3d14a0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacInverterController.java @@ -0,0 +1,121 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.inverter.FacInverterCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.inverter.FacInverterCreateReq; +import org.dromara.facility.domain.dto.inverter.FacInverterQueryReq; +import org.dromara.facility.domain.dto.inverter.FacInverterUpdateReq; +import org.dromara.facility.domain.vo.inverter.FacInverterVo; +import org.dromara.facility.service.IFacInverterService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-逆变器 + * + * @author lilemy + * @date 2025-04-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/facility/inverter") +public class FacInverterController extends BaseController { + + private final IFacInverterService facInverterService; + + /** + * 查询设施-逆变器列表 + */ + @SaCheckPermission("facility:inverter:list") + @GetMapping("/list") + public TableDataInfo list(FacInverterQueryReq req, PageQuery pageQuery) { + return facInverterService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-逆变器列表 + */ + @SaCheckPermission("facility:inverter:export") + @Log(title = "设施-逆变器", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacInverterQueryReq req, HttpServletResponse response) { + List list = facInverterService.queryList(req); + ExcelUtil.exportExcel(list, "设施-逆变器", FacInverterVo.class, response); + } + + /** + * 获取设施-逆变器详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:inverter:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facInverterService.queryById(id)); + } + + /** + * 新增设施-逆变器 + */ + @SaCheckPermission("facility:inverter:add") + @Log(title = "设施-逆变器", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FacInverterCreateReq req) { + return R.ok(facInverterService.insertByBo(req)); + } + + /** + * 通过GeoJson新增设施-逆变器 + */ + @SaCheckPermission("facility:inverter:add") + @Log(title = "设施-逆变器", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/geoJson") + public R insertByGeoJson(@RequestBody FacInverterCreateByGeoJsonReq req) { + return toAjax(facInverterService.insertByGeoJson(req)); + } + + /** + * 修改设施-逆变器 + */ + @SaCheckPermission("facility:inverter:edit") + @Log(title = "设施-逆变器", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FacInverterUpdateReq req) { + return toAjax(facInverterService.updateByBo(req)); + } + + /** + * 删除设施-逆变器 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:inverter:remove") + @Log(title = "设施-逆变器", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facInverterService.deleteWithValidByIds(List.of(ids), true)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacMatrixController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacMatrixController.java new file mode 100644 index 0000000..9ea0b7a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacMatrixController.java @@ -0,0 +1,138 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.matrix.*; +import org.dromara.facility.domain.vo.matrix.FacFacilityPositionGisVo; +import org.dromara.facility.domain.vo.matrix.FacMatrixDetailGisVo; +import org.dromara.facility.domain.vo.matrix.FacMatrixVo; +import org.dromara.facility.service.IFacMatrixService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-方阵 + * + * @author lilemy + * @date 2025-04-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/facility/matrix") +public class FacMatrixController extends BaseController { + + private final IFacMatrixService facMatrixService; + + /** + * 查询设施-方阵列表 + */ + @SaCheckPermission("facility:matrix:list") + @GetMapping("/list") + public TableDataInfo list(FacMatrixQueryReq req, PageQuery pageQuery) { + return facMatrixService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-方阵列表 + */ + @SaCheckPermission("facility:matrix:export") + @Log(title = "设施-方阵", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacMatrixQueryReq req, HttpServletResponse response) { + List list = facMatrixService.queryList(req); + ExcelUtil.exportExcel(list, "设施-方阵", FacMatrixVo.class, response); + } + + /** + * 获取设施-方阵详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:matrix:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facMatrixService.queryById(id)); + } + + /** + * 获取大屏方阵详情 + */ + @SaCheckPermission("facility:matrix:query") + @GetMapping("/gis") + public R getMatrixDetailGis(FacMatrixDetailGisReq req) { + return R.ok(facMatrixService.getMatrixDetailGis(req)); + } + + /** + * 获取设施-方阵大屏位置详情 + */ + @SaCheckPermission("facility:matrix:query") + @GetMapping("/gis/position") + public R> getPositionGis(FacFacilityPositionGisReq req) { + return R.ok(facMatrixService.getPositionGis(req)); + } + + /** + * 通过GeoJson新增设施-方阵 + */ + @SaCheckPermission("facility:matrix:add") + @Log(title = "设施-方阵", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/geoJson") + public R insertByGeoJson(@RequestBody FacMatrixCreateByGeoJsonReq req) { + return toAjax(facMatrixService.insertByGeoJson(req)); + } + + /** + * 新增设施-方阵 + */ + @SaCheckPermission("facility:matrix:add") + @Log(title = "设施-方阵", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FacMatrixCreateReq req) { + return R.ok(facMatrixService.insertByBo(req)); + } + + /** + * 修改设施-方阵 + */ + @SaCheckPermission("facility:matrix:edit") + @Log(title = "设施-方阵", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FacMatrixUpdateReq req) { + return toAjax(facMatrixService.updateByBo(req)); + } + + /** + * 删除设施-方阵 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:matrix:remove") + @Log(title = "设施-方阵", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facMatrixService.deleteWithValidByIds(List.of(ids), true)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPercentageFacilityController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPercentageFacilityController.java new file mode 100644 index 0000000..58fdecf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPercentageFacilityController.java @@ -0,0 +1,81 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.percentagefacility.FacPercentageFacilityQueryReq; +import org.dromara.facility.domain.vo.percentagefacility.FacPercentageFacilityVo; +import org.dromara.facility.service.IFacPercentageFacilityService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-百分比设施 + * + * @author lilemy + * @date 2025-05-26 + */ +@Validated +@RestController +@RequestMapping("/facility/percentageFacility") +public class FacPercentageFacilityController extends BaseController { + + @Resource + private IFacPercentageFacilityService facPercentageFacilityService; + + /** + * 查询设施-百分比设施列表 + */ + @SaCheckPermission("facility:percentageFacility:list") + @GetMapping("/list") + public TableDataInfo list(FacPercentageFacilityQueryReq req, PageQuery pageQuery) { + return facPercentageFacilityService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-百分比设施列表 + */ + @SaCheckPermission("facility:percentageFacility:export") + @Log(title = "设施-百分比设施", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacPercentageFacilityQueryReq req, HttpServletResponse response) { + List list = facPercentageFacilityService.queryList(req); + ExcelUtil.exportExcel(list, "设施-百分比设施", FacPercentageFacilityVo.class, response); + } + + /** + * 获取设施-百分比设施详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:percentageFacility:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facPercentageFacilityService.queryById(id)); + } + + /** + * 删除设施-百分比设施 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:percentageFacility:remove") + @Log(title = "设施-百分比设施", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facPercentageFacilityService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelColumnController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelColumnController.java new file mode 100644 index 0000000..1c8f346 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelColumnController.java @@ -0,0 +1,108 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnVo; +import org.dromara.facility.service.IFacPhotovoltaicPanelColumnService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-光伏板立柱 + * + * @author lilemy + * @date 2025-04-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/facility/photovoltaicPanelColumn") +public class FacPhotovoltaicPanelColumnController extends BaseController { + + private final IFacPhotovoltaicPanelColumnService facPhotovoltaicPanelColumnService; + + /** + * 查询设施-光伏板立柱列表 + */ + @SaCheckPermission("facility:photovoltaicPanelColumn:list") + @GetMapping("/list") + public TableDataInfo list(FacPhotovoltaicPanelColumnQueryReq req, PageQuery pageQuery) { + return facPhotovoltaicPanelColumnService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-光伏板立柱列表 + */ + @SaCheckPermission("facility:photovoltaicPanelColumn:export") + @Log(title = "设施-光伏板立柱", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacPhotovoltaicPanelColumnQueryReq req, HttpServletResponse response) { + List list = facPhotovoltaicPanelColumnService.queryList(req); + ExcelUtil.exportExcel(list, "设施-光伏板立柱", FacPhotovoltaicPanelColumnVo.class, response); + } + + /** + * 获取设施-光伏板立柱详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:photovoltaicPanelColumn:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facPhotovoltaicPanelColumnService.queryById(id)); + } + + /** + * 新增设施-光伏板立柱 + */ + @SaCheckPermission("facility:photovoltaicPanelColumn:add") + @Log(title = "设施-光伏板立柱", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FacPhotovoltaicPanelColumnCreateReq req) { + return R.ok(facPhotovoltaicPanelColumnService.insertByBo(req)); + } + + /** + * 修改设施-光伏板立柱 + */ + @SaCheckPermission("facility:photovoltaicPanelColumn:edit") + @Log(title = "设施-光伏板立柱", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FacPhotovoltaicPanelColumnUpdateReq req) { + return toAjax(facPhotovoltaicPanelColumnService.updateByBo(req)); + } + + /** + * 删除设施-光伏板立柱 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:photovoltaicPanelColumn:remove") + @Log(title = "设施-光伏板立柱", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facPhotovoltaicPanelColumnService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelController.java new file mode 100644 index 0000000..0246f49 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelController.java @@ -0,0 +1,120 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanel.FacPhotovoltaicPanelVo; +import org.dromara.facility.service.IFacPhotovoltaicPanelService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-光伏板 + * + * @author lilemy + * @date 2025-04-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/facility/photovoltaicPanel") +public class FacPhotovoltaicPanelController extends BaseController { + + private final IFacPhotovoltaicPanelService facPhotovoltaicPanelService; + + /** + * 查询设施-光伏板列表 + */ + @SaCheckPermission("facility:photovoltaicPanel:list") + @GetMapping("/list") + public TableDataInfo list(FacPhotovoltaicPanelQueryReq req, PageQuery pageQuery) { + return facPhotovoltaicPanelService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-光伏板列表 + */ + @SaCheckPermission("facility:photovoltaicPanel:export") + @Log(title = "设施-光伏板", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacPhotovoltaicPanelQueryReq req, HttpServletResponse response) { + List list = facPhotovoltaicPanelService.queryList(req); + ExcelUtil.exportExcel(list, "设施-光伏板", FacPhotovoltaicPanelVo.class, response); + } + + /** + * 获取设施-光伏板详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:photovoltaicPanel:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facPhotovoltaicPanelService.queryById(id)); + } + + /** + * 新增设施-光伏板 + */ + @SaCheckPermission("facility:photovoltaicPanel:add") + @Log(title = "设施-光伏板", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FacPhotovoltaicPanelCreateReq req) { + return R.ok(facPhotovoltaicPanelService.insertByBo(req)); + } + + /** + * 通过GeoJson新增设施-光伏板 + */ + @SaCheckPermission("facility:photovoltaicPanel:add") + @Log(title = "设施-光伏板", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/geoJson") + public R insertByGeoJson(@RequestBody FacPhotovoltaicPanelCreateByGeoJsonReq geoJson) { + return toAjax(facPhotovoltaicPanelService.insertByGeoJson(geoJson)); + } + + /** + * 修改设施-光伏板 + */ + @SaCheckPermission("facility:photovoltaicPanel:edit") + @Log(title = "设施-光伏板", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FacPhotovoltaicPanelUpdateReq req) { + return toAjax(facPhotovoltaicPanelService.updateByBo(req)); + } + + /** + * 删除设施-光伏板 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:photovoltaicPanel:remove") + @Log(title = "设施-光伏板", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facPhotovoltaicPanelService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelPartsController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelPartsController.java new file mode 100644 index 0000000..87b9cf1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelPartsController.java @@ -0,0 +1,52 @@ +package org.dromara.facility.controller; + +import jakarta.annotation.Resource; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.photovoltaicpanelparts.FacPhotovoltaicPanelPartsCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.photovoltaicpanelparts.FacPhotovoltaicPanelPartsCreateReq; +import org.dromara.facility.service.IFacPhotovoltaicPanelPartsService; +import org.springframework.validation.annotation.Validated; +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 lilemy + * @date 2025/4/21 + */ +@Validated +@RestController +@RequestMapping("/facility/photovoltaicPanelPoint/parts") +public class FacPhotovoltaicPanelPartsController extends BaseController { + + @Resource + private IFacPhotovoltaicPanelPartsService photovoltaicPanelPartsService; + + /** + * 通过GeoJson新增设施-光伏板桩点、立柱、支架 + */ + @Log(title = "设施-光伏板(桩点、立柱、支架)", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/geoJson") + public R insertPartsByGeoJson(@RequestBody FacPhotovoltaicPanelPartsCreateByGeoJsonReq req) { + return toAjax(photovoltaicPanelPartsService.insertPartsByGeoJson(req)); + } + + /** + * 新增设施-光伏板桩点、立柱、支架 + */ + @Log(title = "设施-光伏板(桩点、立柱、支架)", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R insertPartsByBatch(FacPhotovoltaicPanelPartsCreateReq req) { + return R.ok(photovoltaicPanelPartsService.insertPartsByBatch(req)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelPointController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelPointController.java new file mode 100644 index 0000000..76d5d22 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelPointController.java @@ -0,0 +1,108 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelpoint.FacPhotovoltaicPanelPointVo; +import org.dromara.facility.service.IFacPhotovoltaicPanelPointService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-光伏板桩点 + * + * @author lilemy + * @date 2025-04-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/facility/photovoltaicPanelPoint") +public class FacPhotovoltaicPanelPointController extends BaseController { + + private final IFacPhotovoltaicPanelPointService facPhotovoltaicPanelPointService; + + /** + * 查询设施-光伏板桩点列表 + */ + @SaCheckPermission("facility:photovoltaicPanelPoint:list") + @GetMapping("/list") + public TableDataInfo list(FacPhotovoltaicPanelPointQueryReq req, PageQuery pageQuery) { + return facPhotovoltaicPanelPointService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-光伏板桩点列表 + */ + @SaCheckPermission("facility:photovoltaicPanelPoint:export") + @Log(title = "设施-光伏板桩点", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacPhotovoltaicPanelPointQueryReq req, HttpServletResponse response) { + List list = facPhotovoltaicPanelPointService.queryList(req); + ExcelUtil.exportExcel(list, "设施-光伏板桩点", FacPhotovoltaicPanelPointVo.class, response); + } + + /** + * 获取设施-光伏板桩点详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:photovoltaicPanelPoint:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facPhotovoltaicPanelPointService.queryById(id)); + } + + /** + * 新增设施-光伏板桩点 + */ + @SaCheckPermission("facility:photovoltaicPanelPoint:add") + @Log(title = "设施-光伏板桩点", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FacPhotovoltaicPanelPointCreateReq req) { + return R.ok(facPhotovoltaicPanelPointService.insertByBo(req)); + } + + /** + * 修改设施-光伏板桩点 + */ + @SaCheckPermission("facility:photovoltaicPanelPoint:edit") + @Log(title = "设施-光伏板桩点", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FacPhotovoltaicPanelPointUpdateReq req) { + return toAjax(facPhotovoltaicPanelPointService.updateByBo(req)); + } + + /** + * 删除设施-光伏板桩点 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:photovoltaicPanelPoint:remove") + @Log(title = "设施-光伏板桩点", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facPhotovoltaicPanelPointService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelSupportController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelSupportController.java new file mode 100644 index 0000000..7872e3c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/controller/FacPhotovoltaicPanelSupportController.java @@ -0,0 +1,108 @@ +package org.dromara.facility.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportVo; +import org.dromara.facility.service.IFacPhotovoltaicPanelSupportService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设施-光伏板支架 + * + * @author lilemy + * @date 2025-04-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/facility/photovoltaicPanelSupport") +public class FacPhotovoltaicPanelSupportController extends BaseController { + + private final IFacPhotovoltaicPanelSupportService facPhotovoltaicPanelSupportService; + + /** + * 查询设施-光伏板支架列表 + */ + @SaCheckPermission("facility:photovoltaicPanelSupport:list") + @GetMapping("/list") + public TableDataInfo list(FacPhotovoltaicPanelSupportQueryReq req, PageQuery pageQuery) { + return facPhotovoltaicPanelSupportService.queryPageList(req, pageQuery); + } + + /** + * 导出设施-光伏板支架列表 + */ + @SaCheckPermission("facility:photovoltaicPanelSupport:export") + @Log(title = "设施-光伏板支架", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FacPhotovoltaicPanelSupportQueryReq req, HttpServletResponse response) { + List list = facPhotovoltaicPanelSupportService.queryList(req); + ExcelUtil.exportExcel(list, "设施-光伏板支架", FacPhotovoltaicPanelSupportVo.class, response); + } + + /** + * 获取设施-光伏板支架详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("facility:photovoltaicPanelSupport:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(facPhotovoltaicPanelSupportService.queryById(id)); + } + + /** + * 新增设施-光伏板支架 + */ + @SaCheckPermission("facility:photovoltaicPanelSupport:add") + @Log(title = "设施-光伏板支架", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FacPhotovoltaicPanelSupportCreateReq req) { + return R.ok(facPhotovoltaicPanelSupportService.insertByBo(req)); + } + + /** + * 修改设施-光伏板支架 + */ + @SaCheckPermission("facility:photovoltaicPanelSupport:edit") + @Log(title = "设施-光伏板支架", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FacPhotovoltaicPanelSupportUpdateReq req) { + return toAjax(facPhotovoltaicPanelSupportService.updateByBo(req)); + } + + /** + * 删除设施-光伏板支架 + * + * @param ids 主键串 + */ + @SaCheckPermission("facility:photovoltaicPanelSupport:remove") + @Log(title = "设施-光伏板支架", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(facPhotovoltaicPanelSupportService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacBoxTransformer.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacBoxTransformer.java new file mode 100644 index 0000000..dcc8fb7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacBoxTransformer.java @@ -0,0 +1,82 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.time.LocalDate; + +/** + * 设施-箱变对象 fac_box_transformer + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fac_box_transformer") +public class FacBoxTransformer extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 箱变名称 + */ + private String name; + + /** + * 箱变位置 + */ + private String positions; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 完成时间 + */ + private LocalDate finishDate; + + /** + * 进度类别id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacInverter.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacInverter.java new file mode 100644 index 0000000..1ad604a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacInverter.java @@ -0,0 +1,82 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.time.LocalDate; + +/** + * 设施-逆变器对象 fac_inverter + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fac_inverter") +public class FacInverter extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 逆变器名称 + */ + private String name; + + /** + * 逆变器位置 + */ + private String positions; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 完成时间 + */ + private LocalDate finishDate; + + /** + * 进度类别id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacMatrix.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacMatrix.java new file mode 100644 index 0000000..6e44d62 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacMatrix.java @@ -0,0 +1,51 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 设施-方阵对象 fac_matrix + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fac_matrix") +public class FacMatrix extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵名称 + */ + private String matrixName; + + /** + * 方阵位置 + */ + private String positions; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPercentageFacility.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPercentageFacility.java new file mode 100644 index 0000000..8c6beab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPercentageFacility.java @@ -0,0 +1,60 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 设施-百分比设施对象 fac_percentage_facility + * + * @author lilemy + * @date 2025-05-26 + */ +@Data +@TableName("fac_percentage_facility") +public class FacPercentageFacility implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 进度类型id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanel.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanel.java new file mode 100644 index 0000000..e8d44ec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanel.java @@ -0,0 +1,82 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.time.LocalDate; + +/** + * 设施-光伏板对象 fac_photovoltaic_panel + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fac_photovoltaic_panel") +public class FacPhotovoltaicPanel extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板名称 + */ + private String name; + + /** + * 光伏板位置 + */ + private String positions; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 完成时间 + */ + private LocalDate finishDate; + + /** + * 进度类别id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelColumn.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelColumn.java new file mode 100644 index 0000000..b84b120 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelColumn.java @@ -0,0 +1,82 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.time.LocalDate; + +/** + * 设施-光伏板立柱对象 fac_photovoltaic_panel_column + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fac_photovoltaic_panel_column") +public class FacPhotovoltaicPanelColumn extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板立柱名称 + */ + private String name; + + /** + * 光伏板立柱位置 + */ + private String positions; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 完成时间 + */ + private LocalDate finishDate; + + /** + * 进度类别id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelPoint.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelPoint.java new file mode 100644 index 0000000..4311600 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelPoint.java @@ -0,0 +1,82 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.time.LocalDate; + +/** + * 设施-光伏板桩点对象 fac_photovoltaic_panel_point + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fac_photovoltaic_panel_point") +public class FacPhotovoltaicPanelPoint extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板桩点名称 + */ + private String name; + + /** + * 光伏板桩点位置 + */ + private String positions; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 完成时间 + */ + private LocalDate finishDate; + + /** + * 进度类别id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelSupport.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelSupport.java new file mode 100644 index 0000000..1f1e192 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/FacPhotovoltaicPanelSupport.java @@ -0,0 +1,82 @@ +package org.dromara.facility.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.time.LocalDate; + +/** + * 设施-光伏板支架对象 fac_photovoltaic_panel_support + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fac_photovoltaic_panel_support") +public class FacPhotovoltaicPanelSupport extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板支架名称 + */ + private String name; + + /** + * 光伏板支架位置 + */ + private String positions; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 完成时间 + */ + private LocalDate finishDate; + + /** + * 进度类别id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerCreateByGeoJsonReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerCreateByGeoJsonReq.java new file mode 100644 index 0000000..802c000 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerCreateByGeoJsonReq.java @@ -0,0 +1,35 @@ +package org.dromara.facility.domain.dto.boxtransformer; + +import lombok.Data; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/23 18:12 + */ +@Data +public class FacBoxTransformerCreateByGeoJsonReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5887138349157048252L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 地理位置 + */ + private List locationGeoJson; + + /** + * 名称 + */ + private List nameGeoJson; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerCreateReq.java new file mode 100644 index 0000000..0b02928 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.dto.boxtransformer; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 16:54 + */ +@Data +public class FacBoxTransformerCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 4380175902468104569L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 箱变名称 + */ + private String name; + + /** + * 箱变位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerQueryReq.java new file mode 100644 index 0000000..1686ef2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.facility.domain.dto.boxtransformer; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/21 17:20 + */ +@Data +public class FacBoxTransformerQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -1963080752094759008L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 箱变名称 + */ + private String name; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerUpdateReq.java new file mode 100644 index 0000000..776a14f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/boxtransformer/FacBoxTransformerUpdateReq.java @@ -0,0 +1,59 @@ +package org.dromara.facility.domain.dto.boxtransformer; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 17:20 + */ +@Data +public class FacBoxTransformerUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7030781044685790507L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 箱变名称 + */ + private String name; + + /** + * 箱变位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeature.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeature.java new file mode 100644 index 0000000..1740213 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeature.java @@ -0,0 +1,22 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author lilemy + * @date 2025/4/24 17:38 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacFeature { + + private String type; + + private FacGeometry geometry; + + private FacProperties properties; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeatureByPlane.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeatureByPlane.java new file mode 100644 index 0000000..76e85b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeatureByPlane.java @@ -0,0 +1,28 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/24 10:32 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacFeatureByPlane implements Serializable { + + @Serial + private static final long serialVersionUID = 6732054357362738399L; + + private String type; + + private FacGeometryByPlane geometry; + + private FacProperties properties; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeatureByPoint.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeatureByPoint.java new file mode 100644 index 0000000..7d635e5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacFeatureByPoint.java @@ -0,0 +1,28 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/24 10:40 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacFeatureByPoint implements Serializable { + + @Serial + private static final long serialVersionUID = -3848496198713404019L; + + private String type; + + private FacGeometryByPoint geometry; + + private FacProperties properties; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJson.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJson.java new file mode 100644 index 0000000..2206186 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJson.java @@ -0,0 +1,24 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 17:37 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacGeoJson { + + private String name; + + private String type; + + private List features; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJsonByPlane.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJsonByPlane.java new file mode 100644 index 0000000..2e51444 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJsonByPlane.java @@ -0,0 +1,25 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 10:32 + */ +@Data +public class FacGeoJsonByPlane implements Serializable { + + @Serial + private static final long serialVersionUID = 7407176569611285023L; + + private String name; + + private String type; + + private List features; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJsonByPoint.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJsonByPoint.java new file mode 100644 index 0000000..3e84825 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeoJsonByPoint.java @@ -0,0 +1,25 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 10:38 + */ +@Data +public class FacGeoJsonByPoint implements Serializable { + + @Serial + private static final long serialVersionUID = 3829419654737988678L; + + private String name; + + private String type; + + private List features; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometry.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometry.java new file mode 100644 index 0000000..5ceddda --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometry.java @@ -0,0 +1,24 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 17:38 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacGeometry { + + private String type; + + private List coordinates; + + private Long id; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometryByPlane.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometryByPlane.java new file mode 100644 index 0000000..b2a92eb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometryByPlane.java @@ -0,0 +1,29 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 10:33 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacGeometryByPlane implements Serializable { + + @Serial + private static final long serialVersionUID = -82255764789167107L; + + private String type; + + private List>> coordinates; + + private Long id; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometryByPoint.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometryByPoint.java new file mode 100644 index 0000000..cc1ea90 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacGeometryByPoint.java @@ -0,0 +1,29 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 10:41 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacGeometryByPoint implements Serializable { + + @Serial + private static final long serialVersionUID = -5904591901195563882L; + + private String type; + + private List coordinates; + + private Long id; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacProperties.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacProperties.java new file mode 100644 index 0000000..da35910 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/geojson/FacProperties.java @@ -0,0 +1,26 @@ +package org.dromara.facility.domain.dto.geojson; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/24 10:53 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FacProperties implements Serializable { + + @Serial + private static final long serialVersionUID = -2997401596985220109L; + + private String type; + + private String text; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterCreateByGeoJsonReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterCreateByGeoJsonReq.java new file mode 100644 index 0000000..7be61e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterCreateByGeoJsonReq.java @@ -0,0 +1,35 @@ +package org.dromara.facility.domain.dto.inverter; + +import lombok.Data; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/23 18:15 + */ +@Data +public class FacInverterCreateByGeoJsonReq implements Serializable { + + @Serial + private static final long serialVersionUID = 924709230113144983L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 地理位置 + */ + private List locationGeoJson; + + /** + * 名称 + */ + private List nameGeoJson; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterCreateReq.java new file mode 100644 index 0000000..7f03b85 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.dto.inverter; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 17:57 + */ +@Data +public class FacInverterCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1722660769314535318L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 逆变器名称 + */ + private String name; + + /** + * 逆变器位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterQueryReq.java new file mode 100644 index 0000000..30718b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.facility.domain.dto.inverter; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/21 17:57 + */ +@Data +public class FacInverterQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6022414407700545902L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 逆变器名称 + */ + private String name; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterUpdateReq.java new file mode 100644 index 0000000..dc61cb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/inverter/FacInverterUpdateReq.java @@ -0,0 +1,59 @@ +package org.dromara.facility.domain.dto.inverter; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 17:58 + */ +@Data +public class FacInverterUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8042273364046693533L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 逆变器名称 + */ + private String name; + + /** + * 逆变器位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacFacilityPositionGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacFacilityPositionGisReq.java new file mode 100644 index 0000000..b93158a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacFacilityPositionGisReq.java @@ -0,0 +1,30 @@ +package org.dromara.facility.domain.dto.matrix; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/19 11:58 + */ +@Data +public class FacFacilityPositionGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = 7826656662352650068L; + + /** + * 项目id + */ + @NotNull(message = "项目ID不能为空") + private Long projectId; + + /** + * 方阵id列表 + */ + private List matrixIdList; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixCreateByGeoJsonReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixCreateByGeoJsonReq.java new file mode 100644 index 0000000..932dd3e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixCreateByGeoJsonReq.java @@ -0,0 +1,36 @@ +package org.dromara.facility.domain.dto.matrix; + +import lombok.Data; +import org.dromara.facility.domain.dto.geojson.FacGeoJson; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 11:03 + */ +@Data +public class FacMatrixCreateByGeoJsonReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3636617370172414549L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 地理位置 + */ + private List locationGeoJson; + + /** + * 名称 + */ + private List nameGeoJson; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixCreateReq.java new file mode 100644 index 0000000..af83598 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixCreateReq.java @@ -0,0 +1,39 @@ +package org.dromara.facility.domain.dto.matrix; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 14:55 + */ +@Data +public class FacMatrixCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -9094117932741747339L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵名称 + */ + private String matrixName; + + /** + * 方阵位置 + */ + private List> positionList; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixDetailGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixDetailGisReq.java new file mode 100644 index 0000000..6af99a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixDetailGisReq.java @@ -0,0 +1,28 @@ +package org.dromara.facility.domain.dto.matrix; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 16:27 + */ +@Data +public class FacMatrixDetailGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6514291289474982208L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixQueryReq.java new file mode 100644 index 0000000..781bdbe --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixQueryReq.java @@ -0,0 +1,28 @@ +package org.dromara.facility.domain.dto.matrix; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/21 14:58 + */ +@Data +public class FacMatrixQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6595145503602439606L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵名称 + */ + private String matrixName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixUpdateReq.java new file mode 100644 index 0000000..7faf410 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/matrix/FacMatrixUpdateReq.java @@ -0,0 +1,44 @@ +package org.dromara.facility.domain.dto.matrix; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 14:57 + */ +@Data +public class FacMatrixUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 384644288316208875L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵名称 + */ + private String matrixName; + + /** + * 方阵位置 + */ + private List> positionList; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/percentagefacility/FacPercentageFacilityQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/percentagefacility/FacPercentageFacilityQueryReq.java new file mode 100644 index 0000000..e2d790c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/percentagefacility/FacPercentageFacilityQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.facility.domain.dto.percentagefacility; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/26 18:46 + */ +@Data +public class FacPercentageFacilityQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2855861335256326590L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 进度类型id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelCreateByGeoJsonReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelCreateByGeoJsonReq.java new file mode 100644 index 0000000..aec9ed7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelCreateByGeoJsonReq.java @@ -0,0 +1,51 @@ +package org.dromara.facility.domain.dto.photovoltaicpanel; + +import lombok.Data; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPlane; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/24 9:53 + */ +@Data +public class FacPhotovoltaicPanelCreateByGeoJsonReq implements Serializable { + + @Serial + private static final long serialVersionUID = -14887945592031533L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 地理位置 + */ + private List locationGeoJson; + + /** + * 名称 + */ + private List nameGeoJson; + + /** + * 批次上传标识 + */ + private String sessionId; + + /** + * 当前批次 + */ + private int batchNum; + + /** + * 总批次 + */ + private int totalBatch; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelCreateReq.java new file mode 100644 index 0000000..9310833 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.dto.photovoltaicpanel; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 14:00 + */ +@Data +public class FacPhotovoltaicPanelCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6155515510030793296L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板名称 + */ + private String name; + + /** + * 光伏板位置 + */ + private List> positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelQueryReq.java new file mode 100644 index 0000000..b2e6231 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.facility.domain.dto.photovoltaicpanel; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/21 14:02 + */ +@Data +public class FacPhotovoltaicPanelQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 4450293360698837635L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板名称 + */ + private String name; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelUpdateReq.java new file mode 100644 index 0000000..b1f8cd3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanel/FacPhotovoltaicPanelUpdateReq.java @@ -0,0 +1,59 @@ +package org.dromara.facility.domain.dto.photovoltaicpanel; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 14:03 + */ +@Data +public class FacPhotovoltaicPanelUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7179168647795418115L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板名称 + */ + private String name; + + /** + * 光伏板位置 + */ + private List> positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnCreateReq.java new file mode 100644 index 0000000..c8dded6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelcolumn; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/22 9:50 + */ +@Data +public class FacPhotovoltaicPanelColumnCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5783638527565322237L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板立柱名称 + */ + private String name; + + /** + * 光伏板立柱位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnQueryReq.java new file mode 100644 index 0000000..2e1f677 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelcolumn; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/22 9:51 + */ +@Data +public class FacPhotovoltaicPanelColumnQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4288306372664325906L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板立柱名称 + */ + private String name; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnUpdateReq.java new file mode 100644 index 0000000..b7e0eb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnUpdateReq.java @@ -0,0 +1,59 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelcolumn; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/22 9:50 + */ +@Data +public class FacPhotovoltaicPanelColumnUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6489049981734037038L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板立柱名称 + */ + private String name; + + /** + * 光伏板立柱位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelparts/FacPhotovoltaicPanelPartsCreateByGeoJsonReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelparts/FacPhotovoltaicPanelPartsCreateByGeoJsonReq.java new file mode 100644 index 0000000..80fd164 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelparts/FacPhotovoltaicPanelPartsCreateByGeoJsonReq.java @@ -0,0 +1,44 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelparts; + +import lombok.Data; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/24 11:01 + */ +@Data +public class FacPhotovoltaicPanelPartsCreateByGeoJsonReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5682597792623228174L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 桩点、立柱、支架 GeoJson + */ + private FacGeoJsonByPoint locationGeoJson; + + /** + * 批次上传标识 + */ + private String sessionId; + + /** + * 当前批次 + */ + private int batchNum; + + /** + * 总批次 + */ + private int totalBatch; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelparts/FacPhotovoltaicPanelPartsCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelparts/FacPhotovoltaicPanelPartsCreateReq.java new file mode 100644 index 0000000..a9c7e91 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelparts/FacPhotovoltaicPanelPartsCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelparts; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/21 15:45 + */ +@Data +public class FacPhotovoltaicPanelPartsCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -584396159753737769L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板(桩点、立柱、支架)名称 + */ + private String name; + + /** + * 光伏板(桩点、立柱、支架)位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointCreateReq.java new file mode 100644 index 0000000..8715c5c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelpoint; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/22 9:48 + */ +@Data +public class FacPhotovoltaicPanelPointCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8316395563268976925L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板桩点名称 + */ + private String name; + + /** + * 光伏板桩点位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointQueryReq.java new file mode 100644 index 0000000..aa01259 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelpoint; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/22 9:48 + */ +@Data +public class FacPhotovoltaicPanelPointQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5325875051802738981L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板桩点名称 + */ + private String name; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointUpdateReq.java new file mode 100644 index 0000000..72b61d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelpoint/FacPhotovoltaicPanelPointUpdateReq.java @@ -0,0 +1,59 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelpoint; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/22 9:48 + */ +@Data +public class FacPhotovoltaicPanelPointUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6060380651961899938L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板桩点名称 + */ + private String name; + + /** + * 光伏板桩点位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportCreateReq.java new file mode 100644 index 0000000..a92f449 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelsupport; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/22 9:40 + */ +@Data +public class FacPhotovoltaicPanelSupportCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2859712819532622700L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板支架名称 + */ + private String name; + + /** + * 光伏板支架位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportQueryReq.java new file mode 100644 index 0000000..b557bd7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelsupport; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/22 9:43 + */ +@Data +public class FacPhotovoltaicPanelSupportQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6204782404060432065L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板支架名称 + */ + private String name; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportUpdateReq.java new file mode 100644 index 0000000..1b3c42e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/dto/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportUpdateReq.java @@ -0,0 +1,59 @@ +package org.dromara.facility.domain.dto.photovoltaicpanelsupport; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/22 9:40 + */ +@Data +public class FacPhotovoltaicPanelSupportUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2466440719288904185L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 光伏板支架名称 + */ + private String name; + + /** + * 光伏板支架位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + private String finishType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacCategoryEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacCategoryEnum.java new file mode 100644 index 0000000..7cab2b8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacCategoryEnum.java @@ -0,0 +1,40 @@ +package org.dromara.facility.domain.enums; + +import lombok.Getter; + +import java.util.Objects; + +/** + * @author lilemy + * @date 2025/6/19 9:37 + */ +@Getter +public enum FacCategoryEnum { + + MATRIX("方阵", "fz"), + PHOTOVOLTAIC_PANEL("光伏板", "gfb"), + BOX_TRANSFORMER("箱变", "xb"), + INVERTER("逆变器", "nbq"), + PHOTOVOLTAIC_PANEL_SUPPORT("光伏板支架", "gfbzj"), + PHOTOVOLTAIC_PANEL_COLUMN("光伏板立柱", "gfblz"), + PHOTOVOLTAIC_PANEL_POINT("光伏板桩点", "gfbzd"); + + private final String text; + + private final String value; + + FacCategoryEnum(String text, String value) { + this.text = text; + this.value = value; + } + + // 根据 value 获取对应的 text + public static String getTextByValue(String value) { + for (FacCategoryEnum type : values()) { + if (Objects.equals(type.getValue(), value)) { + return type.getText(); + } + } + return null; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacCoordinateTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacCoordinateTypeEnum.java new file mode 100644 index 0000000..27215f6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacCoordinateTypeEnum.java @@ -0,0 +1,34 @@ +package org.dromara.facility.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/6/19 9:26 + */ +@Getter +public enum FacCoordinateTypeEnum { + + POINT("Point", 1), + POLYGON("Polygon", 2); + + private final String text; + + private final int value; + + FacCoordinateTypeEnum(String text, int value) { + this.text = text; + this.value = value; + } + + // 根据 value 获取对应的 text + public static String getTextByValue(int value) { + for (FacCoordinateTypeEnum type : values()) { + if (type.getValue() == value) { + return type.getText(); + } + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacFinishStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacFinishStatusEnum.java new file mode 100644 index 0000000..4c5e83a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacFinishStatusEnum.java @@ -0,0 +1,25 @@ +package org.dromara.facility.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/28 16:34 + */ +@Getter +public enum FacFinishStatusEnum { + + UNFINISH("未开始", "0"), + INPROGRESS("进行中", "1"), + FINISH("已完成", "2"); + + private final String text; + + private final String value; + + FacFinishStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacFinishTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacFinishTypeEnum.java new file mode 100644 index 0000000..61ff0ff --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/enums/FacFinishTypeEnum.java @@ -0,0 +1,24 @@ +package org.dromara.facility.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/5/28 10:17 + */ +@Getter +public enum FacFinishTypeEnum { + + HAND("手动填报", "1"), + AI("AI填报", "2"); + + private final String text; + + private final String value; + + FacFinishTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/boxtransformer/FacBoxTransformerPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/boxtransformer/FacBoxTransformerPositionGisVo.java new file mode 100644 index 0000000..a5f7452 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/boxtransformer/FacBoxTransformerPositionGisVo.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.vo.boxtransformer; + +import cn.hutool.json.JSONUtil; +import lombok.Data; +import org.dromara.facility.domain.FacBoxTransformer; +import org.springframework.beans.BeanUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/18 16:22 + */ +@Data +public class FacBoxTransformerPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -5381920624456948144L; + + /** + * 主键 + */ + private Long id; + + /** + * 箱变名称 + */ + private String name; + + /** + * 箱变位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 对象转vo + */ + public static FacBoxTransformerPositionGisVo obj2vo(FacBoxTransformer obj) { + FacBoxTransformerPositionGisVo vo = new FacBoxTransformerPositionGisVo(); + BeanUtils.copyProperties(obj, vo); + String positions = obj.getPositions(); + List positionList = JSONUtil.toList(positions, Double.class); + vo.setPositionList(positionList); + return vo; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/boxtransformer/FacBoxTransformerVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/boxtransformer/FacBoxTransformerVo.java new file mode 100644 index 0000000..9014713 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/boxtransformer/FacBoxTransformerVo.java @@ -0,0 +1,86 @@ +package org.dromara.facility.domain.vo.boxtransformer; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.facility.domain.FacBoxTransformer; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 设施-箱变视图对象 fac_box_transformer + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacBoxTransformer.class) +public class FacBoxTransformerVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + @ExcelProperty(value = "方阵id") + private Long matrixId; + + /** + * 箱变名称 + */ + @ExcelProperty(value = "箱变名称") + private String name; + + /** + * 箱变位置 + */ + @ExcelProperty(value = "箱变位置") + private String positions; + + /** + * 箱变位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=完成") + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + @ExcelProperty(value = "完成类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=手动填报,2=AI填报") + private String finishType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/inverter/FacInverterPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/inverter/FacInverterPositionGisVo.java new file mode 100644 index 0000000..11c405b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/inverter/FacInverterPositionGisVo.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.vo.inverter; + +import cn.hutool.json.JSONUtil; +import lombok.Data; +import org.dromara.facility.domain.FacInverter; +import org.springframework.beans.BeanUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/18 16:22 + */ +@Data +public class FacInverterPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = 497930244187026829L; + + /** + * 主键 + */ + private Long id; + + /** + * 逆变器名称 + */ + private String name; + + /** + * 逆变器位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 对象转vo + */ + public static FacInverterPositionGisVo obj2vo(FacInverter obj) { + FacInverterPositionGisVo vo = new FacInverterPositionGisVo(); + BeanUtils.copyProperties(obj, vo); + String positions = obj.getPositions(); + List positionList = JSONUtil.toList(positions, Double.class); + vo.setPositionList(positionList); + return vo; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/inverter/FacInverterVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/inverter/FacInverterVo.java new file mode 100644 index 0000000..694075c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/inverter/FacInverterVo.java @@ -0,0 +1,86 @@ +package org.dromara.facility.domain.vo.inverter; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.facility.domain.FacInverter; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 设施-逆变器视图对象 fac_inverter + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacInverter.class) +public class FacInverterVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + @ExcelProperty(value = "方阵id") + private Long matrixId; + + /** + * 逆变器名称 + */ + @ExcelProperty(value = "逆变器名称") + private String name; + + /** + * 逆变器位置 + */ + @ExcelProperty(value = "逆变器位置") + private String positions; + + /** + * 逆变器位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=完成") + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + @ExcelProperty(value = "完成类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=手动填报,2=AI填报") + private String finishType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacFacilityPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacFacilityPositionGisVo.java new file mode 100644 index 0000000..7cd4065 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacFacilityPositionGisVo.java @@ -0,0 +1,74 @@ +package org.dromara.facility.domain.vo.matrix; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import lombok.Data; +import org.dromara.facility.domain.enums.FacCoordinateTypeEnum; +import org.dromara.common.utils.JsonDimensionUtil; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/19 9:20 + */ +@Data +public class FacFacilityPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = 7684151080297158036L; + + /** + * 主键 + */ + private Long id; + + /** + * 名称 + */ + private String name; + + /** + * 位置 + */ + private JSONArray positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 坐标类型 + */ + private String type; + + /** + * 分类 + */ + private String category; + + /** + * 对象转vo + * + * @param id 主键 + * @param name 名称 + * @param positions 位置字符串 + * @param status 完成状态(0未开始 1进行中 2完成) + * @return FacFacilityPositionGisVo + */ + public static FacFacilityPositionGisVo obj2vo(Long id, String name, String positions, String status, String category) { + FacFacilityPositionGisVo vo = new FacFacilityPositionGisVo(); + vo.setId(id); + vo.setName(name); + JSONArray positionList = JSONUtil.parseArray(positions); + vo.setPositionList(positionList); + vo.setStatus(status); + int depth = JsonDimensionUtil.getJsonArrayDepth(positionList); + vo.setType(FacCoordinateTypeEnum.getTextByValue(depth)); + vo.setCategory(category); + return vo; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixBySubProjectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixBySubProjectVo.java new file mode 100644 index 0000000..2f0476c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixBySubProjectVo.java @@ -0,0 +1,28 @@ +package org.dromara.facility.domain.vo.matrix; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/10 15:09 + */ +@Data +public class FacMatrixBySubProjectVo implements Serializable { + + @Serial + private static final long serialVersionUID = -3427826315362519128L; + + /** + * 主键 + */ + private Long matrixId; + + /** + * 方阵名称 + */ + private String name; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixDetailGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixDetailGisVo.java new file mode 100644 index 0000000..8a5fc0a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixDetailGisVo.java @@ -0,0 +1,78 @@ +package org.dromara.facility.domain.vo.matrix; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 16:19 + */ +@Data +public class FacMatrixDetailGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = 138750225601876373L; + + /** + * 总箱变数量 + */ + private Long boxTransformerCount; + + /** + * 已完成箱变数量 + */ + private Long boxTransformerFinishCount; + + /** + * 总逆变器数量 + */ + private Long inverterCount; + + /** + * 已完成逆变器数量 + */ + private Long inverterFinishCount; + + /** + * 总光伏板数量 + */ + private Long photovoltaicPanelCount; + + /** + * 已完成光伏板数量 + */ + private Long photovoltaicPanelFinishCount; + + /** + * 光伏板总点位数量 + */ + private Long pointCount; + + /** + * 已完成光伏板点位数量 + */ + private Long pointFinishCount; + + /** + * 光伏板总立柱数量 + */ + private Long columnCount; + + /** + * 已完成光伏板立柱数量 + */ + private Long columnFinishCount; + + /** + * 光伏板总支架数量 + */ + private Long supportCount; + + /** + * 已完成光伏板支架数量 + */ + private Long supportFinishCount; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixPositionGisVo.java new file mode 100644 index 0000000..dc36453 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixPositionGisVo.java @@ -0,0 +1,70 @@ +package org.dromara.facility.domain.vo.matrix; + +import lombok.Data; +import org.dromara.facility.domain.vo.boxtransformer.FacBoxTransformerPositionGisVo; +import org.dromara.facility.domain.vo.inverter.FacInverterPositionGisVo; +import org.dromara.facility.domain.vo.photovoltaicpanel.FacPhotovoltaicPanelPositionGisVo; +import org.dromara.facility.domain.vo.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnPositionGisVo; +import org.dromara.facility.domain.vo.photovoltaicpanelpoint.FacPhotovoltaicPanelPointPositionGisVo; +import org.dromara.facility.domain.vo.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportPositionGisVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/18 16:14 + */ +@Data +public class FacMatrixPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = 7720584094593327756L; + + /** + * 主键 + */ + private Long id; + + /** + * 方阵名称 + */ + private String matrixName; + + /** + * 方阵位置 + */ + private List> positions; + + /** + * 逆变器位置 + */ + private List inverterPositionList; + + /** + * 箱变位置 + */ + private List boxTransformerPositionList; + + /** + * 光伏板位置 + */ + private List photovoltaicPanelPositionList; + + /** + * 光伏板立柱位置 + */ + private List photovoltaicPanelColumnPositionList; + + /** + * 光伏板支架位置 + */ + private List photovoltaicPanelSupportPositionList; + + /** + * 光伏板桩点位置 + */ + private List photovoltaicPanelPointPositionList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixVo.java new file mode 100644 index 0000000..dcf0210 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/matrix/FacMatrixVo.java @@ -0,0 +1,51 @@ +package org.dromara.facility.domain.vo.matrix; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.facility.domain.FacMatrix; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 设施-方阵视图对象 fac_matrix + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacMatrix.class) +public class FacMatrixVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵名称 + */ + @ExcelProperty(value = "方阵名称") + private String matrixName; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/percentagefacility/FacPercentageFacilityVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/percentagefacility/FacPercentageFacilityVo.java new file mode 100644 index 0000000..3345048 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/percentagefacility/FacPercentageFacilityVo.java @@ -0,0 +1,58 @@ +package org.dromara.facility.domain.vo.percentagefacility; + +import org.dromara.facility.domain.FacPercentageFacility; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 设施-百分比设施视图对象 fac_percentage_facility + * + * @author lilemy + * @date 2025-05-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacPercentageFacility.class) +public class FacPercentageFacilityVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + @ExcelProperty(value = "方阵id") + private Long matrixId; + + /** + * 进度类型id + */ + @ExcelProperty(value = "进度类型id") + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + @ExcelProperty(value = "进度类别名称") + private String progressCategoryName; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanel/FacPhotovoltaicPanelPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanel/FacPhotovoltaicPanelPositionGisVo.java new file mode 100644 index 0000000..4362156 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanel/FacPhotovoltaicPanelPositionGisVo.java @@ -0,0 +1,59 @@ +package org.dromara.facility.domain.vo.photovoltaicpanel; + +import cn.hutool.json.JSONUtil; +import lombok.Data; +import org.dromara.facility.domain.FacPhotovoltaicPanel; +import org.springframework.beans.BeanUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/18 16:19 + */ +@Data +public class FacPhotovoltaicPanelPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -851548161301247186L; + + /** + * 主键 + */ + private Long id; + + /** + * 光伏板名称 + */ + private String name; + + /** + * 光伏板位置 + */ + private List> positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 对象转VO + */ + public static FacPhotovoltaicPanelPositionGisVo obj2vo(FacPhotovoltaicPanel obj) { + FacPhotovoltaicPanelPositionGisVo vo = new FacPhotovoltaicPanelPositionGisVo(); + BeanUtils.copyProperties(obj, vo); + String positions = obj.getPositions(); + List> positionList = new ArrayList<>(); + List arr = JSONUtil.toList(positions, String.class); + for (String s : arr) { + positionList.add(JSONUtil.toList(s, Double.class)); + } + vo.setPositionList(positionList); + return vo; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanel/FacPhotovoltaicPanelVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanel/FacPhotovoltaicPanelVo.java new file mode 100644 index 0000000..8abba75 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanel/FacPhotovoltaicPanelVo.java @@ -0,0 +1,86 @@ +package org.dromara.facility.domain.vo.photovoltaicpanel; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.facility.domain.FacPhotovoltaicPanel; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 设施-光伏板视图对象 fac_photovoltaic_panel + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacPhotovoltaicPanel.class) +public class FacPhotovoltaicPanelVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + @ExcelProperty(value = "方阵id") + private Long matrixId; + + /** + * 光伏板名称 + */ + @ExcelProperty(value = "光伏板名称") + private String name; + + /** + * 光伏板位置 + */ + @ExcelProperty(value = "光伏板位置") + private String positions; + + /** + * 光伏板位置 + */ + private List> positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=完成") + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + @ExcelProperty(value = "完成类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=手动填报,2=AI填报") + private String finishType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnPositionGisVo.java new file mode 100644 index 0000000..6856eef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnPositionGisVo.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.vo.photovoltaicpanelcolumn; + +import cn.hutool.json.JSONUtil; +import lombok.Data; +import org.dromara.facility.domain.FacPhotovoltaicPanelColumn; +import org.springframework.beans.BeanUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/18 16:25 + */ +@Data +public class FacPhotovoltaicPanelColumnPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = 8131058424226441681L; + + /** + * 主键 + */ + private Long id; + + /** + * 光伏板立柱名称 + */ + private String name; + + /** + * 光伏板立柱位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 对象转vo + */ + public static FacPhotovoltaicPanelColumnPositionGisVo obj2vo(FacPhotovoltaicPanelColumn obj) { + FacPhotovoltaicPanelColumnPositionGisVo vo = new FacPhotovoltaicPanelColumnPositionGisVo(); + BeanUtils.copyProperties(obj, vo); + String positions = obj.getPositions(); + List positionList = JSONUtil.toList(positions, Double.class); + vo.setPositionList(positionList); + return vo; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnVo.java new file mode 100644 index 0000000..6ff845c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelcolumn/FacPhotovoltaicPanelColumnVo.java @@ -0,0 +1,86 @@ +package org.dromara.facility.domain.vo.photovoltaicpanelcolumn; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.facility.domain.FacPhotovoltaicPanelColumn; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 设施-光伏板立柱视图对象 fac_photovoltaic_panel_column + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacPhotovoltaicPanelColumn.class) +public class FacPhotovoltaicPanelColumnVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + @ExcelProperty(value = "方阵id") + private Long matrixId; + + /** + * 光伏板立柱名称 + */ + @ExcelProperty(value = "光伏板立柱名称") + private String name; + + /** + * 光伏板立柱位置 + */ + @ExcelProperty(value = "光伏板立柱位置") + private String positions; + + /** + * 光伏板立柱位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=完成") + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + @ExcelProperty(value = "完成类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=手动填报,2=AI填报") + private String finishType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelpoint/FacPhotovoltaicPanelPointPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelpoint/FacPhotovoltaicPanelPointPositionGisVo.java new file mode 100644 index 0000000..d9c2930 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelpoint/FacPhotovoltaicPanelPointPositionGisVo.java @@ -0,0 +1,54 @@ +package org.dromara.facility.domain.vo.photovoltaicpanelpoint; + +import cn.hutool.json.JSONUtil; +import lombok.Data; +import org.dromara.facility.domain.FacPhotovoltaicPanelPoint; +import org.springframework.beans.BeanUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/18 16:25 + */ +@Data +public class FacPhotovoltaicPanelPointPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -8626958457981310560L; + + /** + * 主键 + */ + private Long id; + + /** + * 光伏板桩点名称 + */ + private String name; + + /** + * 光伏板桩点位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 对象转vo + */ + public static FacPhotovoltaicPanelPointPositionGisVo obj2vo(FacPhotovoltaicPanelPoint obj) { + FacPhotovoltaicPanelPointPositionGisVo vo = new FacPhotovoltaicPanelPointPositionGisVo(); + BeanUtils.copyProperties(obj, vo); + String positions = obj.getPositions(); + List positionList = JSONUtil.toList(positions, Double.class); + vo.setPositionList(positionList); + return vo; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelpoint/FacPhotovoltaicPanelPointVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelpoint/FacPhotovoltaicPanelPointVo.java new file mode 100644 index 0000000..6ed0ea6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelpoint/FacPhotovoltaicPanelPointVo.java @@ -0,0 +1,86 @@ +package org.dromara.facility.domain.vo.photovoltaicpanelpoint; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.facility.domain.FacPhotovoltaicPanelPoint; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 设施-光伏板桩点视图对象 fac_photovoltaic_panel_point + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacPhotovoltaicPanelPoint.class) +public class FacPhotovoltaicPanelPointVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + @ExcelProperty(value = "方阵id") + private Long matrixId; + + /** + * 光伏板桩点名称 + */ + @ExcelProperty(value = "光伏板桩点名称") + private String name; + + /** + * 光伏板桩点位置 + */ + @ExcelProperty(value = "光伏板桩点位置") + private String positions; + + /** + * 光伏板桩点位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=完成") + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + @ExcelProperty(value = "完成类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=手动填报,2=AI填报") + private String finishType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportPositionGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportPositionGisVo.java new file mode 100644 index 0000000..25ca1ae --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportPositionGisVo.java @@ -0,0 +1,55 @@ +package org.dromara.facility.domain.vo.photovoltaicpanelsupport; + +import cn.hutool.json.JSONUtil; +import lombok.Data; +import org.dromara.facility.domain.FacPhotovoltaicPanelSupport; +import org.springframework.beans.BeanUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/18 16:25 + */ +@Data +public class FacPhotovoltaicPanelSupportPositionGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = 330832487175547581L; + + /** + * 主键 + */ + private Long id; + + /** + * 光伏板支架名称 + */ + private String name; + + /** + * 光伏板支架位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 对象转vo + */ + public static FacPhotovoltaicPanelSupportPositionGisVo obj2vo(FacPhotovoltaicPanelSupport obj){ + FacPhotovoltaicPanelSupportPositionGisVo vo = new FacPhotovoltaicPanelSupportPositionGisVo(); + BeanUtils.copyProperties(obj, vo); + String positions = obj.getPositions(); + List positionList = JSONUtil.toList(positions, Double.class); + vo.setPositionList(positionList); + return vo; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportVo.java new file mode 100644 index 0000000..b37d978 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/domain/vo/photovoltaicpanelsupport/FacPhotovoltaicPanelSupportVo.java @@ -0,0 +1,86 @@ +package org.dromara.facility.domain.vo.photovoltaicpanelsupport; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.facility.domain.FacPhotovoltaicPanelSupport; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 设施-光伏板支架视图对象 fac_photovoltaic_panel_support + * + * @author lilemy + * @date 2025-04-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FacPhotovoltaicPanelSupport.class) +public class FacPhotovoltaicPanelSupportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + @ExcelProperty(value = "方阵id") + private Long matrixId; + + /** + * 光伏板支架名称 + */ + @ExcelProperty(value = "光伏板支架名称") + private String name; + + /** + * 光伏板支架位置 + */ + @ExcelProperty(value = "光伏板支架位置") + private String positions; + + /** + * 光伏板支架位置 + */ + private List positionList; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=完成") + private String status; + + /** + * 完成类型(1手动填报 2AI填报) + */ + @ExcelProperty(value = "完成类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=手动填报,2=AI填报") + private String finishType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacBoxTransformerMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacBoxTransformerMapper.java new file mode 100644 index 0000000..7f96f63 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacBoxTransformerMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacBoxTransformer; +import org.dromara.facility.domain.vo.boxtransformer.FacBoxTransformerVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-箱变Mapper接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface FacBoxTransformerMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacInverterMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacInverterMapper.java new file mode 100644 index 0000000..1ec4e28 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacInverterMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacInverter; +import org.dromara.facility.domain.vo.inverter.FacInverterVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-逆变器Mapper接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface FacInverterMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacMatrixMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacMatrixMapper.java new file mode 100644 index 0000000..5700035 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacMatrixMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.domain.vo.matrix.FacMatrixVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-方阵Mapper接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface FacMatrixMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPercentageFacilityMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPercentageFacilityMapper.java new file mode 100644 index 0000000..36c00d8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPercentageFacilityMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacPercentageFacility; +import org.dromara.facility.domain.vo.percentagefacility.FacPercentageFacilityVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-百分比设施Mapper接口 + * + * @author lilemy + * @date 2025-05-26 + */ +public interface FacPercentageFacilityMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelColumnMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelColumnMapper.java new file mode 100644 index 0000000..cd828a4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelColumnMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacPhotovoltaicPanelColumn; +import org.dromara.facility.domain.vo.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-光伏板立柱Mapper接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface FacPhotovoltaicPanelColumnMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelMapper.java new file mode 100644 index 0000000..6429d40 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacPhotovoltaicPanel; +import org.dromara.facility.domain.vo.photovoltaicpanel.FacPhotovoltaicPanelVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-光伏板Mapper接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface FacPhotovoltaicPanelMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelPointMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelPointMapper.java new file mode 100644 index 0000000..31904ef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelPointMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacPhotovoltaicPanelPoint; +import org.dromara.facility.domain.vo.photovoltaicpanelpoint.FacPhotovoltaicPanelPointVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-光伏板桩点Mapper接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface FacPhotovoltaicPanelPointMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelSupportMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelSupportMapper.java new file mode 100644 index 0000000..dacacf9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/mapper/FacPhotovoltaicPanelSupportMapper.java @@ -0,0 +1,15 @@ +package org.dromara.facility.mapper; + +import org.dromara.facility.domain.FacPhotovoltaicPanelSupport; +import org.dromara.facility.domain.vo.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设施-光伏板支架Mapper接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface FacPhotovoltaicPanelSupportMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacBoxTransformerService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacBoxTransformerService.java new file mode 100644 index 0000000..9422df1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacBoxTransformerService.java @@ -0,0 +1,108 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacBoxTransformer; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerCreateReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerQueryReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerUpdateReq; +import org.dromara.facility.domain.vo.boxtransformer.FacBoxTransformerVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-箱变Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacBoxTransformerService extends IService { + + /** + * 查询设施-箱变 + * + * @param id 主键 + * @return 设施-箱变 + */ + FacBoxTransformerVo queryById(Long id); + + /** + * 分页查询设施-箱变列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-箱变分页列表 + */ + TableDataInfo queryPageList(FacBoxTransformerQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-箱变列表 + * + * @param req 查询条件 + * @return 设施-箱变列表 + */ + List queryList(FacBoxTransformerQueryReq req); + + /** + * 新增设施-箱变 + * + * @param req 设施-箱变 + * @return 新增箱变id + */ + Long insertByBo(FacBoxTransformerCreateReq req); + + /** + * 新增设施-箱变 + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + Boolean insertByGeoJson(FacBoxTransformerCreateByGeoJsonReq geoJson); + + /** + * 修改设施-箱变 + * + * @param req 设施-箱变 + * @return 是否修改成功 + */ + Boolean updateByBo(FacBoxTransformerUpdateReq req); + + /** + * 校验并批量删除设施-箱变信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-箱变视图对象 + * + * @param boxTransformer 设施-箱变对象 + * @return 设施-箱变视图对象 + */ + FacBoxTransformerVo getVo(FacBoxTransformer boxTransformer); + + /** + * 获取设施-箱变查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacBoxTransformerQueryReq req); + + /** + * 获取设施-箱变分页对象视图 + * + * @param boxTransformerPage 设施-箱变分页对象 + * @return 设施-箱变分页对象视图 + */ + Page getVoPage(Page boxTransformerPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacInverterService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacInverterService.java new file mode 100644 index 0000000..b9eeb49 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacInverterService.java @@ -0,0 +1,108 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacInverter; +import org.dromara.facility.domain.dto.inverter.FacInverterCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.inverter.FacInverterCreateReq; +import org.dromara.facility.domain.dto.inverter.FacInverterQueryReq; +import org.dromara.facility.domain.dto.inverter.FacInverterUpdateReq; +import org.dromara.facility.domain.vo.inverter.FacInverterVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-逆变器Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacInverterService extends IService { + + /** + * 查询设施-逆变器 + * + * @param id 主键 + * @return 设施-逆变器 + */ + FacInverterVo queryById(Long id); + + /** + * 分页查询设施-逆变器列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-逆变器分页列表 + */ + TableDataInfo queryPageList(FacInverterQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-逆变器列表 + * + * @param req 查询条件 + * @return 设施-逆变器列表 + */ + List queryList(FacInverterQueryReq req); + + /** + * 新增设施-逆变器 + * + * @param req 设施-逆变器 + * @return 新增逆变器id + */ + Long insertByBo(FacInverterCreateReq req); + + /** + * 新增设施-逆变器 + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + Boolean insertByGeoJson(FacInverterCreateByGeoJsonReq geoJson); + + /** + * 修改设施-逆变器 + * + * @param req 设施-逆变器 + * @return 是否修改成功 + */ + Boolean updateByBo(FacInverterUpdateReq req); + + /** + * 校验并批量删除设施-逆变器信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-逆变器视图对象 + * + * @param inverter 设施-逆变器对象 + * @return 设施-逆变器视图对象 + */ + FacInverterVo getVo(FacInverter inverter); + + /** + * 获取设施-逆变器查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacInverterQueryReq req); + + /** + * 获取设施-逆变器分页对象视图 + * + * @param inverterPage 设施-逆变器分页对象 + * @return 设施-逆变器分页对象视图 + */ + Page getVoPage(Page inverterPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacMatrixService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacMatrixService.java new file mode 100644 index 0000000..8c203db --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacMatrixService.java @@ -0,0 +1,141 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.domain.dto.matrix.*; +import org.dromara.facility.domain.vo.matrix.FacFacilityPositionGisVo; +import org.dromara.facility.domain.vo.matrix.FacMatrixDetailGisVo; +import org.dromara.facility.domain.vo.matrix.FacMatrixVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-方阵Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacMatrixService extends IService { + + /** + * 查询设施-方阵 + * + * @param id 主键 + * @return 设施-方阵 + */ + FacMatrixVo queryById(Long id); + + /** + * 分页查询设施-方阵列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-方阵分页列表 + */ + TableDataInfo queryPageList(FacMatrixQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-方阵列表 + * + * @param req 查询条件 + * @return 设施-方阵列表 + */ + List queryList(FacMatrixQueryReq req); + + /** + * 获取大屏方阵详情信息 + * + * @param req 获取大屏方阵详情信息参数 + * @return 大屏方阵详情信息 + */ + FacMatrixDetailGisVo getMatrixDetailGis(FacMatrixDetailGisReq req); + + /** + * 新增设施-方阵 + * + * @param req 设施-方阵 + * @return 新增方阵id + */ + Long insertByBo(FacMatrixCreateReq req); + + /** + * 新增设施-方阵 + * + * @param geoJson GeoJson格式 + * @return 新增方阵id + */ + Boolean insertByGeoJson(FacMatrixCreateByGeoJsonReq geoJson); + + /** + * 修改设施-方阵 + * + * @param req 设施-方阵 + * @return 是否修改成功 + */ + Boolean updateByBo(FacMatrixUpdateReq req); + + /** + * 校验并批量删除设施-方阵信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-方阵视图对象 + * + * @param matrix 设施-方阵对象 + * @return 设施-方阵视图对象 + */ + FacMatrixVo getVo(FacMatrix matrix); + + /** + * 获取设施-方阵查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacMatrixQueryReq req); + + /** + * 获取设施-方阵分页对象视图 + * + * @param matrixPage 设施-方阵分页对象 + * @return 设施-方阵分页对象视图 + */ + Page getVoPage(Page matrixPage); + + /** + * 根据坐标获取符合的方阵 + * + * @param matrixList 方阵集合 + * @param coordinates 坐标 + * @return 符合的方阵 + */ + FacMatrix getMatrixIdByCoordinates(List matrixList, List coordinates); + + /** + * 根据二维坐标获取符合的方阵 + * + * @param matrixList 方阵集合 + * @param coordinates 坐标 + * @return 符合的方阵 + */ + FacMatrix getMatrixIdBy2Coordinates(List matrixList, List> coordinates); + + /** + * 获取设施-方阵位置信息 + * + * @param req 主键 + * @return 设施-方阵位置信息 + */ + List getPositionGis(FacFacilityPositionGisReq req); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPercentageFacilityService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPercentageFacilityService.java new file mode 100644 index 0000000..99622d4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPercentageFacilityService.java @@ -0,0 +1,81 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacPercentageFacility; +import org.dromara.facility.domain.dto.percentagefacility.FacPercentageFacilityQueryReq; +import org.dromara.facility.domain.vo.percentagefacility.FacPercentageFacilityVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-百分比设施Service接口 + * + * @author lilemy + * @date 2025-05-26 + */ +public interface IFacPercentageFacilityService extends IService { + + /** + * 查询设施-百分比设施 + * + * @param id 主键 + * @return 设施-百分比设施 + */ + FacPercentageFacilityVo queryById(Long id); + + /** + * 分页查询设施-百分比设施列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-百分比设施分页列表 + */ + TableDataInfo queryPageList(FacPercentageFacilityQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-百分比设施列表 + * + * @param req 查询条件 + * @return 设施-百分比设施列表 + */ + List queryList(FacPercentageFacilityQueryReq req); + + /** + * 校验并批量删除设施-百分比设施信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-百分比设施视图对象 + * + * @param percentageFacility 设施-百分比设施对象 + * @return 设施-百分比设施视图对象 + */ + FacPercentageFacilityVo getVo(FacPercentageFacility percentageFacility); + + /** + * 获取设施-百分比设施查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacPercentageFacilityQueryReq req); + + /** + * 获取设施-百分比设施分页对象视图 + * + * @param percentageFacilityPage 设施-百分比设施分页对象 + * @return 设施-百分比设施分页对象视图 + */ + Page getVoPage(Page percentageFacilityPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelColumnService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelColumnService.java new file mode 100644 index 0000000..aa1c7ba --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelColumnService.java @@ -0,0 +1,99 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacPhotovoltaicPanelColumn; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-光伏板立柱Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacPhotovoltaicPanelColumnService extends IService { + + /** + * 查询设施-光伏板立柱 + * + * @param id 主键 + * @return 设施-光伏板立柱 + */ + FacPhotovoltaicPanelColumnVo queryById(Long id); + + /** + * 分页查询设施-光伏板立柱列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板立柱分页列表 + */ + TableDataInfo queryPageList(FacPhotovoltaicPanelColumnQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-光伏板立柱列表 + * + * @param req 查询条件 + * @return 设施-光伏板立柱列表 + */ + List queryList(FacPhotovoltaicPanelColumnQueryReq req); + + /** + * 新增设施-光伏板立柱 + * + * @param req 设施-光伏板立柱 + * @return 新增光伏板立柱id + */ + Long insertByBo(FacPhotovoltaicPanelColumnCreateReq req); + + /** + * 修改设施-光伏板立柱 + * + * @param req 设施-光伏板立柱 + * @return 是否修改成功 + */ + Boolean updateByBo(FacPhotovoltaicPanelColumnUpdateReq req); + + /** + * 校验并批量删除设施-光伏板立柱信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-光伏板立柱视图对象 + * + * @param photovoltaicPanelColumn 设施-光伏板立柱对象 + * @return 设施-光伏板立柱视图对象 + */ + FacPhotovoltaicPanelColumnVo getVo(FacPhotovoltaicPanelColumn photovoltaicPanelColumn); + + /** + * 获取设施-光伏板立柱查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelColumnQueryReq req); + + /** + * 获取设施-光伏板立柱分页对象视图 + * + * @param photovoltaicPanelColumnPage 设施-光伏板立柱分页对象 + * @return 设施-光伏板立柱分页对象视图 + */ + Page getVoPage(Page photovoltaicPanelColumnPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelPartsService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelPartsService.java new file mode 100644 index 0000000..503aa6a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelPartsService.java @@ -0,0 +1,89 @@ +package org.dromara.facility.service; + +import org.dromara.facility.domain.FacPhotovoltaicPanelColumn; +import org.dromara.facility.domain.FacPhotovoltaicPanelPoint; +import org.dromara.facility.domain.FacPhotovoltaicPanelSupport; +import org.dromara.facility.domain.dto.photovoltaicpanelparts.FacPhotovoltaicPanelPartsCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.photovoltaicpanelparts.FacPhotovoltaicPanelPartsCreateReq; + +import java.util.Collection; +import java.util.Date; +import java.util.List; + +/** + * 设施-光伏板(桩点、立柱、支架)Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacPhotovoltaicPanelPartsService { + + /** + * 批量新增设施-光伏板(桩点、立柱、支架) + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + Boolean insertPartsByGeoJson(FacPhotovoltaicPanelPartsCreateByGeoJsonReq geoJson); + + /** + * 批量新增设施-光伏板(桩点、立柱、支架)内部方法 + * + * @param pointList 桩点列表 + * @param columnList 立柱列表 + * @param supportList 支架列表 + */ + void batchInsertPartsInner(List pointList, + List columnList, + List supportList); + + /** + * 批量删除设施-光伏板(桩点、立柱、支架)内部方法 + * + * @param pointList 桩点列表 + * @param columnList 立柱列表 + * @param supportList 支架列表 + */ + void batchDeletePartsInner(List pointList, + List columnList, + List supportList); + + /** + * 批量新增设施-光伏板(桩点、立柱、支架) + * + * @param req 设施-光伏板(桩点、立柱、支架) + * @return 是否新增成功 + */ + Boolean insertPartsByBatch(FacPhotovoltaicPanelPartsCreateReq req); + + /** + * 根据方阵主键判断是否存在光伏板点 + * + * @param projectId 项目id + * @param matrixIds 方阵Id列表 + * @return 是否存在 + */ + Boolean validPartsExistByMatrix(Long projectId, Collection matrixIds); + + /** + * 根据光伏板名称判断是否存在光伏板点 + * + * @param projectId 项目id + * @param photovoltaicPanelNames 光伏板名称列表 + * @return 是否存在 + */ + Boolean validPartsExistByPhotovoltaicPanel(Long projectId, Collection photovoltaicPanelNames); + + /** + * 更新光伏板点完成状态 + * + * @param workType 类型 + * @param finishDate 完成时间 + * @param projectId 项目id + * @param matrixId 方阵id + * @param photovoltaicPanelNameList 光伏板名称列表 + * @return 是否更新成功 + */ + Boolean updatePartsFinishStatus(String workType, Date finishDate, Long projectId, Long matrixId, List photovoltaicPanelNameList); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelPointService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelPointService.java new file mode 100644 index 0000000..bc88aa7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelPointService.java @@ -0,0 +1,99 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacPhotovoltaicPanelPoint; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelpoint.FacPhotovoltaicPanelPointVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-光伏板桩点Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacPhotovoltaicPanelPointService extends IService { + + /** + * 查询设施-光伏板桩点 + * + * @param id 主键 + * @return 设施-光伏板桩点 + */ + FacPhotovoltaicPanelPointVo queryById(Long id); + + /** + * 分页查询设施-光伏板桩点列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板桩点分页列表 + */ + TableDataInfo queryPageList(FacPhotovoltaicPanelPointQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-光伏板桩点列表 + * + * @param req 查询条件 + * @return 设施-光伏板桩点列表 + */ + List queryList(FacPhotovoltaicPanelPointQueryReq req); + + /** + * 新增设施-光伏板桩点 + * + * @param req 设施-光伏板桩点 + * @return 新增光伏板桩点id + */ + Long insertByBo(FacPhotovoltaicPanelPointCreateReq req); + + /** + * 修改设施-光伏板桩点 + * + * @param req 设施-光伏板桩点 + * @return 是否修改成功 + */ + Boolean updateByBo(FacPhotovoltaicPanelPointUpdateReq req); + + /** + * 校验并批量删除设施-光伏板桩点信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-光伏板桩点视图对象 + * + * @param photovoltaicPanelPoint 设施-光伏板桩点对象 + * @return 设施-光伏板桩点视图对象 + */ + FacPhotovoltaicPanelPointVo getVo(FacPhotovoltaicPanelPoint photovoltaicPanelPoint); + + /** + * 获取设施-光伏板桩点查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelPointQueryReq req); + + /** + * 获取设施-光伏板桩点分页对象视图 + * + * @param photovoltaicPanelPointPage 设施-光伏板桩点分页对象 + * @return 设施-光伏板桩点分页对象视图 + */ + Page getVoPage(Page photovoltaicPanelPointPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelService.java new file mode 100644 index 0000000..b94cce8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelService.java @@ -0,0 +1,122 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacPhotovoltaicPanel; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanel.FacPhotovoltaicPanelVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-光伏板Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacPhotovoltaicPanelService extends IService { + + /** + * 查询设施-光伏板 + * + * @param id 主键 + * @return 设施-光伏板 + */ + FacPhotovoltaicPanelVo queryById(Long id); + + /** + * 分页查询设施-光伏板列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板分页列表 + */ + TableDataInfo queryPageList(FacPhotovoltaicPanelQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-光伏板列表 + * + * @param req 查询条件 + * @return 设施-光伏板列表 + */ + List queryList(FacPhotovoltaicPanelQueryReq req); + + /** + * 新增设施-光伏板 + * + * @param req 设施-光伏板 + * @return 新增光伏板id + */ + Long insertByBo(FacPhotovoltaicPanelCreateReq req); + + /** + * 新增光伏板 + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + Boolean insertByGeoJson(FacPhotovoltaicPanelCreateByGeoJsonReq geoJson); + + /** + * 批量新增光伏板 + * + * @param photovoltaicPanelList 光伏板列表 + */ + void insertBatchInner(List photovoltaicPanelList); + + /** + * 批量删除光伏板 + * + * @param photovoltaicPanelList 光伏板列表 + */ + void deleteBatchInner(List photovoltaicPanelList); + + /** + * 修改设施-光伏板 + * + * @param req 设施-光伏板 + * @return 是否修改成功 + */ + Boolean updateByBo(FacPhotovoltaicPanelUpdateReq req); + + /** + * 校验并批量删除设施-光伏板信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-光伏板视图对象 + * + * @param photovoltaicPanel 设施-光伏板对象 + * @return 设施-光伏板视图对象 + */ + FacPhotovoltaicPanelVo getVo(FacPhotovoltaicPanel photovoltaicPanel); + + /** + * 获取设施-光伏板查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelQueryReq req); + + /** + * 获取设施-光伏板分页对象视图 + * + * @param photovoltaicPanelPage 设施-光伏板分页对象 + * @return 设施-光伏板分页对象视图 + */ + Page getVoPage(Page photovoltaicPanelPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelSupportService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelSupportService.java new file mode 100644 index 0000000..11dabd9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/IFacPhotovoltaicPanelSupportService.java @@ -0,0 +1,99 @@ +package org.dromara.facility.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacPhotovoltaicPanelSupport; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportVo; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-光伏板支架Service接口 + * + * @author lilemy + * @date 2025-04-21 + */ +public interface IFacPhotovoltaicPanelSupportService extends IService { + + /** + * 查询设施-光伏板支架 + * + * @param id 主键 + * @return 设施-光伏板支架 + */ + FacPhotovoltaicPanelSupportVo queryById(Long id); + + /** + * 分页查询设施-光伏板支架列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板支架分页列表 + */ + TableDataInfo queryPageList(FacPhotovoltaicPanelSupportQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的设施-光伏板支架列表 + * + * @param req 查询条件 + * @return 设施-光伏板支架列表 + */ + List queryList(FacPhotovoltaicPanelSupportQueryReq req); + + /** + * 新增设施-光伏板支架 + * + * @param req 设施-光伏板支架 + * @return 新增光伏板支架id + */ + Long insertByBo(FacPhotovoltaicPanelSupportCreateReq req); + + /** + * 修改设施-光伏板支架 + * + * @param req 设施-光伏板支架 + * @return 是否修改成功 + */ + Boolean updateByBo(FacPhotovoltaicPanelSupportUpdateReq req); + + /** + * 校验并批量删除设施-光伏板支架信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取设施-光伏板支架视图对象 + * + * @param photovoltaicPanelSupport 设施-光伏板支架对象 + * @return 设施-光伏板支架视图对象 + */ + FacPhotovoltaicPanelSupportVo getVo(FacPhotovoltaicPanelSupport photovoltaicPanelSupport); + + /** + * 获取设施-光伏板支架查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelSupportQueryReq req); + + /** + * 获取设施-光伏板支架分页对象视图 + * + * @param photovoltaicPanelSupportPage 设施-光伏板支架分页对象 + * @return 设施-光伏板支架分页对象视图 + */ + Page getVoPage(Page photovoltaicPanelSupportPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacBoxTransformerServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacBoxTransformerServiceImpl.java new file mode 100644 index 0000000..5da423e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacBoxTransformerServiceImpl.java @@ -0,0 +1,413 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.domain.FacBoxTransformer; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerCreateReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerQueryReq; +import org.dromara.facility.domain.dto.boxtransformer.FacBoxTransformerUpdateReq; +import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint; +import org.dromara.facility.domain.dto.geojson.FacGeometryByPoint; +import org.dromara.facility.domain.vo.boxtransformer.FacBoxTransformerVo; +import org.dromara.facility.mapper.FacBoxTransformerMapper; +import org.dromara.facility.service.IFacBoxTransformerService; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.progress.constant.PgsProgressCategoryConstant; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.common.utils.JSTUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 设施-箱变Service业务层处理 + * + * @author lilemy + * @date 2025-04-21 + */ +@Service +public class FacBoxTransformerServiceImpl extends ServiceImpl + implements IFacBoxTransformerService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IFacMatrixService matrixService; + + @Resource + private IPgsProgressCategoryService progressCategoryService; + + /** + * 查询设施-箱变 + * + * @param id 主键 + * @return 设施-箱变 + */ + @Override + public FacBoxTransformerVo queryById(Long id) { + FacBoxTransformer boxTransformer = this.getById(id); + if (boxTransformer == null) { + throw new ServiceException("查询箱变失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(boxTransformer); + } + + /** + * 分页查询设施-箱变列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-箱变分页列表 + */ + @Override + public TableDataInfo queryPageList(FacBoxTransformerQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-箱变列表 + * + * @param req 查询条件 + * @return 设施-箱变列表 + */ + @Override + public List queryList(FacBoxTransformerQueryReq req) { + List boxTransformerList = this.list(this.buildQueryWrapper(req)); + return boxTransformerList.stream().map(this::getVo).toList(); + } + + /** + * 新增设施-箱变 + * + * @param req 设施-箱变 + * @return 新增箱变id + */ + @Override + public Long insertByBo(FacBoxTransformerCreateReq req) { + // 将实体类和 DTO 进行转换 + FacBoxTransformer boxTransformer = new FacBoxTransformer(); + BeanUtils.copyProperties(req, boxTransformer); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + boxTransformer.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(boxTransformer, true); + // 判断是否存在同名箱变 + Long count = this.lambdaQuery() + .eq(FacBoxTransformer::getProjectId, boxTransformer.getProjectId()) + .eq(FacBoxTransformer::getName, boxTransformer.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名箱变", HttpStatus.CONFLICT); + } + // 操作数据库 + boolean save = this.save(boxTransformer); + if (!save) { + throw new ServiceException("新增箱变失败,数据库异常", HttpStatus.ERROR); + } + return boxTransformer.getId(); + } + + /** + * 新增设施-箱变 + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByGeoJson(FacBoxTransformerCreateByGeoJsonReq geoJson) { + Long projectId = geoJson.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 获取当前项目下方阵信息 + List matrixList = matrixService.lambdaQuery() + .select(FacMatrix::getId, FacMatrix::getPositions) + .eq(FacMatrix::getProjectId, projectId).list(); + if (CollUtil.isEmpty(matrixList)) { + throw new ServiceException("项目下无方阵数据,请先创建方阵信息后再添加箱变信息", HttpStatus.NOT_FOUND); + } + // 获取箱变信息 + List oldBoxTransformerList = this.lambdaQuery() + .eq(FacBoxTransformer::getProjectId, projectId).list(); + Map boxTransformerMap = oldBoxTransformerList.stream().collect(Collectors.toMap( + boxTransformer -> boxTransformer.getName() + "_" + boxTransformer.getProgressCategoryId(), + Function.identity(), + (boxTransformer1, boxTransformer2) -> boxTransformer1 + )); + // 获取箱变地理信息 + List locationGeoJsonList = geoJson.getLocationGeoJson(); + List locationGeoJson = new ArrayList<>(); + for (FacGeoJsonByPoint geoJsonByPoint : locationGeoJsonList) { + locationGeoJson.addAll(geoJsonByPoint.getFeatures()); + } + // 获取所有对应名称的点 + List nameGeoJsonList = geoJson.getNameGeoJson(); + List nameGeoJson = new ArrayList<>(); + for (FacGeoJsonByPoint geoJsonByPoint : nameGeoJsonList) { + nameGeoJson.addAll(geoJsonByPoint.getFeatures()); + } + // 获取进度类别信息 + List progressCategoryList = progressCategoryService.lambdaQuery() + .in(PgsProgressCategory::getWorkType, PgsProgressCategoryConstant.BOX_TRANSFORMER_PROGRESS_CATEGORY_WORK_TYPE).list(); + Map> progressCategoryMap = progressCategoryList + .stream().collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId)); + List boxTransformerList = new ArrayList<>(); + for (FacFeatureByPoint locationFeature : locationGeoJson) { + FacGeometryByPoint geometry = locationFeature.getGeometry(); + List coordinates = geometry.getCoordinates(); + // 判断箱变在哪个方阵里 + FacMatrix matrix = matrixService.getMatrixIdByCoordinates(matrixList, coordinates); + if (matrix == null) { + continue; + } + // 获取箱变名称 + String name = JSTUtil.findNearestText(coordinates, nameGeoJson); + if (name == null) { + continue; + } + // 根据进度类别创建 + Long matrixId = matrix.getId(); + List progressCategoryListByMatrix = progressCategoryMap.get(matrixId); + for (PgsProgressCategory progressCategory : progressCategoryListByMatrix) { + FacBoxTransformer boxTransformer = new FacBoxTransformer(); + boxTransformer.setMatrixId(matrix.getId()); + boxTransformer.setName(name); + boxTransformer.setProjectId(projectId); + boxTransformer.setPositions(JSONUtil.toJsonStr(coordinates)); + String mapKey = name + "_" + progressCategory.getId(); + // 如果有同名同类别箱变,则获取该箱变完成状态 + if (CollUtil.isNotEmpty(boxTransformerMap) && boxTransformerMap.containsKey(mapKey)) { + FacBoxTransformer oldBoxTransformer = boxTransformerMap.get(mapKey); + boxTransformer.setFinishType(oldBoxTransformer.getFinishType()); + boxTransformer.setFinishDate(oldBoxTransformer.getFinishDate()); + boxTransformer.setProgressCategoryId(oldBoxTransformer.getProgressCategoryId()); + boxTransformer.setProgressCategoryName(oldBoxTransformer.getProgressCategoryName()); + boxTransformer.setStatus(oldBoxTransformer.getStatus()); + } else { + boxTransformer.setProgressCategoryId(progressCategory.getId()); + boxTransformer.setProgressCategoryName(progressCategory.getName()); + } + boxTransformerList.add(boxTransformer); + } + } + // 删除旧数据 + if (CollUtil.isNotEmpty(oldBoxTransformerList)) { + boolean result = this.removeBatchByIds(oldBoxTransformerList); + if (!result) { + throw new ServiceException("删除箱变失败,数据库异常", HttpStatus.ERROR); + } + } + // 批量保存 + if (CollUtil.isNotEmpty(boxTransformerList)) { + boolean result = this.saveBatch(boxTransformerList); + if (!result) { + throw new ServiceException("新增箱变失败,数据库异常", HttpStatus.ERROR); + } + } + // 更新数量 + Map> countMap = boxTransformerList + .stream().collect(Collectors.groupingBy(FacBoxTransformer::getProgressCategoryId)); + for (PgsProgressCategory progressCategory : progressCategoryList) { + Long progressCategoryId = progressCategory.getId(); + int total = 0; + if (countMap.containsKey(progressCategoryId)) { + total = countMap.get(progressCategoryId).size(); + } + progressCategory.setTotal(BigDecimal.valueOf(total)); + } + boolean result = progressCategoryService.updateBatchById(progressCategoryList); + if (!result) { + throw new ServiceException("更新进度类别失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 修改设施-箱变 + * + * @param req 设施-箱变 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FacBoxTransformerUpdateReq req) { + // 将实体类和 DTO 进行转换 + FacBoxTransformer boxTransformer = new FacBoxTransformer(); + BeanUtils.copyProperties(req, boxTransformer); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + boxTransformer.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(boxTransformer, false); + // 判断是否存在 + FacBoxTransformer oldBoxTransformer = this.getById(boxTransformer.getId()); + if (oldBoxTransformer == null) { + throw new ServiceException("修改箱变失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断是否修改名称 + if (!oldBoxTransformer.getName().equals(boxTransformer.getName())) { + Long count = this.lambdaQuery() + .eq(FacBoxTransformer::getProjectId, boxTransformer.getProjectId()) + .eq(FacBoxTransformer::getName, boxTransformer.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名箱变", HttpStatus.CONFLICT); + } + } + // 操作数据库 + boolean update = this.updateById(boxTransformer); + if (!update) { + throw new ServiceException("修改箱变失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FacBoxTransformer entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long matrixId = entity.getMatrixId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (matrixId == null) { + throw new ServiceException("方阵id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (matrixId != null && matrixService.getById(matrixId) == null) { + throw new ServiceException("对应方阵不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设施-箱变信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List boxTransformerList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = boxTransformerList.stream().map(FacBoxTransformer::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-箱变视图对象 + * + * @param boxTransformer 设施-箱变对象 + * @return 设施-箱变视图对象 + */ + @Override + public FacBoxTransformerVo getVo(FacBoxTransformer boxTransformer) { + // 对象转封装类 + FacBoxTransformerVo boxTransformerVo = new FacBoxTransformerVo(); + if (boxTransformer == null) { + return boxTransformerVo; + } + BeanUtils.copyProperties(boxTransformer, boxTransformerVo); + // 将 JSON 字符串转化为 List + String positions = boxTransformer.getPositions(); + if (StringUtils.isNotBlank(positions)) { + List positionList = JSONUtil.toList(positions, String.class); + boxTransformerVo.setPositionList(positionList); + } + return boxTransformerVo; + } + + /** + * 获取设施-箱变查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacBoxTransformerQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + String name = req.getName(); + String status = req.getStatus(); + String finishType = req.getFinishType(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), FacBoxTransformer::getName, name); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacBoxTransformer::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), FacBoxTransformer::getMatrixId, matrixId); + lqw.eq(StringUtils.isNotBlank(status), FacBoxTransformer::getStatus, status); + lqw.eq(StringUtils.isNotBlank(finishType), FacBoxTransformer::getFinishType, finishType); + lqw.orderByAsc(FacBoxTransformer::getName); + return lqw; + } + + /** + * 获取设施-箱变分页对象视图 + * + * @param boxTransformerPage 设施-箱变分页对象 + * @return 设施-箱变分页对象视图 + */ + @Override + public Page getVoPage(Page boxTransformerPage) { + List boxTransformerList = boxTransformerPage.getRecords(); + Page boxTransformerVoPage = new Page<>( + boxTransformerPage.getCurrent(), + boxTransformerPage.getSize(), + boxTransformerPage.getTotal()); + if (CollUtil.isEmpty(boxTransformerList)) { + return boxTransformerVoPage; + } + List boxTransformerVoList = boxTransformerList.stream().map(this::getVo).toList(); + boxTransformerVoPage.setRecords(boxTransformerVoList); + return boxTransformerVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacInverterServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacInverterServiceImpl.java new file mode 100644 index 0000000..5c7f50e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacInverterServiceImpl.java @@ -0,0 +1,413 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.domain.FacInverter; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint; +import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint; +import org.dromara.facility.domain.dto.geojson.FacGeometryByPoint; +import org.dromara.facility.domain.dto.inverter.FacInverterCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.inverter.FacInverterCreateReq; +import org.dromara.facility.domain.dto.inverter.FacInverterQueryReq; +import org.dromara.facility.domain.dto.inverter.FacInverterUpdateReq; +import org.dromara.facility.domain.vo.inverter.FacInverterVo; +import org.dromara.facility.mapper.FacInverterMapper; +import org.dromara.facility.service.IFacInverterService; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.progress.constant.PgsProgressCategoryConstant; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.common.utils.JSTUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 设施-逆变器Service业务层处理 + * + * @author lilemy + * @date 2025-04-21 + */ +@Service +public class FacInverterServiceImpl extends ServiceImpl + implements IFacInverterService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IFacMatrixService matrixService; + + @Resource + private IPgsProgressCategoryService progressCategoryService; + + /** + * 查询设施-逆变器 + * + * @param id 主键 + * @return 设施-逆变器 + */ + @Override + public FacInverterVo queryById(Long id) { + FacInverter inverter = this.getById(id); + if (inverter == null) { + throw new ServiceException("查询逆变器失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(inverter); + } + + /** + * 分页查询设施-逆变器列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-逆变器分页列表 + */ + @Override + public TableDataInfo queryPageList(FacInverterQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-逆变器列表 + * + * @param req 查询条件 + * @return 设施-逆变器列表 + */ + @Override + public List queryList(FacInverterQueryReq req) { + List inverterList = this.list(this.buildQueryWrapper(req)); + return inverterList.stream().map(this::getVo).toList(); + } + + /** + * 新增设施-逆变器 + * + * @param req 设施-逆变器 + * @return 新增逆变器id + */ + @Override + public Long insertByBo(FacInverterCreateReq req) { + // 将实体类和 DTO 进行转换 + FacInverter inverter = new FacInverter(); + BeanUtils.copyProperties(req, inverter); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + inverter.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(inverter, true); + // 判断是否存在同名逆变器 + Long count = this.lambdaQuery() + .eq(FacInverter::getProjectId, inverter.getProjectId()) + .eq(FacInverter::getName, inverter.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名逆变器", HttpStatus.CONFLICT); + } + // 操作数据库 + boolean save = this.save(inverter); + if (!save) { + throw new ServiceException("新增逆变器失败,数据库异常", HttpStatus.ERROR); + } + return inverter.getId(); + } + + /** + * 新增设施-逆变器 + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByGeoJson(FacInverterCreateByGeoJsonReq geoJson) { + Long projectId = geoJson.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 获取当前项目下方阵信息 + List matrixList = matrixService.lambdaQuery() + .select(FacMatrix::getId, FacMatrix::getPositions) + .eq(FacMatrix::getProjectId, projectId).list(); + if (CollUtil.isEmpty(matrixList)) { + throw new ServiceException("项目下无方阵数据,请先创建方阵信息后再添加逆变器信息", HttpStatus.NOT_FOUND); + } + // 获取箱变信息 + List oldInverterList = this.lambdaQuery() + .eq(FacInverter::getProjectId, projectId).list(); + Map inverterMap = oldInverterList.stream().collect(Collectors.toMap( + inverter -> inverter.getName() + "_" + inverter.getProgressCategoryId(), + Function.identity(), + (inverter1, inverter2) -> inverter1 + )); + // 获取所有逆变器对应名称的点 + List locationGeoJsonList = geoJson.getLocationGeoJson(); + List locationGeoJson = new ArrayList<>(); + for (FacGeoJsonByPoint geoJsonByPoint : locationGeoJsonList) { + locationGeoJson.addAll(geoJsonByPoint.getFeatures()); + } + // 获取所有对应名称的点 + List nameGeoJsonList = geoJson.getNameGeoJson(); + List nameGeoJson = new ArrayList<>(); + for (FacGeoJsonByPoint geoJsonByPoint : nameGeoJsonList) { + nameGeoJson.addAll(geoJsonByPoint.getFeatures()); + } + // 获取进度类别信息 + List progressCategoryList = progressCategoryService.lambdaQuery() + .in(PgsProgressCategory::getWorkType, PgsProgressCategoryConstant.INVERTER_PROGRESS_CATEGORY_WORK_TYPE).list(); + Map> progressCategoryMap = progressCategoryList.stream() + .collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId)); + List inverterList = new ArrayList<>(); + for (FacFeatureByPoint locationFeature : locationGeoJson) { + FacGeometryByPoint geometry = locationFeature.getGeometry(); + List coordinates = geometry.getCoordinates(); + // 判断箱变在哪个方阵里 + FacMatrix matrix = matrixService.getMatrixIdByCoordinates(matrixList, coordinates); + if (matrix == null) { + continue; + } + // 获取逆变器名称 + String name = JSTUtil.findNearestText(coordinates, nameGeoJson); + if (name == null) { + continue; + } + // 根据进度类别创建 + Long matrixId = matrix.getId(); + List progressCategoryListByMatrix = progressCategoryMap.get(matrixId); + for (PgsProgressCategory progressCategory : progressCategoryListByMatrix) { + FacInverter inverter = new FacInverter(); + inverter.setMatrixId(matrix.getId()); + inverter.setName(name); + inverter.setProjectId(projectId); + inverter.setPositions(JSONUtil.toJsonStr(coordinates)); + String mapKey = name + "_" + progressCategory.getId(); + // 如果有同名同类别箱变,则获取该箱变完成状态 + if (CollUtil.isNotEmpty(inverterMap) && inverterMap.containsKey(mapKey)) { + FacInverter oldInverter = inverterMap.get(mapKey); + inverter.setFinishType(oldInverter.getFinishType()); + inverter.setFinishDate(oldInverter.getFinishDate()); + inverter.setProgressCategoryId(oldInverter.getProgressCategoryId()); + inverter.setProgressCategoryName(oldInverter.getProgressCategoryName()); + inverter.setStatus(oldInverter.getStatus()); + } else { + inverter.setProgressCategoryId(progressCategory.getId()); + inverter.setProgressCategoryName(progressCategory.getName()); + } + inverterList.add(inverter); + } + } + // 删除旧数据 + if (CollUtil.isNotEmpty(oldInverterList)) { + boolean result = this.removeBatchByIds(oldInverterList); + if (!result) { + throw new ServiceException("删除逆变器失败,数据库异常", HttpStatus.ERROR); + } + } + // 批量保存 + if (CollUtil.isNotEmpty(inverterList)) { + boolean result = this.saveBatch(inverterList); + if (!result) { + throw new ServiceException("新增逆变器失败,数据库异常", HttpStatus.ERROR); + } + } + // 更新数量 + Map> countMap = inverterList + .stream().collect(Collectors.groupingBy(FacInverter::getProgressCategoryId)); + for (PgsProgressCategory progressCategory : progressCategoryList) { + Long progressCategoryId = progressCategory.getId(); + int total = 0; + if (countMap.containsKey(progressCategoryId)) { + total = countMap.get(progressCategoryId).size(); + } + progressCategory.setTotal(BigDecimal.valueOf(total)); + } + boolean result = progressCategoryService.updateBatchById(progressCategoryList); + if (!result) { + throw new ServiceException("更新进度类别失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 修改设施-逆变器 + * + * @param req 设施-逆变器 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FacInverterUpdateReq req) { + // 将实体类和 DTO 进行转换 + FacInverter inverter = new FacInverter(); + BeanUtils.copyProperties(req, inverter); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + inverter.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(inverter, false); + // 判断是否存在 + FacInverter oldInverter = this.getById(inverter.getId()); + if (oldInverter == null) { + throw new ServiceException("修改逆变器失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断是否修改名称 + if (!oldInverter.getName().equals(inverter.getName())) { + Long count = this.lambdaQuery() + .eq(FacInverter::getProjectId, inverter.getProjectId()) + .eq(FacInverter::getName, inverter.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名逆变器", HttpStatus.CONFLICT); + } + } + // 操作数据库 + boolean update = this.updateById(inverter); + if (!update) { + throw new ServiceException("修改逆变器失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FacInverter entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long matrixId = entity.getMatrixId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (matrixId == null) { + throw new ServiceException("方阵id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (matrixId != null && matrixService.getById(matrixId) == null) { + throw new ServiceException("对应方阵不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设施-逆变器信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List inverterList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = inverterList.stream().map(FacInverter::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-逆变器视图对象 + * + * @param inverter 设施-逆变器对象 + * @return 设施-逆变器视图对象 + */ + @Override + public FacInverterVo getVo(FacInverter inverter) { + // 对象转封装类 + FacInverterVo inverterVo = new FacInverterVo(); + if (inverter == null) { + return inverterVo; + } + BeanUtils.copyProperties(inverter, inverterVo); + // 将 JSON 字符串转化为 List + String positions = inverter.getPositions(); + if (StringUtils.isNotBlank(positions)) { + List positionList = JSONUtil.toList(positions, String.class); + inverterVo.setPositionList(positionList); + } + return inverterVo; + } + + /** + * 获取设施-逆变器查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacInverterQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + String name = req.getName(); + String status = req.getStatus(); + String finishType = req.getFinishType(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), FacInverter::getName, name); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacInverter::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), FacInverter::getMatrixId, matrixId); + lqw.eq(StringUtils.isNotBlank(status), FacInverter::getStatus, status); + lqw.eq(StringUtils.isNotBlank(finishType), FacInverter::getFinishType, finishType); + lqw.orderByAsc(FacInverter::getName); + return lqw; + } + + /** + * 获取设施-逆变器分页对象视图 + * + * @param inverterPage 设施-逆变器分页对象 + * @return 设施-逆变器分页对象视图 + */ + @Override + public Page getVoPage(Page inverterPage) { + List inverterList = inverterPage.getRecords(); + Page inverterVoPage = new Page<>( + inverterPage.getCurrent(), + inverterPage.getSize(), + inverterPage.getTotal()); + if (CollUtil.isEmpty(inverterList)) { + return inverterVoPage; + } + List inverterVoList = inverterList.stream().map(this::getVo).toList(); + inverterVoPage.setRecords(inverterVoList); + return inverterVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacMatrixServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacMatrixServiceImpl.java new file mode 100644 index 0000000..82a506f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacMatrixServiceImpl.java @@ -0,0 +1,722 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.constant.FacRedisKeyConstant; +import org.dromara.facility.domain.*; +import org.dromara.facility.domain.dto.geojson.*; +import org.dromara.facility.domain.dto.matrix.*; +import org.dromara.facility.domain.enums.FacCategoryEnum; +import org.dromara.facility.domain.enums.FacFinishStatusEnum; +import org.dromara.facility.domain.vo.matrix.FacFacilityPositionGisVo; +import org.dromara.facility.domain.vo.matrix.FacMatrixDetailGisVo; +import org.dromara.facility.domain.vo.matrix.FacMatrixVo; +import org.dromara.facility.mapper.FacMatrixMapper; +import org.dromara.facility.service.*; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.dromara.common.utils.JSTUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * 设施-方阵Service业务层处理 + * + * @author lilemy + * @date 2025-04-21 + */ +@Service +public class FacMatrixServiceImpl extends ServiceImpl + implements IFacMatrixService { + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private IFacPhotovoltaicPanelService photovoltaicPanelService; + + @Lazy + @Resource + private IFacPhotovoltaicPanelPartsService photovoltaicPanelPartsService; + + @Lazy + @Resource + private IFacPhotovoltaicPanelPointService photovoltaicPanelPointService; + + @Lazy + @Resource + private IFacPhotovoltaicPanelColumnService photovoltaicPanelColumnService; + + @Lazy + @Resource + private IFacPhotovoltaicPanelSupportService photovoltaicPanelSupportService; + + @Lazy + @Resource + private IFacBoxTransformerService boxTransformerService; + + @Lazy + @Resource + private IFacInverterService inverterService; + + @Lazy + @Resource + private IPgsProgressCategoryService progressCategoryService; + + @Resource + private RedisTemplate redisTemplate; + + /** + * 查询设施-方阵 + * + * @param id 主键 + * @return 设施-方阵 + */ + @Override + public FacMatrixVo queryById(Long id) { + FacMatrix matrix = this.getById(id); + if (matrix == null) { + throw new ServiceException("查询方阵失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(matrix); + } + + /** + * 分页查询设施-方阵列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-方阵分页列表 + */ + @Override + public TableDataInfo queryPageList(FacMatrixQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-方阵列表 + * + * @param req 查询条件 + * @return 设施-方阵列表 + */ + @Override + public List queryList(FacMatrixQueryReq req) { + List matrixList = this.list(this.buildQueryWrapper(req)); + return matrixList.stream().map(this::getVo).toList(); + } + + /** + * 获取大屏方阵详情信息 + * + * @param req 获取大屏方阵详情信息参数 + * @return 大屏方阵详情信息 + */ + @Override + public FacMatrixDetailGisVo getMatrixDetailGis(FacMatrixDetailGisReq req) { + Long projectId = req.getProjectId(); + if (projectId == null || projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + Long matrixId = req.getMatrixId(); + FacMatrixDetailGisVo matrixDetailGisVo = new FacMatrixDetailGisVo(); + // 获取箱变数量 + List boxTransformerList = boxTransformerService.lambdaQuery() + .select(FacBoxTransformer::getId, FacBoxTransformer::getStatus) + .eq(FacBoxTransformer::getProjectId, projectId) + .eq(ObjectUtils.isNotEmpty(matrixId), FacBoxTransformer::getMatrixId, matrixId) + .list(); + if (CollUtil.isNotEmpty(boxTransformerList)) { + matrixDetailGisVo.setBoxTransformerCount((long) boxTransformerList.size()); + matrixDetailGisVo.setBoxTransformerFinishCount(boxTransformerList.stream() + .filter(boxTransformer -> + FacFinishStatusEnum.FINISH.getValue().equals(boxTransformer.getStatus())).count()); + } + // 获取逆变器数量 + List inverterList = inverterService.lambdaQuery() + .select(FacInverter::getId, FacInverter::getStatus) + .eq(FacInverter::getProjectId, projectId) + .eq(ObjectUtils.isNotEmpty(matrixId), FacInverter::getMatrixId, matrixId) + .list(); + if (CollUtil.isNotEmpty(inverterList)) { + matrixDetailGisVo.setInverterCount((long) inverterList.size()); + matrixDetailGisVo.setInverterFinishCount(inverterList.stream() + .filter(inverter -> + FacFinishStatusEnum.FINISH.getValue().equals(inverter.getStatus())).count()); + } + // 获取光伏板数量 + List photovoltaicPanelList = photovoltaicPanelService.lambdaQuery() + .select(FacPhotovoltaicPanel::getId, FacPhotovoltaicPanel::getStatus) + .eq(FacPhotovoltaicPanel::getProjectId, projectId) + .eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanel::getMatrixId, matrixId) + .list(); + if (CollUtil.isNotEmpty(photovoltaicPanelList)) { + matrixDetailGisVo.setPhotovoltaicPanelCount((long) photovoltaicPanelList.size()); + matrixDetailGisVo.setPhotovoltaicPanelFinishCount(photovoltaicPanelList.stream() + .filter(photovoltaicPanel -> + FacFinishStatusEnum.FINISH.getValue().equals(photovoltaicPanel.getStatus())).count()); + } + // 获取光伏板点数量 + List photovoltaicPanelPointList = photovoltaicPanelPointService.lambdaQuery() + .select(FacPhotovoltaicPanelPoint::getId, FacPhotovoltaicPanelPoint::getStatus) + .eq(FacPhotovoltaicPanelPoint::getProjectId, projectId) + .eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanelPoint::getMatrixId, matrixId) + .list(); + if (CollUtil.isNotEmpty(photovoltaicPanelPointList)) { + matrixDetailGisVo.setPointCount((long) photovoltaicPanelPointList.size()); + matrixDetailGisVo.setPointFinishCount(photovoltaicPanelPointList.stream() + .filter(photovoltaicPanelPoint -> + FacFinishStatusEnum.FINISH.getValue().equals(photovoltaicPanelPoint.getStatus())).count()); + } + // 获取支架数量 + List photovoltaicPanelSupportList = photovoltaicPanelSupportService.lambdaQuery() + .select(FacPhotovoltaicPanelSupport::getId, FacPhotovoltaicPanelSupport::getStatus) + .eq(FacPhotovoltaicPanelSupport::getProjectId, projectId) + .eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanelSupport::getMatrixId, matrixId) + .list(); + if (CollUtil.isNotEmpty(photovoltaicPanelSupportList)) { + matrixDetailGisVo.setSupportCount((long) photovoltaicPanelSupportList.size()); + matrixDetailGisVo.setSupportFinishCount(photovoltaicPanelSupportList.stream() + .filter(photovoltaicPanelSupport -> + FacFinishStatusEnum.FINISH.getValue().equals(photovoltaicPanelSupport.getStatus())).count()); + } + // 获取立柱数量 + List photovoltaicPanelColumnList = photovoltaicPanelColumnService.lambdaQuery() + .select(FacPhotovoltaicPanelColumn::getId, FacPhotovoltaicPanelColumn::getStatus) + .eq(FacPhotovoltaicPanelColumn::getProjectId, projectId) + .eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanelColumn::getMatrixId, matrixId) + .list(); + if (CollUtil.isNotEmpty(photovoltaicPanelColumnList)) { + matrixDetailGisVo.setColumnCount((long) photovoltaicPanelColumnList.size()); + matrixDetailGisVo.setColumnFinishCount(photovoltaicPanelColumnList.stream() + .filter(photovoltaicPanelColumn -> + FacFinishStatusEnum.FINISH.getValue().equals(photovoltaicPanelColumn.getStatus())).count()); + } + return matrixDetailGisVo; + } + + /** + * 新增设施-方阵 + * + * @param req 设施-方阵 + * @return 新增方阵id + */ + @Override + public Long insertByBo(FacMatrixCreateReq req) { + // 将实体类和 DTO 进行转换 + FacMatrix matrix = new FacMatrix(); + BeanUtils.copyProperties(req, matrix); + // 将位置信息转换为 JSON 字符串 + List> positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + matrix.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(matrix, true); + // 判断是否存在同名方阵 + Long count = this.lambdaQuery() + .eq(FacMatrix::getProjectId, matrix.getProjectId()) + .eq(FacMatrix::getMatrixName, matrix.getMatrixName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名方阵", HttpStatus.CONFLICT); + } + // 操作数据库 + boolean save = this.save(matrix); + if (!save) { + throw new ServiceException("新增方阵失败,数据库异常", HttpStatus.ERROR); + } + return matrix.getId(); + } + + /** + * 新增设施-方阵 + * + * @param geoJson GeoJson格式 + * @return 新增方阵id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByGeoJson(FacMatrixCreateByGeoJsonReq geoJson) { + Long projectId = geoJson.getProjectId(); + // 判断 redis key 是否存在,存在则返回 + List operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId); + List list = redisTemplate.opsForValue().multiGet(operationRedisKey); + boolean hasValue = list != null && list.stream().anyMatch(Objects::nonNull); + if (hasValue) { + throw new ServiceException("项目下有设施数据正在处理中,请等待处理完毕后再操作", HttpStatus.BAD_REQUEST); + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 获取当前项目下方阵信息 + List oldMatrixList = this.lambdaQuery() + .select(FacMatrix::getId) + .eq(FacMatrix::getProjectId, projectId).list(); + List matrixList = new ArrayList<>(); + List locationGeoJsonList = geoJson.getLocationGeoJson(); + List locationFeatures = new ArrayList<>(); + for (FacGeoJson geoJsonByPoint : locationGeoJsonList) { + locationFeatures.addAll(geoJsonByPoint.getFeatures()); + } + // 获取所有对应名称的点 + List nameGeoJsonList = geoJson.getNameGeoJson(); + List nameFeatures = new ArrayList<>(); + for (FacGeoJsonByPoint geoJsonByPoint : nameGeoJsonList) { + nameFeatures.addAll(geoJsonByPoint.getFeatures()); + } + // 遍历位置信息 + for (FacFeature feature : locationFeatures) { + FacMatrix matrix = new FacMatrix(); + matrix.setProjectId(projectId); + FacGeometry geometry = feature.getGeometry(); + // 获取坐标信息 + List> coordinatesList = JSTUtil.getTwoDimensionalCoordinates(geometry); + // 获取方阵名称 + String nameStr = JSTUtil.findNearestPointText(coordinatesList, nameFeatures); + String name = nameStr.split(" ")[0]; + if (name == null) { + continue; + } + // 将位置信息转换为 JSON 字符串 + String positionStr = JSONUtil.toJsonStr(coordinatesList); + matrix.setPositions(positionStr); + matrix.setMatrixName(name); + matrixList.add(matrix); + } + // todo 关联数据处理 + if (CollUtil.isNotEmpty(matrixList)) { + boolean result = this.saveBatch(matrixList); + if (!result) { + throw new ServiceException("批量新增方阵失败,数据库异常", HttpStatus.ERROR); + } + Boolean save = progressCategoryService.insertByTemplate(projectId, matrixList, oldMatrixList); + if (!save) { + throw new ServiceException("批量新增方阵进度分类失败,数据库异常", HttpStatus.ERROR); + } + } + if (CollUtil.isNotEmpty(oldMatrixList)) { + List oldMatrixIds = oldMatrixList.stream().map(FacMatrix::getId).toList(); + boolean result = this.removeBatchByIds(oldMatrixIds); + if (!result) { + throw new ServiceException("删除老方阵失败,数据库异常", HttpStatus.ERROR); + } + } + return true; + } + + /** + * 修改设施-方阵 + * + * @param req 设施-方阵 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FacMatrixUpdateReq req) { + // 将实体类和 DTO 进行转换 + FacMatrix matrix = new FacMatrix(); + BeanUtils.copyProperties(req, matrix); + // 将位置信息转换为 JSON 字符串 + List> positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + matrix.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(matrix, false); + // 判断是否存在 + FacMatrix oldMatrix = this.getById(matrix.getId()); + if (oldMatrix == null) { + throw new ServiceException("修改方阵失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断是否修改名称 + if (!oldMatrix.getMatrixName().equals(matrix.getMatrixName())) { + Long count = this.lambdaQuery() + .eq(FacMatrix::getProjectId, matrix.getProjectId()) + .eq(FacMatrix::getMatrixName, matrix.getMatrixName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名方阵", HttpStatus.CONFLICT); + } + } + // 操作数据库 + boolean update = this.updateById(matrix); + if (!update) { + throw new ServiceException("修改方阵失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FacMatrix entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设施-方阵信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List matrixList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectIds = matrixList.stream().map(FacMatrix::getProjectId).distinct().toList(); + if (CollUtil.isNotEmpty(projectIds) && projectIds.size() > 1) { + throw new ServiceException("仅能删除单个项目下的方阵", HttpStatus.BAD_REQUEST); + } + Long projectId = projectIds.getFirst(); + projectService.validAuth(projectId, userId); + // 判断方阵下是否存在光伏板信息 + Long photovoltaicPanelCount = photovoltaicPanelService.lambdaQuery() + .eq(FacPhotovoltaicPanel::getProjectId, projectId) + .in(FacPhotovoltaicPanel::getMatrixId, ids).count(); + if (photovoltaicPanelCount > 0) { + throw new ServiceException("删除失败,方阵下存在光伏板信息", HttpStatus.CONFLICT); + } + // 判断方阵下是否存在箱变信息 + Long boxTransformerCount = boxTransformerService.lambdaQuery() + .eq(FacBoxTransformer::getProjectId, projectId) + .in(FacBoxTransformer::getMatrixId, ids).count(); + if (boxTransformerCount > 0) { + throw new ServiceException("删除失败,方阵下存在箱变信息", HttpStatus.CONFLICT); + } + // 判断方阵下是否存在逆变器信息 + Long inverterCount = inverterService.lambdaQuery() + .eq(FacInverter::getProjectId, projectId) + .in(FacInverter::getMatrixId, ids).count(); + if (inverterCount > 0) { + throw new ServiceException("删除失败,方阵下存在逆变器信息", HttpStatus.CONFLICT); + } + // 判断方阵下是否存在光伏板点信息 + Boolean result = photovoltaicPanelPartsService.validPartsExistByMatrix(projectId, ids); + if (result) { + throw new ServiceException("删除失败,方阵下存在光伏板点信息", HttpStatus.CONFLICT); + } + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-方阵视图对象 + * + * @param matrix 设施-方阵对象 + * @return 设施-方阵视图对象 + */ + @Override + public FacMatrixVo getVo(FacMatrix matrix) { + // 对象转封装类 + FacMatrixVo matrixVo = new FacMatrixVo(); + if (matrix == null) { + return matrixVo; + } + BeanUtils.copyProperties(matrix, matrixVo); + return matrixVo; + } + + /** + * 获取设施-方阵查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacMatrixQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String matrixName = req.getMatrixName(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(matrixName), FacMatrix::getMatrixName, matrixName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacMatrix::getProjectId, projectId); + // 排序 + lqw.orderByAsc(FacMatrix::getMatrixName); + return lqw; + } + + /** + * 获取设施-方阵分页对象视图 + * + * @param matrixPage 设施-方阵分页对象 + * @return 设施-方阵分页对象视图 + */ + @Override + public Page getVoPage(Page matrixPage) { + List matrixList = matrixPage.getRecords(); + Page matrixVoPage = new Page<>( + matrixPage.getCurrent(), + matrixPage.getSize(), + matrixPage.getTotal()); + if (CollUtil.isEmpty(matrixList)) { + return matrixVoPage; + } + List matrixVoList = matrixList.stream().map(this::getVo).toList(); + matrixVoPage.setRecords(matrixVoList); + return matrixVoPage; + } + + /** + * 根据坐标获取符合的方阵 + * + * @param matrixList 方阵集合 + * @param coordinates 坐标 + * @return 符合的方阵 + */ + @Override + public FacMatrix getMatrixIdByCoordinates(List matrixList, List coordinates) { + // 判断在哪个方阵里 + FacMatrix matchMatrix = null; + for (FacMatrix matrix : matrixList) { + String positions = matrix.getPositions(); + List> positionList = new ArrayList<>(); + List arr = JSONUtil.toList(positions, String.class); + for (String s : arr) { + positionList.add(JSONUtil.toList(s, Double.class)); + } + Boolean result = JSTUtil.pointIsWithInPlane(positionList, coordinates); + if (result) { + matchMatrix = matrix; + break; + } + } + return matchMatrix; + } + + /** + * 根据二维坐标获取符合的方阵 + * + * @param matrixList 方阵集合 + * @param coordinates 坐标 + * @return 符合的方阵 + */ + @Override + public FacMatrix getMatrixIdBy2Coordinates(List matrixList, List> coordinates) { + FacMatrix matchMatrix = null; + for (FacMatrix matrix : matrixList) { + String positions = matrix.getPositions(); + List> positionList = new ArrayList<>(); + List arr = JSONUtil.toList(positions, String.class); + for (String s : arr) { + positionList.add(JSONUtil.toList(s, Double.class)); + } + Boolean result = JSTUtil.planeIsWithInPlane(positionList, coordinates); + if (result) { + matchMatrix = matrix; + break; + } else { + Boolean areResult = JSTUtil.arePolygonsIntersecting(positionList, coordinates); + if (areResult) { + matchMatrix = matrix; + break; + } + } + } + return matchMatrix; + } + + /** + * 获取设施-方阵位置信息 + * + * @param req 主键 + * @return 设施-方阵位置信息 + */ + @Override + public List getPositionGis(FacFacilityPositionGisReq req) { + Long projectId = req.getProjectId(); + List matrixIdList = req.getMatrixIdList(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + List result = new ArrayList<>(); + List matrixList = this.lambdaQuery() + .eq(FacMatrix::getProjectId, projectId) + .in(CollUtil.isNotEmpty(matrixIdList), FacMatrix::getId, matrixIdList) + .list(); + if (CollUtil.isEmpty(matrixList)) { + return result; + } + List matrixVoList = matrixList.stream().map(obj -> + FacFacilityPositionGisVo.obj2vo( + obj.getId(), + obj.getMatrixName(), + obj.getPositions(), + null, + FacCategoryEnum.MATRIX.getValue() + )) + .toList(); + result.addAll(matrixVoList); + // 获取光伏板立柱信息 + List columnList = photovoltaicPanelColumnService.lambdaQuery() + .select( + FacPhotovoltaicPanelColumn::getId, + FacPhotovoltaicPanelColumn::getName, + FacPhotovoltaicPanelColumn::getPositions, + FacPhotovoltaicPanelColumn::getStatus + ) + .eq(FacPhotovoltaicPanelColumn::getProjectId, projectId) + .in(CollUtil.isNotEmpty(matrixIdList), FacPhotovoltaicPanelColumn::getMatrixId, matrixIdList) + .list(); + List columnVoList = columnList.stream().map(obj -> + FacFacilityPositionGisVo.obj2vo( + obj.getId(), + obj.getName(), + obj.getPositions(), + obj.getStatus(), + FacCategoryEnum.PHOTOVOLTAIC_PANEL_COLUMN.getValue() + )) + .toList(); + result.addAll(columnVoList); + // 获取光伏板点信息 + List pointList = photovoltaicPanelPointService.lambdaQuery() + .select( + FacPhotovoltaicPanelPoint::getId, + FacPhotovoltaicPanelPoint::getName, + FacPhotovoltaicPanelPoint::getPositions, + FacPhotovoltaicPanelPoint::getStatus + ) + .eq(FacPhotovoltaicPanelPoint::getProjectId, projectId) + .in(CollUtil.isNotEmpty(matrixIdList), FacPhotovoltaicPanelPoint::getMatrixId, matrixIdList) + .list(); + List pointVoList = pointList.stream().map(obj -> + FacFacilityPositionGisVo.obj2vo( + obj.getId(), + obj.getName(), + obj.getPositions(), + obj.getStatus(), + FacCategoryEnum.PHOTOVOLTAIC_PANEL_POINT.getValue() + )) + .toList(); + result.addAll(pointVoList); + // 获取光伏板支架信息 + List supportList = photovoltaicPanelSupportService.lambdaQuery() + .select( + FacPhotovoltaicPanelSupport::getId, + FacPhotovoltaicPanelSupport::getName, + FacPhotovoltaicPanelSupport::getPositions, + FacPhotovoltaicPanelSupport::getStatus + ) + .eq(FacPhotovoltaicPanelSupport::getProjectId, projectId) + .in(CollUtil.isNotEmpty(matrixIdList), FacPhotovoltaicPanelSupport::getMatrixId, matrixIdList) + .list(); + List supporVotList = supportList.stream().map(obj -> + FacFacilityPositionGisVo.obj2vo( + obj.getId(), + obj.getName(), + obj.getPositions(), + obj.getStatus(), + FacCategoryEnum.PHOTOVOLTAIC_PANEL_SUPPORT.getValue() + )) + .toList(); + result.addAll(supporVotList); + // 获取光伏板信息 + List panelList = photovoltaicPanelService.lambdaQuery() + .select( + FacPhotovoltaicPanel::getId, + FacPhotovoltaicPanel::getName, + FacPhotovoltaicPanel::getPositions, + FacPhotovoltaicPanel::getStatus + ) + .eq(FacPhotovoltaicPanel::getProjectId, projectId) + .eq(FacPhotovoltaicPanel::getProgressCategoryName, "光伏板") + .in(CollUtil.isNotEmpty(matrixIdList), FacPhotovoltaicPanel::getMatrixId, matrixIdList) + .list(); + List panelVoList = panelList.stream().map(obj -> + FacFacilityPositionGisVo.obj2vo( + obj.getId(), + obj.getName(), + obj.getPositions(), + obj.getStatus(), + FacCategoryEnum.PHOTOVOLTAIC_PANEL.getValue() + )) + .toList(); + result.addAll(panelVoList); + // 获取箱变信息 + List boxTransformerList = boxTransformerService.lambdaQuery() + .select( + FacBoxTransformer::getId, + FacBoxTransformer::getName, + FacBoxTransformer::getPositions, + FacBoxTransformer::getStatus + ) + .eq(FacBoxTransformer::getProjectId, projectId) + .eq(FacBoxTransformer::getProgressCategoryName, "箱变基础") + .in(CollUtil.isNotEmpty(matrixIdList), FacBoxTransformer::getMatrixId, matrixIdList) + .list(); + List boxTransformerVoList = boxTransformerList.stream().map(obj -> + FacFacilityPositionGisVo.obj2vo( + obj.getId(), + obj.getName(), + obj.getPositions(), + obj.getStatus(), + FacCategoryEnum.BOX_TRANSFORMER.getValue() + )) + .toList(); + result.addAll(boxTransformerVoList); + // 获取逆变器信息 + List inverterList = inverterService.lambdaQuery() + .select( + FacInverter::getId, + FacInverter::getName, + FacInverter::getPositions, + FacInverter::getStatus + ) + .eq(FacInverter::getProjectId, projectId) + .eq(FacInverter::getProgressCategoryName, "逆变器安装") + .in(CollUtil.isNotEmpty(matrixIdList), FacInverter::getMatrixId, matrixIdList) + .list(); + List inverterVoList = inverterList.stream().map(obj -> + FacFacilityPositionGisVo.obj2vo( + obj.getId(), + obj.getName(), + obj.getPositions(), + obj.getStatus(), + FacCategoryEnum.INVERTER.getValue() + )) + .toList(); + result.addAll(inverterVoList); + return result; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPercentageFacilityServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPercentageFacilityServiceImpl.java new file mode 100644 index 0000000..d0fe23b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPercentageFacilityServiceImpl.java @@ -0,0 +1,161 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.domain.FacPercentageFacility; +import org.dromara.facility.domain.dto.percentagefacility.FacPercentageFacilityQueryReq; +import org.dromara.facility.domain.vo.percentagefacility.FacPercentageFacilityVo; +import org.dromara.facility.mapper.FacPercentageFacilityMapper; +import org.dromara.facility.service.IFacPercentageFacilityService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-百分比设施Service业务层处理 + * + * @author lilemy + * @date 2025-05-26 + */ +@Service +public class FacPercentageFacilityServiceImpl extends ServiceImpl + implements IFacPercentageFacilityService { + + @Resource + private IBusProjectService projectService; + + /** + * 查询设施-百分比设施 + * + * @param id 主键 + * @return 设施-百分比设施 + */ + @Override + public FacPercentageFacilityVo queryById(Long id) { + FacPercentageFacility percentageFacility = this.getById(id); + if (percentageFacility == null) { + throw new ServiceException("查询设施失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(percentageFacility); + } + + /** + * 分页查询设施-百分比设施列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-百分比设施分页列表 + */ + @Override + public TableDataInfo queryPageList(FacPercentageFacilityQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-百分比设施列表 + * + * @param req 查询条件 + * @return 设施-百分比设施列表 + */ + @Override + public List queryList(FacPercentageFacilityQueryReq req) { + List list = this.list(this.buildQueryWrapper(req)); + return list.stream().map(this::getVo).toList(); + } + + /** + * 校验并批量删除设施-百分比设施信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List percentageFacilityList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = percentageFacilityList.stream().map(FacPercentageFacility::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-百分比设施视图对象 + * + * @param percentageFacility 设施-百分比设施对象 + * @return 设施-百分比设施视图对象 + */ + @Override + public FacPercentageFacilityVo getVo(FacPercentageFacility percentageFacility) { + // 对象转封装类 + FacPercentageFacilityVo percentageFacilityVo = new FacPercentageFacilityVo(); + if (percentageFacility == null) { + return percentageFacilityVo; + } + BeanUtils.copyProperties(percentageFacility, percentageFacilityVo); + return percentageFacilityVo; + } + + /** + * 获取设施-百分比设施查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacPercentageFacilityQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + Long progressCategoryId = req.getProgressCategoryId(); + String progressCategoryName = req.getProgressCategoryName(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacPercentageFacility::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), FacPercentageFacility::getMatrixId, matrixId); + lqw.eq(ObjectUtils.isNotEmpty(progressCategoryId), FacPercentageFacility::getProgressCategoryId, progressCategoryId); + lqw.eq(StringUtils.isNotBlank(progressCategoryName), FacPercentageFacility::getProgressCategoryName, progressCategoryName); + return lqw; + } + + /** + * 获取设施-百分比设施分页对象视图 + * + * @param percentageFacilityPage 设施-百分比设施分页对象 + * @return 设施-百分比设施分页对象视图 + */ + @Override + public Page getVoPage(Page percentageFacilityPage) { + List percentageFacilityList = percentageFacilityPage.getRecords(); + Page percentageFacilityVoPage = new Page<>( + percentageFacilityPage.getCurrent(), + percentageFacilityPage.getSize(), + percentageFacilityPage.getTotal()); + if (CollUtil.isEmpty(percentageFacilityList)) { + return percentageFacilityVoPage; + } + List percentageFacilityVoList = percentageFacilityList.stream().map(this::getVo).toList(); + percentageFacilityVoPage.setRecords(percentageFacilityVoList); + return percentageFacilityVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelColumnServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelColumnServiceImpl.java new file mode 100644 index 0000000..d440b0a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelColumnServiceImpl.java @@ -0,0 +1,280 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.domain.FacPhotovoltaicPanelColumn; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelcolumn.FacPhotovoltaicPanelColumnVo; +import org.dromara.facility.mapper.FacPhotovoltaicPanelColumnMapper; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.facility.service.IFacPhotovoltaicPanelColumnService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-光伏板立柱Service业务层处理 + * + * @author lilemy + * @date 2025-04-21 + */ +@Service +public class FacPhotovoltaicPanelColumnServiceImpl extends ServiceImpl + implements IFacPhotovoltaicPanelColumnService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IFacMatrixService matrixService; + + /** + * 查询设施-光伏板立柱 + * + * @param id 主键 + * @return 设施-光伏板立柱 + */ + @Override + public FacPhotovoltaicPanelColumnVo queryById(Long id) { + FacPhotovoltaicPanelColumn photovoltaicPanelColumn = this.getById(id); + if (photovoltaicPanelColumn == null) { + throw new ServiceException("查询光伏板立柱失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(photovoltaicPanelColumn); + } + + /** + * 分页查询设施-光伏板立柱列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板立柱分页列表 + */ + @Override + public TableDataInfo queryPageList(FacPhotovoltaicPanelColumnQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-光伏板立柱列表 + * + * @param req 查询条件 + * @return 设施-光伏板立柱列表 + */ + @Override + public List queryList(FacPhotovoltaicPanelColumnQueryReq req) { + List photovoltaicPanelColumnList = this.list(this.buildQueryWrapper(req)); + return photovoltaicPanelColumnList.stream().map(this::getVo).toList(); + } + + /** + * 新增设施-光伏板立柱 + * + * @param req 设施-光伏板立柱 + * @return 新增光伏板立柱id + */ + @Override + public Long insertByBo(FacPhotovoltaicPanelColumnCreateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanelColumn photovoltaicPanelColumn = new FacPhotovoltaicPanelColumn(); + BeanUtils.copyProperties(req, photovoltaicPanelColumn); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanelColumn.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanelColumn, true); + // 判断是否存在同名光伏板立柱 + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanelColumn::getProjectId, photovoltaicPanelColumn.getProjectId()) + .eq(FacPhotovoltaicPanelColumn::getName, photovoltaicPanelColumn.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板立柱", HttpStatus.CONFLICT); + } + // 操作数据库 + boolean save = this.save(photovoltaicPanelColumn); + if (!save) { + throw new ServiceException("新增光伏板立柱失败,数据库异常", HttpStatus.ERROR); + } + return photovoltaicPanelColumn.getId(); + } + + /** + * 修改设施-光伏板立柱 + * + * @param req 设施-光伏板立柱 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FacPhotovoltaicPanelColumnUpdateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanelColumn photovoltaicPanelColumn = new FacPhotovoltaicPanelColumn(); + BeanUtils.copyProperties(req, photovoltaicPanelColumn); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanelColumn.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanelColumn, false); + // 判断是否存在 + FacPhotovoltaicPanelColumn oldPhotovoltaicPanelColumn = this.getById(photovoltaicPanelColumn.getId()); + if (oldPhotovoltaicPanelColumn == null) { + throw new ServiceException("修改光伏板立柱失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断是否修改名称 + if (!oldPhotovoltaicPanelColumn.getName().equals(photovoltaicPanelColumn.getName())) { + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanelColumn::getProjectId, photovoltaicPanelColumn.getProjectId()) + .eq(FacPhotovoltaicPanelColumn::getName, photovoltaicPanelColumn.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板立柱", HttpStatus.CONFLICT); + } + } + // 操作数据库 + boolean update = this.updateById(photovoltaicPanelColumn); + if (!update) { + throw new ServiceException("修改光伏板立柱失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FacPhotovoltaicPanelColumn entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long matrixId = entity.getMatrixId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (matrixId == null) { + throw new ServiceException("方阵id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (matrixId != null && matrixService.getById(matrixId) == null) { + throw new ServiceException("对应方阵不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设施-光伏板立柱信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List photovoltaicPanelColumnList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = photovoltaicPanelColumnList.stream().map(FacPhotovoltaicPanelColumn::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-光伏板立柱视图对象 + * + * @param photovoltaicPanelColumn 设施-光伏板立柱对象 + * @return 设施-光伏板立柱视图对象 + */ + @Override + public FacPhotovoltaicPanelColumnVo getVo(FacPhotovoltaicPanelColumn photovoltaicPanelColumn) { + // 对象转封装类 + FacPhotovoltaicPanelColumnVo photovoltaicPanelColumnVo = new FacPhotovoltaicPanelColumnVo(); + if (photovoltaicPanelColumn == null) { + return photovoltaicPanelColumnVo; + } + BeanUtils.copyProperties(photovoltaicPanelColumn, photovoltaicPanelColumnVo); + // 将 JSON 字符串转化为 List + String positions = photovoltaicPanelColumn.getPositions(); + if (StringUtils.isNotBlank(positions)) { + List positionList = JSONUtil.toList(positions, String.class); + photovoltaicPanelColumnVo.setPositionList(positionList); + } + return photovoltaicPanelColumnVo; + } + + /** + * 获取设施-光伏板立柱查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelColumnQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + String name = req.getName(); + String status = req.getStatus(); + String finishType = req.getFinishType(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), FacPhotovoltaicPanelColumn::getName, name); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacPhotovoltaicPanelColumn::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanelColumn::getMatrixId, matrixId); + lqw.eq(StringUtils.isNotBlank(status), FacPhotovoltaicPanelColumn::getStatus, status); + lqw.eq(StringUtils.isNotBlank(finishType), FacPhotovoltaicPanelColumn::getFinishType, finishType); + lqw.orderByAsc(FacPhotovoltaicPanelColumn::getName); + return lqw; + } + + /** + * 获取设施-光伏板立柱分页对象视图 + * + * @param photovoltaicPanelColumnPage 设施-光伏板立柱分页对象 + * @return 设施-光伏板立柱分页对象视图 + */ + @Override + public Page getVoPage(Page photovoltaicPanelColumnPage) { + List photovoltaicPanelColumnList = photovoltaicPanelColumnPage.getRecords(); + Page photovoltaicPanelColumnVoPage = new Page<>( + photovoltaicPanelColumnPage.getCurrent(), + photovoltaicPanelColumnPage.getSize(), + photovoltaicPanelColumnPage.getTotal()); + if (CollUtil.isEmpty(photovoltaicPanelColumnList)) { + return photovoltaicPanelColumnVoPage; + } + List photovoltaicPanelColumnVoList = photovoltaicPanelColumnList.stream().map(this::getVo).toList(); + photovoltaicPanelColumnVoPage.setRecords(photovoltaicPanelColumnVoList); + return photovoltaicPanelColumnVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelPartsServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelPartsServiceImpl.java new file mode 100644 index 0000000..23cd534 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelPartsServiceImpl.java @@ -0,0 +1,732 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.facility.constant.FacPhotovoltaicPanelPartsConstant; +import org.dromara.facility.constant.FacRedisKeyConstant; +import org.dromara.facility.domain.FacPhotovoltaicPanel; +import org.dromara.facility.domain.FacPhotovoltaicPanelColumn; +import org.dromara.facility.domain.FacPhotovoltaicPanelPoint; +import org.dromara.facility.domain.FacPhotovoltaicPanelSupport; +import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint; +import org.dromara.facility.domain.dto.photovoltaicpanelparts.FacPhotovoltaicPanelPartsCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.photovoltaicpanelparts.FacPhotovoltaicPanelPartsCreateReq; +import org.dromara.facility.domain.enums.FacFinishStatusEnum; +import org.dromara.facility.domain.enums.FacFinishTypeEnum; +import org.dromara.facility.service.*; +import org.dromara.progress.constant.PgsProgressCategoryConstant; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.common.utils.JSTUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author lilemy + * @date 2025/4/21 15:53 + */ +@Slf4j +@Service +public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPanelPartsService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IFacMatrixService matrixService; + + @Resource + private IFacPhotovoltaicPanelService photovoltaicPanelService; + + @Resource + private IFacPhotovoltaicPanelPointService photovoltaicPanelPointService; + + @Resource + private IFacPhotovoltaicPanelColumnService photovoltaicPanelColumnService; + + @Resource + private IFacPhotovoltaicPanelSupportService photovoltaicPanelSupportService; + + @Resource + private IPgsProgressCategoryService progressCategoryService; + + @Resource + private RedisTemplate redisTemplate; + + @Resource + private ScheduledExecutorService scheduledExecutorService; + + @Lazy + @Resource + private FacPhotovoltaicPanelPartsServiceImpl self; // 注入自己 + + /** + * 批量新增设施-光伏板(桩点、立柱、支架) + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + @Override + public Boolean insertPartsByGeoJson(FacPhotovoltaicPanelPartsCreateByGeoJsonReq geoJson) { + Long projectId = geoJson.getProjectId(); + // 判断 redis key 是否存在,存在则返回 + List operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId); + List list = redisTemplate.opsForValue().multiGet(operationRedisKey); + boolean hasValue = list != null && list.stream().anyMatch(Objects::nonNull); + if (hasValue) { + throw new ServiceException("项目下有设施数据正在处理中,请等待处理完毕后再操作", HttpStatus.BAD_REQUEST); + } + // 第一次接收请求,进行数据校验 + int batchNum = geoJson.getBatchNum(); + if (batchNum == 1) { + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 查询项目下光伏板 + Long count = photovoltaicPanelService.lambdaQuery() + .eq(FacPhotovoltaicPanel::getProjectId, projectId).count(); + if (count <= 0) { + throw new ServiceException("项目下无光伏板信息,请先创建光伏板信息后再添加桩点、立柱、支架信息", HttpStatus.NOT_FOUND); + } + } + // 获取 redis key + String sessionId = geoJson.getSessionId(); + int totalBatch = geoJson.getTotalBatch(); + List dataList = geoJson.getLocationGeoJson().getFeatures(); + String redisKey = FacRedisKeyConstant.getBatchUploadPartsRedisKey(sessionId, batchNum); + // 存储到 Redis,设置过期时间 30 分钟 + redisTemplate.opsForValue().set(redisKey, dataList, 1800, TimeUnit.SECONDS); + log.info("已接收第 {} 批数据,共 {} 批", batchNum, totalBatch); + Long userId = LoginHelper.getUserId(); + SseMessageDto messageDto = new SseMessageDto(); + messageDto.setUserIds(List.of(userId)); + // 如果是最后一批,开始合并 + if (batchNum == totalBatch) { + List allData = new ArrayList<>(); + for (int i = 1; i <= totalBatch; i++) { + String batchKey = FacRedisKeyConstant.getBatchUploadPartsRedisKey(sessionId, i); + Object batchObj = redisTemplate.opsForValue().get(batchKey); + if (batchObj instanceof List) { + @SuppressWarnings("unchecked") + List batch = (List) batchObj; + allData.addAll(batch); + } + } + // 设置 redis key,防止多次操作 + String operationPartsRedisKey = FacRedisKeyConstant.getPartsInOperationByProjectRedisKey(projectId); + redisTemplate.opsForValue().set(operationPartsRedisKey, true); + messageDto.setMessage("桩点、立柱、支架数据上传完毕,正在处理中"); + SseMessageUtils.publishMessage(messageDto); + scheduledExecutorService.execute(() -> { + try { + // 合并后的数据处理,如入库 + this.saveBatch(projectId, allData, userId); + } catch (Exception e) { + messageDto.setMessage("桩点、立柱、支架数据处理失败,请联系管理员处理"); + SseMessageUtils.publishMessage(messageDto); + log.error("桩点、立柱、支架数据处理失败", e); + throw new ServiceException("桩点、立柱、支架数据处理失败", HttpStatus.ERROR); + } finally { + // 清理缓存 + for (int i = 1; i <= totalBatch; i++) { + String batchKey = FacRedisKeyConstant.getBatchUploadPartsRedisKey(sessionId, i); + redisTemplate.delete(batchKey); + } + redisTemplate.delete(operationPartsRedisKey); + } + messageDto.setMessage("桩点、立柱、支架数据处理完毕"); + SseMessageUtils.publishMessage(messageDto); + }); + return true; + } + return true; + } + + /** + * 批量保存数据 + * + * @param projectId 项目id + * @param features 数据 + * @param userId 操作用户id + */ + private void saveBatch(Long projectId, List features, Long userId) { + // 获取进度类别 Map + List progressCategoryNameList = List.of( + FacPhotovoltaicPanelPartsConstant.POINT, + FacPhotovoltaicPanelPartsConstant.COLUMN, + FacPhotovoltaicPanelPartsConstant.SUPPORT + ); + List progressCategoryList = progressCategoryService.lambdaQuery() + .select(PgsProgressCategory::getId, PgsProgressCategory::getName, PgsProgressCategory::getMatrixId) + .in(PgsProgressCategory::getName, progressCategoryNameList) + .in(PgsProgressCategory::getProjectId, projectId, PgsProgressCategoryConstant.PUBLIC_PROJECT_ID) + .list(); + Map> progressCategoryMap = progressCategoryList.stream() + .collect(Collectors.groupingBy( + progressCategory -> progressCategory.getMatrixId() + "_" + progressCategory.getName() + )); + // 查询项目下光伏板 + List photovoltaicPanelList = photovoltaicPanelService.lambdaQuery() + .eq(FacPhotovoltaicPanel::getProjectId, projectId) + .list(); + Map photovoltaicPanelMap = photovoltaicPanelList.stream() + .collect(Collectors.toMap( + FacPhotovoltaicPanel::getName, + Function.identity(), + (existing, replacement) -> existing // 如果有重复,保留第一个 + )); + // 获取数据库中所有点的列表 + List oldPointList = photovoltaicPanelPointService.lambdaQuery() + .select(FacPhotovoltaicPanelPoint::getId, + FacPhotovoltaicPanelPoint::getName, + FacPhotovoltaicPanelPoint::getFinishType, + FacPhotovoltaicPanelPoint::getFinishDate, + FacPhotovoltaicPanelPoint::getStatus) + .eq(FacPhotovoltaicPanelPoint::getProjectId, projectId) + .list(); + Map oldPointMap = oldPointList.stream() + .collect(Collectors.toMap( + FacPhotovoltaicPanelPoint::getName, + Function.identity(), + (existing, replacement) -> existing // 如果有重复,保留第一个 + )); + List oldColumnList = photovoltaicPanelColumnService.lambdaQuery() + .select(FacPhotovoltaicPanelColumn::getId, + FacPhotovoltaicPanelColumn::getName, + FacPhotovoltaicPanelColumn::getFinishType, + FacPhotovoltaicPanelColumn::getFinishDate, + FacPhotovoltaicPanelColumn::getStatus) + .eq(FacPhotovoltaicPanelColumn::getProjectId, projectId) + .list(); + Map oldColumnMap = oldColumnList.stream() + .collect(Collectors.toMap( + FacPhotovoltaicPanelColumn::getName, + Function.identity(), + (existing, replacement) -> existing // 如果有重复,保留第一个 + )); + List oldSupportList = photovoltaicPanelSupportService.lambdaQuery() + .select(FacPhotovoltaicPanelSupport::getId, + FacPhotovoltaicPanelSupport::getName, + FacPhotovoltaicPanelSupport::getFinishType, + FacPhotovoltaicPanelSupport::getFinishDate, + FacPhotovoltaicPanelSupport::getStatus) + .eq(FacPhotovoltaicPanelSupport::getProjectId, projectId) + .list(); + Map oldSupportMap = oldSupportList.stream() + .collect(Collectors.toMap( + FacPhotovoltaicPanelSupport::getName, + Function.identity(), + (existing, replacement) -> existing // 如果有重复,保留第一个 + )); + // 线程安全集合 + List pointList = Collections.synchronizedList(new ArrayList<>()); + List columnList = Collections.synchronizedList(new ArrayList<>()); + List supportList = Collections.synchronizedList(new ArrayList<>()); + try (ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())) { + // 所有点列表 + List> pointPositionList = new ArrayList<>(features.stream() + .map(featureByPoint -> featureByPoint.getGeometry().getCoordinates()) + .toList()); + // 多线程处理 + List> futures = new ArrayList<>(); + List> sharedPointList = Collections.synchronizedList(pointPositionList); + for (Map.Entry entry : photovoltaicPanelMap.entrySet()) { + FacPhotovoltaicPanel photovoltaicPanel = entry.getValue(); + Future future = executor.submit(() -> { + List> positionList = JSONUtil.toList(photovoltaicPanel.getPositions(), String.class) + .stream().map(s -> JSONUtil.toList(s, Double.class)).collect(Collectors.toList()); + List> pointInPlaneList = JSTUtil.getPointInPlaneList(positionList, sharedPointList); + if (CollUtil.isNotEmpty(pointInPlaneList)) { + int i = 1; + for (List list : pointInPlaneList) { + String str = String.format("%02d", i++); + String name = photovoltaicPanel.getName() + "." + str; + Long matrixId = photovoltaicPanel.getMatrixId(); + String jsonStr = JSONUtil.toJsonStr(list); + // 创建 Point + FacPhotovoltaicPanelPoint point = new FacPhotovoltaicPanelPoint(); + point.setProjectId(projectId); + point.setMatrixId(matrixId); + point.setName(name); + point.setPositions(jsonStr); + point.setCreateBy(userId); + point.setUpdateBy(userId); + if (oldPointMap.containsKey(name)) { + FacPhotovoltaicPanelPoint oldPoint = oldPointMap.get(name); + point.setFinishType(oldPoint.getFinishType()); + point.setFinishDate(oldPoint.getFinishDate()); + point.setStatus(oldPoint.getStatus()); + } + String pointMapKey = matrixId + "_" + FacPhotovoltaicPanelPartsConstant.POINT; + if (progressCategoryMap.containsKey(pointMapKey)) { + PgsProgressCategory cat = progressCategoryMap.get(pointMapKey).getFirst(); + point.setProgressCategoryId(cat.getId()); + point.setProgressCategoryName(cat.getName()); + } + pointList.add(point); + // 创建 Column + FacPhotovoltaicPanelColumn column = new FacPhotovoltaicPanelColumn(); + column.setProjectId(projectId); + column.setMatrixId(matrixId); + column.setName(name); + column.setPositions(jsonStr); + column.setCreateBy(userId); + column.setUpdateBy(userId); + if (oldColumnMap.containsKey(name)) { + FacPhotovoltaicPanelColumn oldColumn = oldColumnMap.get(name); + column.setFinishType(oldColumn.getFinishType()); + column.setFinishDate(oldColumn.getFinishDate()); + column.setStatus(oldColumn.getStatus()); + } + String columnMapKey = matrixId + "_" + FacPhotovoltaicPanelPartsConstant.COLUMN; + if (progressCategoryMap.containsKey(columnMapKey)) { + PgsProgressCategory cat = progressCategoryMap.get(columnMapKey).getFirst(); + column.setProgressCategoryId(cat.getId()); + column.setProgressCategoryName(cat.getName()); + } + columnList.add(column); + // 创建 Support + FacPhotovoltaicPanelSupport support = new FacPhotovoltaicPanelSupport(); + support.setProjectId(projectId); + support.setMatrixId(matrixId); + support.setName(name); + support.setPositions(jsonStr); + support.setCreateBy(userId); + support.setUpdateBy(userId); + if (oldSupportMap.containsKey(name)) { + FacPhotovoltaicPanelSupport oldSupport = oldSupportMap.get(name); + support.setFinishType(oldSupport.getFinishType()); + support.setFinishDate(oldSupport.getFinishDate()); + support.setStatus(oldSupport.getStatus()); + } + String supportMapKey = matrixId + "_" + FacPhotovoltaicPanelPartsConstant.SUPPORT; + if (progressCategoryMap.containsKey(supportMapKey)) { + PgsProgressCategory cat = progressCategoryMap.get(supportMapKey).getFirst(); + support.setProgressCategoryId(cat.getId()); + support.setProgressCategoryName(cat.getName()); + } + supportList.add(support); + } + } + }); + futures.add(future); + } + // 等待所有线程完成 + for (Future future : futures) { + try { + future.get(); + } catch (Exception e) { + log.error("多线程进行光伏板点位与面匹配异常", e); + throw new ServiceException("进行光伏板点位与面匹配异常", HttpStatus.ERROR); + } + } + } + // 自定义线程池(IO 密集型线程池) + ThreadPoolExecutor customExecutor = new ThreadPoolExecutor( + 20, // 核心线程数 + 50, // 最大线程数 + 60L, // 线程空闲存活时间 + TimeUnit.SECONDS, // 存活时间单位 + new LinkedBlockingQueue<>(10000), // 阻塞队列容量 + new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用线程处理任务 + ); + // 分批处理,避免长事务,假设每次处理 1000 条数据 + int batchSize = 1000; + // 保存所有批次任务 + List> deleteFutures = new ArrayList<>(); + int deleteSize = oldPointList.size(); + for (int i = 0; i < deleteSize; i += batchSize) { + int endIndex = Math.min(i + batchSize, deleteSize); + List batchPointList = oldPointList.subList(i, endIndex); + List batchColumnList = oldColumnList.subList(i, endIndex); + List batchSupportList = oldSupportList.subList(i, endIndex); + // 使用事务处理每批数据 + // 获取代理 + FacPhotovoltaicPanelPartsServiceImpl photovoltaicPanelPartsService = self; + // 异步处理每批数据,将任务添加到异步任务列表 + CompletableFuture future = CompletableFuture.runAsync(() -> photovoltaicPanelPartsService.batchDeletePartsInner(batchPointList, batchColumnList, batchSupportList), customExecutor); + deleteFutures.add(future); + } + // 等待所有批次完成操作 + CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0])).join(); + // 保存所有批次任务 + List> insertFutures = new ArrayList<>(); + int totalSize = pointList.size(); + for (int i = 0; i < totalSize; i += batchSize) { + int endIndex = Math.min(i + batchSize, totalSize); + List batchPointList = pointList.subList(i, endIndex); + List batchColumnList = columnList.subList(i, endIndex); + List batchSupportList = supportList.subList(i, endIndex); + // 使用事务处理每批数据 + // 获取代理 + FacPhotovoltaicPanelPartsServiceImpl photovoltaicPanelPartsService = self; + // 异步处理每批数据,将任务添加到异步任务列表 + CompletableFuture future = CompletableFuture.runAsync(() -> photovoltaicPanelPartsService.batchInsertPartsInner(batchPointList, batchColumnList, batchSupportList), customExecutor); + insertFutures.add(future); + } + // 等待所有批次完成操作 + CompletableFuture.allOf(insertFutures.toArray(new CompletableFuture[0])).join(); + // 关闭线程池 + customExecutor.shutdown(); + } + + /** + * 批量新增设施-光伏板(桩点、立柱、支架)内部方法 + * + * @param pointList 桩点列表 + * @param columnList 立柱列表 + * @param supportList 支架列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void batchInsertPartsInner(List pointList, + List columnList, + List supportList) { + try { + if (CollUtil.isNotEmpty(pointList)) { + boolean result = photovoltaicPanelPointService.saveBatch(pointList); + if (!result) { + throw new ServiceException("批量新增光伏板桩点失败,数据库异常", HttpStatus.ERROR); + } + } + if (CollUtil.isNotEmpty(columnList)) { + boolean result = photovoltaicPanelColumnService.saveBatch(columnList); + if (!result) { + throw new ServiceException("批量新增光伏板立柱失败,数据库异常", HttpStatus.ERROR); + } + } + if (CollUtil.isNotEmpty(supportList)) { + boolean result = photovoltaicPanelSupportService.saveBatch(supportList); + if (!result) { + throw new ServiceException("批量新增光伏板支架失败,数据库异常", HttpStatus.ERROR); + } + } + } catch (DataIntegrityViolationException e) { + log.error("数据库唯一键冲突或违反其他完整性约束, 错误信息: {}", e.getMessage()); + throw new ServiceException("数据已存在,无法重复添加"); + } catch (DataAccessException e) { + log.error("数据库连接问题、事务问题等导致操作失败, 错误信息: {}", e.getMessage()); + throw new ServiceException("数据库操作失败"); + } catch (Exception e) { + // 捕获其他异常,做通用处理 + log.error("批量添加光伏板点时发生未知错误,错误信息: {}", e.getMessage()); + throw new ServiceException("批量添加光伏板点失败"); + } + } + + /** + * 批量删除设施-光伏板(桩点、立柱、支架)内部方法 + * + * @param pointList 桩点列表 + * @param columnList 立柱列表 + * @param supportList 支架列表 + */ + @Override + public void batchDeletePartsInner(List pointList, + List columnList, + List supportList) { + try { + if (CollUtil.isNotEmpty(pointList)) { + boolean result = photovoltaicPanelPointService.removeBatchByIds(pointList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + } + if (CollUtil.isNotEmpty(columnList)) { + boolean result = photovoltaicPanelColumnService.removeBatchByIds(columnList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + } + if (CollUtil.isNotEmpty(supportList)) { + boolean result = photovoltaicPanelSupportService.removeBatchByIds(supportList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + } + } catch (DataIntegrityViolationException e) { + log.error("数据库唯一键冲突或违反其他完整性约束: {}", e.getMessage()); + throw new ServiceException("数据已存在,无法重复添加"); + } catch (DataAccessException e) { + log.error("数据库连接问题、事务问题等导致操作失败: {}", e.getMessage()); + throw new ServiceException("数据库操作失败"); + } catch (Exception e) { + // 捕获其他异常,做通用处理 + log.error("批量删除光伏板点时发生未知错误,错误信息: {}", e.getMessage()); + throw new ServiceException("批量添加光伏板点失败"); + } + } + + /** + * 批量新增设施-光伏板(桩点、立柱、支架) + * + * @param req 设施-光伏板(桩点、立柱、支架) + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertPartsByBatch(FacPhotovoltaicPanelPartsCreateReq req) { + // 参数校验 + Long projectId = req.getProjectId(); + if (projectId == null || projectService.getById(projectId) == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + Long matrixId = req.getMatrixId(); + if (matrixId == null || matrixService.getById(matrixId) == null) { + throw new ServiceException("方阵信息不存在", HttpStatus.NOT_FOUND); + } + // 数据校验 + this.validName(projectId, req.getName()); + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanelPoint photovoltaicPanelPoint = new FacPhotovoltaicPanelPoint(); + BeanUtils.copyProperties(req, photovoltaicPanelPoint); + FacPhotovoltaicPanelColumn photovoltaicPanelColumn = new FacPhotovoltaicPanelColumn(); + BeanUtils.copyProperties(req, photovoltaicPanelColumn); + FacPhotovoltaicPanelSupport photovoltaicPanelSupport = new FacPhotovoltaicPanelSupport(); + BeanUtils.copyProperties(req, photovoltaicPanelSupport); + // 填充默认值 + List positionList = req.getPositionList(); + if (CollUtil.isNotEmpty(positionList)) { + String jsonStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanelPoint.setPositions(jsonStr); + photovoltaicPanelColumn.setPositions(jsonStr); + photovoltaicPanelSupport.setPositions(jsonStr); + } + // 插入数据 + boolean pointSave = photovoltaicPanelPointService.save(photovoltaicPanelPoint); + if (!pointSave) { + throw new ServiceException("桩点信息插入失败", HttpStatus.ERROR); + } + boolean columnSave = photovoltaicPanelColumnService.save(photovoltaicPanelColumn); + if (!columnSave) { + throw new ServiceException("立柱信息插入失败", HttpStatus.ERROR); + } + boolean supportSave = photovoltaicPanelSupportService.save(photovoltaicPanelSupport); + if (!supportSave) { + throw new ServiceException("支架信息插入失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 根据方阵主键判断是否存在光伏板点 + * + * @param projectId 项目id + * @param matrixIds 方阵Id列表 + * @return 是否存在 + */ + @Override + public Boolean validPartsExistByMatrix(Long projectId, Collection matrixIds) { + Long pointCount = photovoltaicPanelPointService.lambdaQuery() + .eq(FacPhotovoltaicPanelPoint::getProjectId, projectId) + .in(FacPhotovoltaicPanelPoint::getMatrixId, matrixIds) + .count(); + if (pointCount > 0) { + return true; + } + Long columnCount = photovoltaicPanelColumnService.lambdaQuery() + .eq(FacPhotovoltaicPanelColumn::getProjectId, projectId) + .in(FacPhotovoltaicPanelColumn::getMatrixId, matrixIds) + .count(); + if (columnCount > 0) { + return true; + } + Long supportCount = photovoltaicPanelSupportService.lambdaQuery() + .eq(FacPhotovoltaicPanelSupport::getProjectId, projectId) + .in(FacPhotovoltaicPanelSupport::getMatrixId, matrixIds) + .count(); + return supportCount > 0; + } + + /** + * 根据光伏板名称判断是否存在光伏板点 + * + * @param projectId 项目id + * @param photovoltaicPanelNames 光伏板名称列表 + * @return 是否存在 + */ + @Override + public Boolean validPartsExistByPhotovoltaicPanel(Long projectId, Collection photovoltaicPanelNames) { + LambdaQueryWrapper pointWrapper = new LambdaQueryWrapper<>(); + pointWrapper.and(query -> { + for (String name : photovoltaicPanelNames) { + query.or().likeRight(FacPhotovoltaicPanelPoint::getName, name + "."); + } + }); + if (photovoltaicPanelPointService.count(pointWrapper) > 0) { + return true; + } + LambdaQueryWrapper ColumnWrapper = new LambdaQueryWrapper<>(); + ColumnWrapper.and(query -> { + for (String name : photovoltaicPanelNames) { + query.or().likeRight(FacPhotovoltaicPanelColumn::getName, name + "."); + } + }); + if (photovoltaicPanelColumnService.count(ColumnWrapper) > 0) { + return true; + } + LambdaQueryWrapper supportWrapper = new LambdaQueryWrapper<>(); + supportWrapper.and(query -> { + for (String name : photovoltaicPanelNames) { + query.or().likeRight(FacPhotovoltaicPanelSupport::getName, name + "."); + } + }); + return photovoltaicPanelSupportService.count(supportWrapper) > 0; + } + + /** + * 更新光伏板点完成状态 + * + * @param workType 类型 + * @param finishDate 完成时间 + * @param projectId 项目id + * @param matrixId 方阵id + * @param photovoltaicPanelNameList 光伏板名称列表 + * @return 是否更新成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updatePartsFinishStatus(String workType, Date finishDate, Long projectId, Long matrixId, List photovoltaicPanelNameList) { + if (CollUtil.isEmpty(photovoltaicPanelNameList)) { + return true; + } + switch (workType) { + case PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_POINT_WORK_TYPE -> { + LambdaUpdateWrapper pointWrapper = new LambdaUpdateWrapper<>(); + pointWrapper.eq(FacPhotovoltaicPanelPoint::getProjectId, projectId); + pointWrapper.eq(FacPhotovoltaicPanelPoint::getMatrixId, matrixId); + pointWrapper.and(query -> { + for (int i = 0; i < photovoltaicPanelNameList.size(); i++) { + String prefix = photovoltaicPanelNameList.get(i) + "."; + if (i == 0) { + query.likeRight(FacPhotovoltaicPanelPoint::getName, prefix); + } else { + query.or().likeRight(FacPhotovoltaicPanelPoint::getName, prefix); + } + } + }); + long count = photovoltaicPanelPointService.count(pointWrapper); + if (count <= 0) { + throw new ServiceException("光伏板桩点数据不存在,请导入数据后再进行操作", HttpStatus.NOT_FOUND); + } + pointWrapper.set(FacPhotovoltaicPanelPoint::getFinishDate, finishDate); + pointWrapper.set(FacPhotovoltaicPanelPoint::getFinishType, FacFinishTypeEnum.HAND.getValue()); + pointWrapper.set(FacPhotovoltaicPanelPoint::getStatus, FacFinishStatusEnum.FINISH.getValue()); + boolean updatePoint = photovoltaicPanelPointService.update(pointWrapper); + if (!updatePoint) { + throw new ServiceException("桩点信息更新失败", HttpStatus.ERROR); + } + } + case PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_COLUMN_WORK_TYPE -> { + LambdaUpdateWrapper columnWrapper = new LambdaUpdateWrapper<>(); + columnWrapper.eq(FacPhotovoltaicPanelColumn::getProjectId, projectId); + columnWrapper.eq(FacPhotovoltaicPanelColumn::getMatrixId, matrixId); + columnWrapper.and(query -> { + for (int i = 0; i < photovoltaicPanelNameList.size(); i++) { + String prefix = photovoltaicPanelNameList.get(i) + "."; + if (i == 0) { + query.likeRight(FacPhotovoltaicPanelColumn::getName, prefix); + } else { + query.or().likeRight(FacPhotovoltaicPanelColumn::getName, prefix); + } + } + }); + long count = photovoltaicPanelColumnService.count(columnWrapper); + if (count <= 0) { + throw new ServiceException("光伏板立柱数据不存在,请导入数据后再进行操作", HttpStatus.NOT_FOUND); + } + columnWrapper.set(FacPhotovoltaicPanelColumn::getFinishDate, finishDate); + columnWrapper.set(FacPhotovoltaicPanelColumn::getFinishType, FacFinishTypeEnum.HAND.getValue()); + columnWrapper.set(FacPhotovoltaicPanelColumn::getStatus, FacFinishStatusEnum.FINISH.getValue()); + boolean updateColumn = photovoltaicPanelColumnService.update(columnWrapper); + if (!updateColumn) { + throw new ServiceException("立柱信息更新失败", HttpStatus.ERROR); + } + } + case PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_SUPPORT_WORK_TYPE -> { + LambdaUpdateWrapper supportWrapper = new LambdaUpdateWrapper<>(); + supportWrapper.eq(FacPhotovoltaicPanelSupport::getProjectId, projectId); + supportWrapper.eq(FacPhotovoltaicPanelSupport::getMatrixId, matrixId); + supportWrapper.and(query -> { + for (int i = 0; i < photovoltaicPanelNameList.size(); i++) { + String prefix = photovoltaicPanelNameList.get(i) + "."; + if (i == 0) { + query.likeRight(FacPhotovoltaicPanelSupport::getName, prefix); + } else { + query.or().likeRight(FacPhotovoltaicPanelSupport::getName, prefix); + } + } + }); + long count = photovoltaicPanelSupportService.count(supportWrapper); + if (count <= 0) { + throw new ServiceException("光伏板支架数据不存在,请导入数据后再进行操作", HttpStatus.NOT_FOUND); + } + supportWrapper.set(FacPhotovoltaicPanelSupport::getFinishDate, finishDate); + supportWrapper.set(FacPhotovoltaicPanelSupport::getFinishType, FacFinishTypeEnum.HAND.getValue()); + supportWrapper.set(FacPhotovoltaicPanelSupport::getStatus, FacFinishStatusEnum.FINISH.getValue()); + boolean updateSupport = photovoltaicPanelSupportService.update(supportWrapper); + if (!updateSupport) { + throw new ServiceException("支架信息更新失败", HttpStatus.ERROR); + } + } + case null, default -> throw new ServiceException("未知设施类型", HttpStatus.ERROR); + } + return true; + } + + /** + * 校验名称是否重复 + * + * @param projectId 项目ID + * @param name 名称 + */ + private void validName(Long projectId, String name) { + if (StringUtils.isBlank(name)) { + throw new ServiceException("桩点、立柱、支架名称不能为空"); + } + // 参数校验 + Long pointCount = photovoltaicPanelPointService.lambdaQuery() + .eq(FacPhotovoltaicPanelPoint::getProjectId, projectId) + .eq(FacPhotovoltaicPanelPoint::getName, name) + .count(); + if (pointCount > 0) { + throw new ServiceException("桩点名称重复"); + } + Long columnCount = photovoltaicPanelColumnService.lambdaQuery() + .eq(FacPhotovoltaicPanelColumn::getProjectId, projectId) + .eq(FacPhotovoltaicPanelColumn::getName, name) + .count(); + if (columnCount > 0) { + throw new ServiceException("立柱名称重复"); + } + Long supportCount = photovoltaicPanelSupportService.lambdaQuery() + .eq(FacPhotovoltaicPanelSupport::getProjectId, projectId) + .eq(FacPhotovoltaicPanelSupport::getName, name) + .count(); + if (supportCount > 0) { + throw new ServiceException("支架名称重复"); + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelPointServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelPointServiceImpl.java new file mode 100644 index 0000000..c7fa73e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelPointServiceImpl.java @@ -0,0 +1,280 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.domain.FacPhotovoltaicPanelPoint; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelpoint.FacPhotovoltaicPanelPointUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelpoint.FacPhotovoltaicPanelPointVo; +import org.dromara.facility.mapper.FacPhotovoltaicPanelPointMapper; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.facility.service.IFacPhotovoltaicPanelPointService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-光伏板桩点Service业务层处理 + * + * @author lilemy + * @date 2025-04-21 + */ +@Service +public class FacPhotovoltaicPanelPointServiceImpl extends ServiceImpl + implements IFacPhotovoltaicPanelPointService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IFacMatrixService matrixService; + + /** + * 查询设施-光伏板桩点 + * + * @param id 主键 + * @return 设施-光伏板桩点 + */ + @Override + public FacPhotovoltaicPanelPointVo queryById(Long id) { + FacPhotovoltaicPanelPoint photovoltaicPanelPoint = this.getById(id); + if (photovoltaicPanelPoint == null) { + throw new ServiceException("查询光伏板桩点失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(photovoltaicPanelPoint); + } + + /** + * 分页查询设施-光伏板桩点列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板桩点分页列表 + */ + @Override + public TableDataInfo queryPageList(FacPhotovoltaicPanelPointQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-光伏板桩点列表 + * + * @param req 查询条件 + * @return 设施-光伏板桩点列表 + */ + @Override + public List queryList(FacPhotovoltaicPanelPointQueryReq req) { + List photovoltaicPanelPointList = this.list(this.buildQueryWrapper(req)); + return photovoltaicPanelPointList.stream().map(this::getVo).toList(); + } + + /** + * 新增设施-光伏板桩点 + * + * @param req 设施-光伏板桩点 + * @return 新增光伏板桩点id + */ + @Override + public Long insertByBo(FacPhotovoltaicPanelPointCreateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanelPoint photovoltaicPanelPoint = new FacPhotovoltaicPanelPoint(); + BeanUtils.copyProperties(req, photovoltaicPanelPoint); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanelPoint.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanelPoint, true); + // 判断是否存在同名光伏板桩点 + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanelPoint::getProjectId, photovoltaicPanelPoint.getProjectId()) + .eq(FacPhotovoltaicPanelPoint::getName, photovoltaicPanelPoint.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板桩点", HttpStatus.CONFLICT); + } + // 操作数据库 + boolean save = this.save(photovoltaicPanelPoint); + if (!save) { + throw new ServiceException("新增光伏板桩点失败,数据库异常", HttpStatus.ERROR); + } + return photovoltaicPanelPoint.getId(); + } + + /** + * 修改设施-光伏板桩点 + * + * @param req 设施-光伏板桩点 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FacPhotovoltaicPanelPointUpdateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanelPoint photovoltaicPanelPoint = new FacPhotovoltaicPanelPoint(); + BeanUtils.copyProperties(req, photovoltaicPanelPoint); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanelPoint.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanelPoint, false); + // 判断是否存在 + FacPhotovoltaicPanelPoint oldPhotovoltaicPanelPoint = this.getById(photovoltaicPanelPoint.getId()); + if (oldPhotovoltaicPanelPoint == null) { + throw new ServiceException("修改光伏板桩点失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断是否修改名称 + if (!oldPhotovoltaicPanelPoint.getName().equals(photovoltaicPanelPoint.getName())) { + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanelPoint::getProjectId, photovoltaicPanelPoint.getProjectId()) + .eq(FacPhotovoltaicPanelPoint::getName, photovoltaicPanelPoint.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板桩点", HttpStatus.CONFLICT); + } + } + // 操作数据库 + boolean update = this.updateById(photovoltaicPanelPoint); + if (!update) { + throw new ServiceException("修改光伏板桩点失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FacPhotovoltaicPanelPoint entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long matrixId = entity.getMatrixId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (matrixId == null) { + throw new ServiceException("方阵id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (matrixId != null && matrixService.getById(matrixId) == null) { + throw new ServiceException("对应方阵不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设施-光伏板桩点信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List photovoltaicPanelPointList = this.list(this.buildQueryWrapper(null)); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = photovoltaicPanelPointList.stream().map(FacPhotovoltaicPanelPoint::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-光伏板桩点视图对象 + * + * @param photovoltaicPanelPoint 设施-光伏板桩点对象 + * @return 设施-光伏板桩点视图对象 + */ + @Override + public FacPhotovoltaicPanelPointVo getVo(FacPhotovoltaicPanelPoint photovoltaicPanelPoint) { + // 对象转封装类 + FacPhotovoltaicPanelPointVo photovoltaicPanelPointVo = new FacPhotovoltaicPanelPointVo(); + if (photovoltaicPanelPoint == null) { + return photovoltaicPanelPointVo; + } + BeanUtils.copyProperties(photovoltaicPanelPoint, photovoltaicPanelPointVo); + // 将 JSON 字符串转化为 List + String positions = photovoltaicPanelPoint.getPositions(); + if (StringUtils.isNotBlank(positions)) { + List positionList = JSONUtil.toList(positions, String.class); + photovoltaicPanelPointVo.setPositionList(positionList); + } + return photovoltaicPanelPointVo; + } + + /** + * 获取设施-光伏板桩点查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelPointQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + String name = req.getName(); + String status = req.getStatus(); + String finishType = req.getFinishType(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), FacPhotovoltaicPanelPoint::getName, name); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacPhotovoltaicPanelPoint::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanelPoint::getMatrixId, matrixId); + lqw.eq(StringUtils.isNotBlank(status), FacPhotovoltaicPanelPoint::getStatus, status); + lqw.eq(StringUtils.isNotBlank(finishType), FacPhotovoltaicPanelPoint::getFinishType, finishType); + lqw.orderByAsc(FacPhotovoltaicPanelPoint::getName); + return lqw; + } + + /** + * 获取设施-光伏板桩点分页对象视图 + * + * @param photovoltaicPanelPointPage 设施-光伏板桩点分页对象 + * @return 设施-光伏板桩点分页对象视图 + */ + @Override + public Page getVoPage(Page photovoltaicPanelPointPage) { + List photovoltaicPanelPointList = photovoltaicPanelPointPage.getRecords(); + Page photovoltaicPanelPointVoPage = new Page<>( + photovoltaicPanelPointPage.getCurrent(), + photovoltaicPanelPointPage.getSize(), + photovoltaicPanelPointPage.getTotal()); + if (CollUtil.isEmpty(photovoltaicPanelPointList)) { + return photovoltaicPanelPointVoPage; + } + List photovoltaicPanelPointVoList = photovoltaicPanelPointList.stream().map(this::getVo).toList(); + photovoltaicPanelPointVoPage.setRecords(photovoltaicPanelPointVoList); + return photovoltaicPanelPointVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelServiceImpl.java new file mode 100644 index 0000000..49ddb23 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelServiceImpl.java @@ -0,0 +1,629 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.common.utils.JSTUtil; +import org.dromara.facility.constant.FacRedisKeyConstant; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.domain.FacPhotovoltaicPanel; +import org.dromara.facility.domain.dto.geojson.*; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateByGeoJsonReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelUpdateReq; +import org.dromara.facility.domain.enums.FacFinishStatusEnum; +import org.dromara.facility.domain.vo.photovoltaicpanel.FacPhotovoltaicPanelVo; +import org.dromara.facility.mapper.FacPhotovoltaicPanelMapper; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.facility.service.IFacPhotovoltaicPanelPartsService; +import org.dromara.facility.service.IFacPhotovoltaicPanelService; +import org.dromara.progress.constant.PgsProgressCategoryConstant; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 设施-光伏板Service业务层处理 + * + * @author lilemy + * @date 2025-04-21 + */ +@Slf4j +@Service +public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl + implements IFacPhotovoltaicPanelService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IFacMatrixService matrixService; + + @Lazy + @Resource + private IFacPhotovoltaicPanelPartsService photovoltaicPanelPartsService; + + @Resource + private IPgsProgressCategoryService progressCategoryService; + + @Resource + private RedisTemplate redisTemplate; + + @Resource + private ScheduledExecutorService scheduledExecutorService; + + @Lazy + @Resource + private FacPhotovoltaicPanelServiceImpl self; // 注入自己 + + /** + * 查询设施-光伏板 + * + * @param id 主键 + * @return 设施-光伏板 + */ + @Override + public FacPhotovoltaicPanelVo queryById(Long id) { + FacPhotovoltaicPanel photovoltaicPanel = this.getById(id); + if (photovoltaicPanel == null) { + throw new ServiceException("查询光伏板失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(photovoltaicPanel); + } + + /** + * 分页查询设施-光伏板列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板分页列表 + */ + @Override + public TableDataInfo queryPageList(FacPhotovoltaicPanelQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-光伏板列表 + * + * @param req 查询条件 + * @return 设施-光伏板列表 + */ + @Override + public List queryList(FacPhotovoltaicPanelQueryReq req) { + List photovoltaicPanelList = this.list(this.buildQueryWrapper(req)); + return photovoltaicPanelList.stream().map(this::getVo).toList(); + } + + /** + * 新增设施-光伏板 + * + * @param req 设施-光伏板 + * @return 新增光伏板id + */ + @Override + public Long insertByBo(FacPhotovoltaicPanelCreateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanel photovoltaicPanel = new FacPhotovoltaicPanel(); + BeanUtils.copyProperties(req, photovoltaicPanel); + // 将位置信息转换为 JSON 字符串 + List> positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanel.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanel, true); + // 判断是否存在同名光伏板 + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanel::getProjectId, photovoltaicPanel.getProjectId()) + .eq(FacPhotovoltaicPanel::getName, photovoltaicPanel.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板", HttpStatus.CONFLICT); + } + // 操作数据库 + boolean save = this.save(photovoltaicPanel); + if (!save) { + throw new ServiceException("新增光伏板失败,数据库异常", HttpStatus.ERROR); + } + return photovoltaicPanel.getId(); + } + + /** + * 新增光伏板 + * + * @param geoJson GeoJson格式 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByGeoJson(FacPhotovoltaicPanelCreateByGeoJsonReq geoJson) { + Long projectId = geoJson.getProjectId(); + // 判断 redis key 是否存在,存在则返回 + List operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId); + List list = redisTemplate.opsForValue().multiGet(operationRedisKey); + boolean hasValue = list != null && list.stream().anyMatch(Objects::nonNull); + if (hasValue) { + throw new ServiceException("项目下有设施数据正在处理中,请等待处理完毕后再操作", HttpStatus.BAD_REQUEST); + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 获取项目下方阵信息 + List matrixList = matrixService.lambdaQuery() + .select(FacMatrix::getId, FacMatrix::getPositions) + .eq(FacMatrix::getProjectId, projectId).list(); + if (CollUtil.isEmpty(matrixList)) { + throw new ServiceException("项目下无方阵数据,请先创建方阵信息后再添加光伏板信息", HttpStatus.NOT_FOUND); + } + // 获取 redis key + String sessionId = geoJson.getSessionId(); + int batchNum = geoJson.getBatchNum(); + int totalBatch = geoJson.getTotalBatch(); + // 获取所有光伏板位置信息 + List locationGeoJsonBatchList = geoJson.getLocationGeoJson(); + if (CollUtil.isNotEmpty(locationGeoJsonBatchList)) { + List locationFeaturesBatch = new ArrayList<>(); + for (FacGeoJsonByPlane geoJsonByPlane : locationGeoJsonBatchList) { + locationFeaturesBatch.addAll(geoJsonByPlane.getFeatures()); + } + // 存储到 Redis,设置过期时间 30 分钟 + String redisKeyByLocation = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, batchNum, FacRedisKeyConstant.GEO_TYPE_LOCAL); + redisTemplate.opsForValue().set(redisKeyByLocation, locationFeaturesBatch, 1800, TimeUnit.SECONDS); + } + // 获取所有对应名称的点 + List nameGeoJsonBatchList = geoJson.getNameGeoJson(); + if (CollUtil.isNotEmpty(nameGeoJsonBatchList)) { + List nameFeaturesBatch = new ArrayList<>(); + for (FacGeoJsonByPoint geoJsonByPoint : nameGeoJsonBatchList) { + nameFeaturesBatch.addAll(geoJsonByPoint.getFeatures()); + } + // 存储到 Redis,设置过期时间 30 分钟 + String redisKeyByName = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, batchNum, FacRedisKeyConstant.GEO_TYPE_NAME); + redisTemplate.opsForValue().set(redisKeyByName, nameFeaturesBatch, 1800, TimeUnit.SECONDS); + } + log.info("已接收第 {} 批数据,共 {} 批", batchNum, totalBatch); + Long userId = LoginHelper.getUserId(); + SseMessageDto messageDto = new SseMessageDto(); + messageDto.setUserIds(List.of(userId)); + // 如果是最后一批,开始合并 + if (batchNum == totalBatch) { + List locationFeatures = new ArrayList<>(); + List nameFeatures = new ArrayList<>(); + for (int i = 1; i <= totalBatch; i++) { + String batchKeyByLocation = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_LOCAL); + String batchKeyByName = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_NAME); + Object batchLocationObj = redisTemplate.opsForValue().get(batchKeyByLocation); + Object batchNameObj = redisTemplate.opsForValue().get(batchKeyByName); + if (batchLocationObj instanceof List) { + @SuppressWarnings("unchecked") + List batch = (List) batchLocationObj; + locationFeatures.addAll(batch); + } + if (batchNameObj instanceof List) { + @SuppressWarnings("unchecked") + List batch = (List) batchNameObj; + nameFeatures.addAll(batch); + } + } + // 设置 redis key,防止多次操作 + String operationPanelRedisKey = FacRedisKeyConstant.getPanelInOperationByProjectRedisKey(projectId); + redisTemplate.opsForValue().set(operationPanelRedisKey, true); + messageDto.setMessage("光伏板数据上传完毕,正在处理中"); + SseMessageUtils.publishMessage(messageDto); + scheduledExecutorService.execute(() -> { + try { + // 获取当下项目下光伏板的信息 + List oldPhotovoltaicPanelList = this.lambdaQuery() + .eq(FacPhotovoltaicPanel::getProjectId, projectId).list(); + Map photovoltaicPanelMap = oldPhotovoltaicPanelList.stream() + .collect(Collectors.toMap( + panel -> panel.getName() + "_" + panel.getProgressCategoryId(), + Function.identity(), + (existing, replacement) -> existing // 如果有重复,保留第一个 + )); + // 获取进度类别信息 + List progressCategoryList = progressCategoryService.lambdaQuery() + .in(PgsProgressCategory::getWorkType, PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE).list(); + Map> progressCategoryMap = progressCategoryList.stream() + .collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId)); + List allPanels = new ArrayList<>(); + List>> futures = new ArrayList<>(); + // 构建光伏板实体集合 + try (ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())) { + for (FacFeatureByPoint nameFeature : nameFeatures) { + Future> future = executorService.submit(() -> { + FacProperties nameProperties = nameFeature.getProperties(); + String name = nameProperties.getText(); + // ① 获取名称 + if (StringUtils.isBlank(name)) return Collections.emptyList(); + if (!name.startsWith("G")) return Collections.emptyList(); + List panelList = new ArrayList<>(); + // ② 找到该点对应的 polygon(优先包含,否则最近) + FacFeatureByPlane matchedPolygon = JSTUtil.findNearestOrContainingPolygon(nameFeature, locationFeatures); + if (matchedPolygon == null) return Collections.emptyList(); + // ③ 获取 geometry 坐标 + List> coordinates = matchedPolygon.getGeometry().getCoordinates().getFirst(); + // ④ 判断所属方阵 + FacMatrix matrix = matrixService.getMatrixIdBy2Coordinates(matrixList, coordinates); + if (matrix == null) return Collections.emptyList(); + Long matrixId = matrix.getId(); + // ⑤ 获取进度类别 + List progressCategoryListByMatrix = progressCategoryMap.get(matrixId); + if (CollUtil.isEmpty(progressCategoryListByMatrix)) return Collections.emptyList(); + + // ⑥ 构建面板数据 + for (PgsProgressCategory progressCategory : progressCategoryListByMatrix) { + FacPhotovoltaicPanel panel = new FacPhotovoltaicPanel(); + panel.setMatrixId(matrixId); + panel.setName(name); + panel.setProjectId(projectId); + panel.setPositions(JSONUtil.toJsonStr(coordinates)); + panel.setCreateBy(userId); + panel.setUpdateBy(userId); + String mapKey = name + "_" + progressCategory.getId(); + FacPhotovoltaicPanel oldPanel = photovoltaicPanelMap.get(mapKey); + if (oldPanel != null) { + panel.setStatus(oldPanel.getStatus()); + if (FacFinishStatusEnum.FINISH.getValue().equals(oldPanel.getStatus())) { + panel.setFinishType(oldPanel.getFinishType()); + panel.setFinishDate(oldPanel.getFinishDate()); + } + panel.setProgressCategoryId(oldPanel.getProgressCategoryId()); + panel.setProgressCategoryName(oldPanel.getProgressCategoryName()); + } else { + panel.setProgressCategoryId(progressCategory.getId()); + panel.setProgressCategoryName(progressCategory.getName()); + } + panelList.add(panel); + } + return panelList; + }); + futures.add(future); + } + // 等待所有结果 + for (Future> future : futures) { + try { + allPanels.addAll(future.get()); + } catch (Exception e) { + log.error("线程执行异常", e); + } + } + } + // 自定义线程池(IO 密集型线程池) + ThreadPoolExecutor customExecutor = new ThreadPoolExecutor( + 20, // 核心线程数 + 50, // 最大线程数 + 60L, // 线程空闲存活时间 + TimeUnit.SECONDS, // 存活时间单位 + new LinkedBlockingQueue<>(10000), // 阻塞队列容量 + new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用线程处理任务 + ); + // 分批处理,避免长事务,每次处理 1000 条数据 + int batchSize = 1000; + // 保存所有批次任务 + List> deleteFutures = new ArrayList<>(); + int deleteSize = oldPhotovoltaicPanelList.size(); + for (int i = 0; i < deleteSize; i += batchSize) { + int endIndex = Math.min(i + batchSize, deleteSize); + List batchList = oldPhotovoltaicPanelList.subList(i, endIndex); + // 使用事务处理每批数据 + // 获取代理 + FacPhotovoltaicPanelServiceImpl photovoltaicPanelService = self; + // 异步处理每批数据,将任务添加到异步任务列表 + CompletableFuture future = CompletableFuture.runAsync(() -> photovoltaicPanelService.deleteBatchInner(batchList), customExecutor); + deleteFutures.add(future); + } + // 等待所有批次完成操作 + CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0])).join(); + // 保存所有批次任务 + List> insertFutures = new ArrayList<>(); + int totalSize = allPanels.size(); + for (int i = 0; i < totalSize; i += batchSize) { + int endIndex = Math.min(i + batchSize, totalSize); + List batchList = allPanels.subList(i, endIndex); + // 使用事务处理每批数据 + // 获取代理 + FacPhotovoltaicPanelServiceImpl photovoltaicPanelService = self; + // 异步处理每批数据,将任务添加到异步任务列表 + CompletableFuture future = CompletableFuture.runAsync(() -> photovoltaicPanelService.insertBatchInner(batchList), customExecutor); + insertFutures.add(future); + } + // 等待所有批次完成操作 + CompletableFuture.allOf(insertFutures.toArray(new CompletableFuture[0])).join(); + // 关闭线程池 + customExecutor.shutdown(); + // 更新数量 + Map> countMap = allPanels + .stream().collect(Collectors.groupingBy(FacPhotovoltaicPanel::getProgressCategoryId)); + for (PgsProgressCategory progressCategory : progressCategoryList) { + Long progressCategoryId = progressCategory.getId(); + int total = 0; + if (countMap.containsKey(progressCategoryId)) { + total = countMap.get(progressCategoryId).size(); + } + progressCategory.setTotal(BigDecimal.valueOf(total)); + } + boolean result = progressCategoryService.updateBatchById(progressCategoryList); + if (!result) { + throw new ServiceException("更新进度类别失败,数据库异常", HttpStatus.ERROR); + } + messageDto.setMessage("光伏板数据处理完毕"); + SseMessageUtils.publishMessage(messageDto); + } catch (Exception e) { + messageDto.setMessage("光伏板数据处理失败,请联系管理员处理"); + SseMessageUtils.publishMessage(messageDto); + log.error("光伏板数据处理失败", e); + throw new ServiceException("光伏板数据处理失败", HttpStatus.ERROR); + } finally { + // 清理缓存 + for (int i = 1; i <= totalBatch; i++) { + String batchKeyByLocation = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_LOCAL); + String batchKeyByName = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_NAME); + redisTemplate.delete(batchKeyByLocation); + redisTemplate.delete(batchKeyByName); + } + redisTemplate.delete(operationPanelRedisKey); + } + }); + } + return true; + } + + /** + * 批量新增光伏板 + * + * @param photovoltaicPanelList 光伏板列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertBatchInner(List photovoltaicPanelList) { + try { + if (CollUtil.isNotEmpty(photovoltaicPanelList)) { + boolean result = this.saveBatch(photovoltaicPanelList); + if (!result) { + throw new ServiceException("批量新增光伏板失败,数据库异常", HttpStatus.ERROR); + } + } + } catch (DataIntegrityViolationException e) { + log.error("数据库唯一键冲突或违反其他完整性约束, 错误信息: {}", e.getMessage()); + throw new ServiceException("数据已存在,无法重复添加"); + } catch (DataAccessException e) { + log.error("数据库连接问题、事务问题等导致操作失败, 错误信息: {}", e.getMessage()); + throw new ServiceException("数据库操作失败"); + } catch (Exception e) { + // 捕获其他异常,做通用处理 + log.error("批量添加光伏板时发生未知错误,错误信息: {}", e.getMessage()); + throw new ServiceException("批量添加光伏板失败"); + } + } + + /** + * 批量删除光伏板 + * + * @param photovoltaicPanelList 光伏板列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBatchInner(List photovoltaicPanelList) { + try { + if (CollUtil.isNotEmpty(photovoltaicPanelList)) { + boolean result = this.removeBatchByIds(photovoltaicPanelList); + if (!result) { + throw new ServiceException("删除光伏板失败,数据库异常", HttpStatus.ERROR); + } + } + } catch (DataIntegrityViolationException e) { + log.error("数据库唯一键冲突或违反其他完整性约束: {}", e.getMessage()); + throw new ServiceException("数据已存在,无法重复添加"); + } catch (DataAccessException e) { + log.error("数据库连接问题、事务问题等导致操作失败: {}", e.getMessage()); + throw new ServiceException("数据库操作失败"); + } catch (Exception e) { + // 捕获其他异常,做通用处理 + log.error("批量删除光伏板时发生未知错误,错误信息: {}", e.getMessage()); + throw new ServiceException("批量添加光伏板失败"); + } + } + + /** + * 修改设施-光伏板 + * + * @param req 设施-光伏板 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FacPhotovoltaicPanelUpdateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanel photovoltaicPanel = new FacPhotovoltaicPanel(); + BeanUtils.copyProperties(req, photovoltaicPanel); + // 将位置信息转换为 JSON 字符串 + List> positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanel.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanel, false); + // 判断是否存在 + FacPhotovoltaicPanel oldPhotovoltaicPanel = this.getById(photovoltaicPanel.getId()); + if (oldPhotovoltaicPanel == null) { + throw new ServiceException("修改光伏板失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断是否修改名称 + if (!oldPhotovoltaicPanel.getName().equals(photovoltaicPanel.getName())) { + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanel::getProjectId, photovoltaicPanel.getProjectId()) + .eq(FacPhotovoltaicPanel::getName, photovoltaicPanel.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板", HttpStatus.CONFLICT); + } + } + // 操作数据库 + boolean update = this.updateById(photovoltaicPanel); + if (!update) { + throw new ServiceException("修改光伏板失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FacPhotovoltaicPanel entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long matrixId = entity.getMatrixId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (matrixId == null) { + throw new ServiceException("方阵id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (matrixId != null && matrixService.getById(matrixId) == null) { + throw new ServiceException("对应方阵不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设施-光伏板信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List photovoltaicPanelList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectIds = photovoltaicPanelList.stream().map(FacPhotovoltaicPanel::getProjectId).distinct().toList(); + if (CollUtil.isNotEmpty(projectIds) && projectIds.size() > 1) { + throw new ServiceException("仅能删除单个项目下的光伏板", HttpStatus.BAD_REQUEST); + } + Long projectId = projectIds.getFirst(); + projectService.validAuth(projectId, userId); + // 判断是否存在光伏板点信息 + List matrixNames = photovoltaicPanelList.stream().map(FacPhotovoltaicPanel::getName).toList(); + Boolean result = photovoltaicPanelPartsService.validPartsExistByPhotovoltaicPanel(projectId, matrixNames); + if (result) { + throw new ServiceException("删除失败,存在光伏板点信息", HttpStatus.CONFLICT); + } + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-光伏板视图对象 + * + * @param photovoltaicPanel 设施-光伏板对象 + * @return 设施-光伏板视图对象 + */ + @Override + public FacPhotovoltaicPanelVo getVo(FacPhotovoltaicPanel photovoltaicPanel) { + // 对象转封装类 + FacPhotovoltaicPanelVo photovoltaicPanelVo = new FacPhotovoltaicPanelVo(); + if (photovoltaicPanel == null) { + return photovoltaicPanelVo; + } + BeanUtils.copyProperties(photovoltaicPanel, photovoltaicPanelVo); + // 将 JSON 字符串转化为 List + String positions = photovoltaicPanel.getPositions(); + if (StringUtils.isNotBlank(positions)) { + List> positionList = new ArrayList<>(); + List arr = JSONUtil.toList(positions, String.class); + for (String s : arr) { + positionList.add(JSONUtil.toList(s, String.class)); + } + photovoltaicPanelVo.setPositionList(positionList); + } + return photovoltaicPanelVo; + } + + /** + * 获取设施-光伏板查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + String name = req.getName(); + String status = req.getStatus(); + String finishType = req.getFinishType(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), FacPhotovoltaicPanel::getName, name); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacPhotovoltaicPanel::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanel::getMatrixId, matrixId); + lqw.eq(StringUtils.isNotBlank(status), FacPhotovoltaicPanel::getStatus, status); + lqw.eq(StringUtils.isNotBlank(finishType), FacPhotovoltaicPanel::getFinishType, finishType); + lqw.orderByAsc(FacPhotovoltaicPanel::getName); + return lqw; + } + + /** + * 获取设施-光伏板分页对象视图 + * + * @param photovoltaicPanelPage 设施-光伏板分页对象 + * @return 设施-光伏板分页对象视图 + */ + @Override + public Page getVoPage(Page photovoltaicPanelPage) { + List photovoltaicPanelList = photovoltaicPanelPage.getRecords(); + Page photovoltaicPanelVoPage = new Page<>( + photovoltaicPanelPage.getCurrent(), + photovoltaicPanelPage.getSize(), + photovoltaicPanelPage.getTotal()); + if (CollUtil.isEmpty(photovoltaicPanelList)) { + return photovoltaicPanelVoPage; + } + List photovoltaicPanelVoList = photovoltaicPanelList.stream().map(this::getVo).toList(); + photovoltaicPanelVoPage.setRecords(photovoltaicPanelVoList); + return photovoltaicPanelVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelSupportServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelSupportServiceImpl.java new file mode 100644 index 0000000..d82adab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/facility/service/impl/FacPhotovoltaicPanelSupportServiceImpl.java @@ -0,0 +1,280 @@ +package org.dromara.facility.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.domain.FacPhotovoltaicPanelSupport; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportCreateReq; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportQueryReq; +import org.dromara.facility.domain.dto.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportUpdateReq; +import org.dromara.facility.domain.vo.photovoltaicpanelsupport.FacPhotovoltaicPanelSupportVo; +import org.dromara.facility.mapper.FacPhotovoltaicPanelSupportMapper; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.facility.service.IFacPhotovoltaicPanelSupportService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 设施-光伏板支架Service业务层处理 + * + * @author lilemy + * @date 2025-04-21 + */ +@Service +public class FacPhotovoltaicPanelSupportServiceImpl extends ServiceImpl + implements IFacPhotovoltaicPanelSupportService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IFacMatrixService matrixService; + + /** + * 查询设施-光伏板支架 + * + * @param id 主键 + * @return 设施-光伏板支架 + */ + @Override + public FacPhotovoltaicPanelSupportVo queryById(Long id) { + FacPhotovoltaicPanelSupport photovoltaicPanelSupport = this.getById(id); + if (photovoltaicPanelSupport == null) { + throw new ServiceException("查询光伏板支架失败,数据不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(photovoltaicPanelSupport); + } + + /** + * 分页查询设施-光伏板支架列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 设施-光伏板支架分页列表 + */ + @Override + public TableDataInfo queryPageList(FacPhotovoltaicPanelSupportQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的设施-光伏板支架列表 + * + * @param req 查询条件 + * @return 设施-光伏板支架列表 + */ + @Override + public List queryList(FacPhotovoltaicPanelSupportQueryReq req) { + List photovoltaicPanelSupportList = this.list(this.buildQueryWrapper(req)); + return photovoltaicPanelSupportList.stream().map(this::getVo).toList(); + } + + /** + * 新增设施-光伏板支架 + * + * @param req 设施-光伏板支架 + * @return 新增光伏板支架id + */ + @Override + public Long insertByBo(FacPhotovoltaicPanelSupportCreateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanelSupport photovoltaicPanelSupport = new FacPhotovoltaicPanelSupport(); + BeanUtils.copyProperties(req, photovoltaicPanelSupport); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanelSupport.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanelSupport, true); + // 判断是否存在同名光伏板支架 + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanelSupport::getProjectId, photovoltaicPanelSupport.getProjectId()) + .eq(FacPhotovoltaicPanelSupport::getName, photovoltaicPanelSupport.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板支架", HttpStatus.CONFLICT); + } + // 操作数据库 + boolean save = this.save(photovoltaicPanelSupport); + if (!save) { + throw new ServiceException("新增光伏板支架失败,数据库异常", HttpStatus.ERROR); + } + return photovoltaicPanelSupport.getId(); + } + + /** + * 修改设施-光伏板支架 + * + * @param req 设施-光伏板支架 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(FacPhotovoltaicPanelSupportUpdateReq req) { + // 将实体类和 DTO 进行转换 + FacPhotovoltaicPanelSupport photovoltaicPanelSupport = new FacPhotovoltaicPanelSupport(); + BeanUtils.copyProperties(req, photovoltaicPanelSupport); + // 将位置信息转换为 JSON 字符串 + List positionList = req.getPositionList(); + if (ObjectUtils.isNotEmpty(positionList)) { + String positionStr = JSONUtil.toJsonStr(positionList); + photovoltaicPanelSupport.setPositions(positionStr); + } + // 数据校验 + validEntityBeforeSave(photovoltaicPanelSupport, false); + // 判断是否存在 + FacPhotovoltaicPanelSupport oldPhotovoltaicPanelSupport = this.getById(photovoltaicPanelSupport.getId()); + if (oldPhotovoltaicPanelSupport == null) { + throw new ServiceException("修改光伏板支架失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断是否修改名称 + if (!oldPhotovoltaicPanelSupport.getName().equals(photovoltaicPanelSupport.getName())) { + Long count = this.lambdaQuery() + .eq(FacPhotovoltaicPanelSupport::getProjectId, photovoltaicPanelSupport.getProjectId()) + .eq(FacPhotovoltaicPanelSupport::getName, photovoltaicPanelSupport.getName()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名光伏板支架", HttpStatus.CONFLICT); + } + } + // 操作数据库 + boolean update = this.updateById(photovoltaicPanelSupport); + if (!update) { + throw new ServiceException("修改光伏板支架失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FacPhotovoltaicPanelSupport entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long matrixId = entity.getMatrixId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (matrixId == null) { + throw new ServiceException("方阵id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (matrixId != null && matrixService.getById(matrixId) == null) { + throw new ServiceException("对应方阵不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除设施-光伏板支架信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List photovoltaicPanelSupportList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = photovoltaicPanelSupportList.stream().map(FacPhotovoltaicPanelSupport::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取设施-光伏板支架视图对象 + * + * @param photovoltaicPanelSupport 设施-光伏板支架对象 + * @return 设施-光伏板支架视图对象 + */ + @Override + public FacPhotovoltaicPanelSupportVo getVo(FacPhotovoltaicPanelSupport photovoltaicPanelSupport) { + // 对象转封装类 + FacPhotovoltaicPanelSupportVo photovoltaicPanelSupportVo = new FacPhotovoltaicPanelSupportVo(); + if (photovoltaicPanelSupport == null) { + return photovoltaicPanelSupportVo; + } + BeanUtils.copyProperties(photovoltaicPanelSupport, photovoltaicPanelSupportVo); + // 将 JSON 字符串转化为 List + String positions = photovoltaicPanelSupport.getPositions(); + if (StringUtils.isNotBlank(positions)) { + List positionList = JSONUtil.toList(positions, String.class); + photovoltaicPanelSupportVo.setPositionList(positionList); + } + return photovoltaicPanelSupportVo; + } + + /** + * 获取设施-光伏板支架查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(FacPhotovoltaicPanelSupportQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + String name = req.getName(); + String status = req.getStatus(); + String finishType = req.getFinishType(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), FacPhotovoltaicPanelSupport::getName, name); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), FacPhotovoltaicPanelSupport::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), FacPhotovoltaicPanelSupport::getMatrixId, matrixId); + lqw.eq(StringUtils.isNotBlank(status), FacPhotovoltaicPanelSupport::getStatus, status); + lqw.eq(StringUtils.isNotBlank(finishType), FacPhotovoltaicPanelSupport::getFinishType, finishType); + lqw.orderByAsc(FacPhotovoltaicPanelSupport::getName); + return lqw; + } + + /** + * 获取设施-光伏板支架分页对象视图 + * + * @param photovoltaicPanelSupportPage 设施-光伏板支架分页对象 + * @return 设施-光伏板支架分页对象视图 + */ + @Override + public Page getVoPage(Page photovoltaicPanelSupportPage) { + List photovoltaicPanelSupportList = photovoltaicPanelSupportPage.getRecords(); + Page photovoltaicPanelSupportVoPage = new Page<>( + photovoltaicPanelSupportPage.getCurrent(), + photovoltaicPanelSupportPage.getSize(), + photovoltaicPanelSupportPage.getTotal()); + if (CollUtil.isEmpty(photovoltaicPanelSupportList)) { + return photovoltaicPanelSupportVoPage; + } + List photovoltaicPanelSupportVoList = photovoltaicPanelSupportList.stream().map(this::getVo).toList(); + photovoltaicPanelSupportVoPage.setRecords(photovoltaicPanelSupportVoList); + return photovoltaicPanelSupportVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/DeleteProjectCache.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/DeleteProjectCache.java new file mode 100644 index 0000000..53dd6f1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/DeleteProjectCache.java @@ -0,0 +1,52 @@ +package org.dromara.job.cycle; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.project.constant.BusProjectConstant; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.Set; + +/** + * 清理项目缓存 + * + * @author lilemy + * @date 2025/5/14 10:23 + */ +@Slf4j +@Component +public class DeleteProjectCache { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + // 每天凌晨 12 点执行 + @Scheduled(cron = "0 0 0 * * ?") + public void run() { + log.info("执行定时任务:清理项目缓存"); + // 构建扫描选项 + ScanOptions scanOptions = ScanOptions.scanOptions() + .match(BusProjectConstant.PROJECT_CACHE_REDIS_KEY_PREFIX + "*") + .count(1000) // 每次 scan 的数量 + .build(); + Set keysToDelete = new HashSet<>(); + Cursor cursor = stringRedisTemplate.getConnectionFactory() + .getConnection() + .scan(scanOptions); + while (cursor.hasNext()) { + keysToDelete.add(new String(cursor.next())); + } + // 批量删除 + if (!keysToDelete.isEmpty()) { + log.info("清理项目缓存,共 {} 条:{}", keysToDelete.size(), keysToDelete); + stringRedisTemplate.delete(keysToDelete); + } else { + log.info("没有需要清理的项目缓存"); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/DeleteYs7DeviceCapturePicData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/DeleteYs7DeviceCapturePicData.java new file mode 100644 index 0000000..823e6e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/DeleteYs7DeviceCapturePicData.java @@ -0,0 +1,39 @@ +package org.dromara.job.cycle; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.other.service.IOthYs7DeviceImgService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Date; + +/** + * 清理萤石设备抓拍图片数据 + * + * @author lilemy + * @date 2025/6/19 10:23 + */ +@Slf4j +@Component +public class DeleteYs7DeviceCapturePicData { + + @Resource + private IOthYs7DeviceImgService ys7DeviceImgService; + + @Scheduled(cron = "0 0 4 * * ?") + public void run() { + log.info("执行定时任务:清理萤石设备抓拍图片数据"); + // 构建扫描选项 + Date thirtyDaysAgo = DateUtils.toDate(LocalDateTime.now().minusDays(30)); + int deleteCount = ys7DeviceImgService.deleteByCreateTimeBefore(thirtyDaysAgo); + String formatDate = DateUtils.formatDateTime(thirtyDaysAgo); + if (deleteCount > 0) { + log.info("清理萤石设备抓拍图片数据完成,清理时间:{},删除了 {} 条数据", formatDate, deleteCount); + } else { + log.info("清理萤石设备抓拍图片数据完成,清理时间:{},没有数据需要清理", formatDate); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncValidProgressPlanIsDelay.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncValidProgressPlanIsDelay.java new file mode 100644 index 0000000..4a74e0b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncValidProgressPlanIsDelay.java @@ -0,0 +1,32 @@ +package org.dromara.job.cycle; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.progress.service.IPgsProgressPlanService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * 判断施工进度是否延期 + * + * @author lilemy + * @date 2025/5/29 9:38 + */ +@Slf4j +@Component +public class IncSyncValidProgressPlanIsDelay { + + @Resource + private IPgsProgressPlanService progressPlanService; + + // 每天凌晨 12 点执行 + @Scheduled(cron = "0 0 0 * * ?") + public void run() { + log.info("执行定时任务:判断施工进度是否延期"); + Boolean result = progressPlanService.validProgressPlanIsDelay(); + if (result) { + log.info("延期施工进度设置成功"); + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncYs7DeviceCapturePicData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncYs7DeviceCapturePicData.java new file mode 100644 index 0000000..46d54ef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncYs7DeviceCapturePicData.java @@ -0,0 +1,141 @@ +package org.dromara.job.cycle; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.manager.ys7manager.Ys7Manager; +import org.dromara.other.domain.OthDevicePreset; +import org.dromara.other.domain.OthYs7Device; +import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture; +import org.dromara.other.domain.enums.OthDeviceStatusEnum; +import org.dromara.other.service.IOthDevicePresetService; +import org.dromara.other.service.IOthYs7DeviceImgService; +import org.dromara.other.service.IOthYs7DeviceService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +/** + * 定时同步萤石设备图片数据 + * + * @author lilemy + * @date 2025/6/18 15:59 + */ +@Slf4j +//@Component +public class IncSyncYs7DeviceCapturePicData { + + @Resource + private IOthYs7DeviceService ys7DeviceService; + + @Resource + private IOthDevicePresetService devicePresetService; + + @Resource + private IOthYs7DeviceImgService ys7DeviceImgService; + + @Resource + private Ys7Manager ys7Manager; + + private final ExecutorService executorService = Executors.newFixedThreadPool(5); + + // 每 30 分钟执行一次 + @Scheduled(cron = "0 */30 7-19 * * ?") + public void run() { + // 查询所有在线的摄像头设备,仅获取必要字段 + List deviceList = ys7DeviceService.lambdaQuery() + .select(OthYs7Device::getId, OthYs7Device::getDeviceSerial, OthYs7Device::getDeviceName) + .eq(OthYs7Device::getStatus, OthDeviceStatusEnum.ONLINE.getValue()) + .list(); + // 提取设备序列号用于后续查询预置位 + List deviceSerialList = deviceList.stream() + .map(OthYs7Device::getDeviceSerial).toList(); + // 查询所有相关的摄像头预置位信息 + List presetList = devicePresetService.lambdaQuery() + .in(OthDevicePreset::getDeviceSerial, deviceSerialList) + .list(); + // 将预置位按设备序列号分组,便于后续查找 + Map> presetMap = presetList.stream() + .collect(Collectors.groupingBy(OthDevicePreset::getDeviceSerial)); + // 存储抓拍图片结果,使用线程安全的列表 + List imgList = Collections.synchronizedList(new ArrayList<>()); + // 用于等待所有子任务完成的计数器 + CountDownLatch latch = new CountDownLatch(deviceList.size()); + // 遍历每个摄像头设备进行处理 + for (OthYs7Device ys7Device : deviceList) { + executorService.submit(() -> { + try { + String deviceSerial = ys7Device.getDeviceSerial(); + List presets = presetMap.get(deviceSerial); + // 如果存在预置位,则遍历每个预置位进行抓图 + if (presets != null && !presets.isEmpty()) { + for (OthDevicePreset preset : presets) { + OthYs7DeviceImgCreateByCapture img = new OthYs7DeviceImgCreateByCapture(); + img.setProjectId(ys7Device.getProjectId()); + img.setDeviceSerial(deviceSerial); + img.setDeviceName(ys7Device.getDeviceName()); + int channelNo = preset.getChannelNo(); + int index = preset.getPresetIndex(); + // 调用摄像头移动到预置位 + boolean result = ys7Manager.moveDevicePreset(deviceSerial, channelNo, index); + if (!result) { + log.error("调用摄像头预置位失败:{}", deviceSerial); + continue; + } + // 等待摄像头转动到位 + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("线程中断", e); + } + // 抓取当前画面图片 + try { + String url = ys7Manager.getCaptureDevicePic(deviceSerial, channelNo, 2); + img.setCreateTime(new Date()); + img.setUrl(url); + imgList.add(img); + } catch (Exception e) { + log.error("摄像头 {} 通道:{},预置点序号:{},抓图失败:{}", deviceSerial, channelNo, index, e.getMessage()); + } + } + } else { + // 如果没有预置位,则直接对默认通道抓图 + OthYs7DeviceImgCreateByCapture img = new OthYs7DeviceImgCreateByCapture(); + img.setProjectId(ys7Device.getProjectId()); + img.setDeviceSerial(deviceSerial); + img.setDeviceName(ys7Device.getDeviceName()); + try { + String url = ys7Manager.getCaptureDevicePic(deviceSerial, 1, 2); + img.setCreateTime(new Date()); + img.setUrl(url); + imgList.add(img); + } catch (Exception e) { + log.error("摄像头 {} 抓图失败:{}", deviceSerial, e.getMessage()); + } + } + } catch (Exception ex) { + log.error("设备处理异常:{}", ys7Device.getDeviceSerial(), ex); + } finally { + // 不论成功与否,都减少计数器 + latch.countDown(); + } + }); + } + // 等待所有设备处理完成 + try { + latch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("主线程中断", e); + } + // 输出抓图结果日志 + log.info("获取图片完成,共 {} 张", imgList.size()); + ys7DeviceImgService.saveCapturePic(imgList); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncYs7DeviceData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncYs7DeviceData.java new file mode 100644 index 0000000..66e1aaf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/cycle/IncSyncYs7DeviceData.java @@ -0,0 +1,41 @@ +package org.dromara.job.cycle; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.manager.ys7manager.Ys7Manager; +import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; +import org.dromara.other.service.IOthYs7DeviceService; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.List; + +/** + * 定时同步摄像头设备数据 + * + * @author lilemy + * @date 2025/6/17 9:33 + */ +@Slf4j +//@Component +public class IncSyncYs7DeviceData { + + @Resource + private Ys7Manager ys7Manager; + + @Resource + private IOthYs7DeviceService ys7DeviceService; + + // 每 1 分钟执行一次 + @Scheduled(cron = "0 */1 * * * ?") + public void run() { + log.info("定时同步摄像头设备数据"); + List ys7QueryDeviceList = ys7Manager.queryAllDeviceList(); + Boolean result = ys7DeviceService.saveOrUpdateByDeviceList(ys7QueryDeviceList); + if (result) { + log.info("定时同步摄像头设备数据成功"); + } else { + log.info("没有需要定时同步的设备"); + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/once/FullSyncYs7DeviceData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/once/FullSyncYs7DeviceData.java new file mode 100644 index 0000000..0743e31 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/once/FullSyncYs7DeviceData.java @@ -0,0 +1,45 @@ +package org.dromara.job.once; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.manager.ys7manager.Ys7Manager; +import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; +import org.dromara.other.service.IOthYs7DeviceService; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 同步摄像头设备数据 + * + * @author lilemy + * @date 2025/6/13 11:08 + */ +@Slf4j +@Component +public class FullSyncYs7DeviceData implements CommandLineRunner { + + @Resource + private Ys7Manager ys7Manager; + + @Resource + private IOthYs7DeviceService ys7DeviceService; + + @Override + public void run(String... args) throws Exception { + log.info("开始同步摄像头设备数据"); + try { + List ys7QueryDeviceList = ys7Manager.queryAllDeviceList(); + Boolean result = ys7DeviceService.saveOrUpdateByDeviceList(ys7QueryDeviceList); + if (result) { + log.info("摄像头设备数据同步成功"); + } else { + log.info("没有需要同步的设备"); + } + } catch (Exception e) { + log.info("摄像头设备数据同步失败", e); + } + + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/controller/EqpMachineryController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/controller/EqpMachineryController.java new file mode 100644 index 0000000..0e03b30 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/controller/EqpMachineryController.java @@ -0,0 +1,119 @@ +package org.dromara.machinery.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryCreateReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryGisReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryQueryReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryUpdateReq; +import org.dromara.machinery.domain.vo.machinery.EqpMachineryVo; +import org.dromara.machinery.domain.vo.machinery.EqpMachineryGisVo; +import org.dromara.machinery.service.IEqpMachineryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 机械 + * + * @author lilemy + * @date 2025-03-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/machinery/machinery") +public class EqpMachineryController extends BaseController { + + private final IEqpMachineryService machineryService; + + /** + * 查询机械列表 + */ + @SaCheckPermission("machinery:machinery:list") + @GetMapping("/list") + public TableDataInfo list(EqpMachineryQueryReq req, PageQuery pageQuery) { + return machineryService.queryPageList(req, pageQuery); + } + + /** + * 导出机械列表 + */ + @SaCheckPermission("machinery:machinery:export") + @Log(title = "机械", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(EqpMachineryQueryReq req, HttpServletResponse response) { + List list = machineryService.queryList(req); + ExcelUtil.exportExcel(list, "机械", EqpMachineryVo.class, response); + } + + /** + * 查询大屏机械列表 + */ + @SaCheckPermission("machinery:machinery:list") + @GetMapping("/list/gis") + public R> queryGisList(EqpMachineryGisReq req) { + return R.ok(machineryService.queryGisList(req)); + } + + /** + * 获取机械详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("machinery:machinery:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(machineryService.queryById(id)); + } + + /** + * 新增机械 + */ + @SaCheckPermission("machinery:machinery:add") + @Log(title = "机械", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody EqpMachineryCreateReq req) { + return R.ok(machineryService.insertByBo(req)); + } + + /** + * 修改机械 + */ + @SaCheckPermission("machinery:machinery:edit") + @Log(title = "机械", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody EqpMachineryUpdateReq req) { + return toAjax(machineryService.updateByBo(req)); + } + + /** + * 删除机械 + * + * @param ids 主键串 + */ + @SaCheckPermission("machinery:machinery:remove") + @Log(title = "机械", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(machineryService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/controller/EqpMachineryDetailController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/controller/EqpMachineryDetailController.java new file mode 100644 index 0000000..051ca9f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/controller/EqpMachineryDetailController.java @@ -0,0 +1,108 @@ +package org.dromara.machinery.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailCreateReq; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailQueryReq; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailUpdateReq; +import org.dromara.machinery.domain.vo.machinerydetail.EqpMachineryDetailVo; +import org.dromara.machinery.service.IEqpMachineryDetailService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 机械详情 + * + * @author lilemy + * @date 2025-03-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/machinery/machineryDetail") +public class EqpMachineryDetailController extends BaseController { + + private final IEqpMachineryDetailService machineryDetailService; + + /** + * 查询机械详情列表 + */ + @SaCheckPermission("machinery:machineryDetail:list") + @GetMapping("/list") + public TableDataInfo list(EqpMachineryDetailQueryReq req, PageQuery pageQuery) { + return machineryDetailService.queryPageList(req, pageQuery); + } + + /** + * 导出机械详情列表 + */ + @SaCheckPermission("machinery:machineryDetail:export") + @Log(title = "机械详情", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(EqpMachineryDetailQueryReq req, HttpServletResponse response) { + List list = machineryDetailService.queryList(req); + ExcelUtil.exportExcel(list, "机械详情", EqpMachineryDetailVo.class, response); + } + + /** + * 获取机械详情详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("machinery:machineryDetail:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(machineryDetailService.queryById(id)); + } + + /** + * 新增机械详情 + */ + @SaCheckPermission("machinery:machineryDetail:add") + @Log(title = "机械详情", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody EqpMachineryDetailCreateReq req) { + return R.ok(machineryDetailService.insertByBo(req)); + } + + /** + * 修改机械详情 + */ + @SaCheckPermission("machinery:machineryDetail:edit") + @Log(title = "机械详情", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody EqpMachineryDetailUpdateReq req) { + return toAjax(machineryDetailService.updateByBo(req)); + } + + /** + * 删除机械详情 + * + * @param ids 主键串 + */ + @SaCheckPermission("machinery:machineryDetail:remove") + @Log(title = "机械详情", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(machineryDetailService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/EqpMachinery.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/EqpMachinery.java new file mode 100644 index 0000000..219692e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/EqpMachinery.java @@ -0,0 +1,71 @@ +package org.dromara.machinery.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 机械对象 eqp_machinery + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("eqp_machinery") +public class EqpMachinery extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 机械名称 + */ + private String machineryName; + + /** + * 机械型号 + */ + private String machineryNumber; + + /** + * 项目id + */ + private Long projectId; + + /** + * 数量 + */ + private Long number; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 供应商 + */ + private String provider; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/EqpMachineryDetail.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/EqpMachineryDetail.java new file mode 100644 index 0000000..a47b3e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/EqpMachineryDetail.java @@ -0,0 +1,77 @@ +package org.dromara.machinery.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 机械详情对象 eqp_machinery_detail + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("eqp_machinery_detail") +public class EqpMachineryDetail extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 检验证编号 + */ + private String checkoutNumber; + + /** + * 检验单位 + */ + private String checkoutUnit; + + /** + * 检定日期/有效期 + */ + private String checkoutDate; + + /** + * 施工类型状态(0正常 1停用) + */ + private String status; + + /** + * 0入场 1出场 + */ + private String type; + + /** + * 入场时间 + */ + private Date entryTime; + + /** + * 备注 + */ + private String remark; + + /** + * 图片(英文逗号分隔) + */ + private String picture; + + /** + * 机械主键id + */ + private Long machineryId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryCreateReq.java new file mode 100644 index 0000000..5d70a3a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryCreateReq.java @@ -0,0 +1,58 @@ +package org.dromara.machinery.domain.dto.machinery; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class EqpMachineryCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 机械名称 + */ + private String machineryName; + + /** + * 机械型号 + */ + private String machineryNumber; + + /** + * 项目id + */ + private Long projectId; + + /** + * 数量 + */ + private Long number; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 供应商 + */ + private String provider; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryGisReq.java new file mode 100644 index 0000000..eaad847 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryGisReq.java @@ -0,0 +1,25 @@ +package org.dromara.machinery.domain.dto.machinery; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 10:26 + */ +@Data +public class EqpMachineryGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5157791260034938544L; + + /** + * 项目主键 + */ + @NotNull(message = "项目主键不能为空") + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryQueryReq.java new file mode 100644 index 0000000..e9b41fa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryQueryReq.java @@ -0,0 +1,63 @@ +package org.dromara.machinery.domain.dto.machinery; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class EqpMachineryQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3252651952758479341L; + + /** + * 主键id + */ + private Long id; + + /** + * 机械名称 + */ + private String machineryName; + + /** + * 机械型号 + */ + private String machineryNumber; + + /** + * 项目id + */ + private Long projectId; + + /** + * 数量 + */ + private Long number; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 供应商 + */ + private String provider; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryUpdateReq.java new file mode 100644 index 0000000..ba1b1e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinery/EqpMachineryUpdateReq.java @@ -0,0 +1,63 @@ +package org.dromara.machinery.domain.dto.machinery; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class EqpMachineryUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8022860866890925958L; + + /** + * 主键id + */ + private Long id; + + /** + * 机械名称 + */ + private String machineryName; + + /** + * 机械型号 + */ + private String machineryNumber; + + /** + * 项目id + */ + private Long projectId; + + /** + * 数量 + */ + private Long number; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 供应商 + */ + private String provider; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailCreateReq.java new file mode 100644 index 0000000..542aa90 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailCreateReq.java @@ -0,0 +1,64 @@ +package org.dromara.machinery.domain.dto.machinerydetail; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class EqpMachineryDetailCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 检验证编号 + */ + private String checkoutNumber; + + /** + * 检验单位 + */ + private String checkoutUnit; + + /** + * 检定日期/有效期 + */ + private String checkoutDate; + + /** + * 施工类型状态(0正常 1停用) + */ + private String status; + + /** + * 0入场 1出场 + */ + private String type; + + /** + * 入场时间 + */ + private Date entryTime; + + /** + * 备注 + */ + private String remark; + + /** + * 图片(英文逗号分隔) + */ + private String picture; + + /** + * 机械主键id + */ + private Long machineryId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailQueryReq.java new file mode 100644 index 0000000..c6d60c5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailQueryReq.java @@ -0,0 +1,64 @@ +package org.dromara.machinery.domain.dto.machinerydetail; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class EqpMachineryDetailQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3252651952758479341L; + + /** + * 主键id + */ + private Long id; + + /** + * 检验证编号 + */ + private String checkoutNumber; + + /** + * 检验单位 + */ + private String checkoutUnit; + + /** + * 检定日期/有效期 + */ + private String checkoutDate; + + /** + * 施工类型状态(0正常 1停用) + */ + private String status; + + /** + * 0入场 1出场 + */ + private String type; + + /** + * 入场时间 + */ + private Date entryTime; + + /** + * 备注 + */ + private String remark; + + /** + * 机械主键id + */ + private Long machineryId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailUpdateReq.java new file mode 100644 index 0000000..9dd1cdd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/dto/machinerydetail/EqpMachineryDetailUpdateReq.java @@ -0,0 +1,69 @@ +package org.dromara.machinery.domain.dto.machinerydetail; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class EqpMachineryDetailUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8022860866890925958L; + + /** + * 主键id + */ + private Long id; + + /** + * 检验证编号 + */ + private String checkoutNumber; + + /** + * 检验单位 + */ + private String checkoutUnit; + + /** + * 检定日期/有效期 + */ + private String checkoutDate; + + /** + * 施工类型状态(0正常 1停用) + */ + private String status; + + /** + * 0入场 1出场 + */ + private String type; + + /** + * 入场时间 + */ + private Date entryTime; + + /** + * 备注 + */ + private String remark; + + /** + * 图片(英文逗号分隔) + */ + private String picture; + + /** + * 机械主键id + */ + private Long machineryId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/enums/EqpMachineryDetailTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/enums/EqpMachineryDetailTypeEnum.java new file mode 100644 index 0000000..de6b127 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/enums/EqpMachineryDetailTypeEnum.java @@ -0,0 +1,24 @@ +package org.dromara.machinery.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/30 15:29 + */ +@Getter +public enum EqpMachineryDetailTypeEnum { + + PUT("入场", "0"), + OUT("出场", "1"); + + private final String text; + + private final String value; + + EqpMachineryDetailTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinery/EqpMachineryGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinery/EqpMachineryGisVo.java new file mode 100644 index 0000000..e164271 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinery/EqpMachineryGisVo.java @@ -0,0 +1,28 @@ +package org.dromara.machinery.domain.vo.machinery; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 10:27 + */ +@Data +public class EqpMachineryGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -724470814094084721L; + + /** + * 机械名称 + */ + private String machineryName; + + /** + * 机械数量 + */ + private Long machineryCount; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinery/EqpMachineryVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinery/EqpMachineryVo.java new file mode 100644 index 0000000..f6ce15d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinery/EqpMachineryVo.java @@ -0,0 +1,88 @@ +package org.dromara.machinery.domain.vo.machinery; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.machinery.domain.EqpMachinery; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 机械视图对象 eqp_machinery + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = EqpMachinery.class) +public class EqpMachineryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 机械名称 + */ + @ExcelProperty(value = "机械名称") + private String machineryName; + + /** + * 机械型号 + */ + @ExcelProperty(value = "机械型号") + private String machineryNumber; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 数量 + */ + @ExcelProperty(value = "数量") + private Long number; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String principal; + + /** + * 负责人电话 + */ + @ExcelProperty(value = "负责人电话") + private String principalPhone; + + /** + * 供应商 + */ + @ExcelProperty(value = "供应商") + private String provider; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinerydetail/EqpMachineryDetailVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinerydetail/EqpMachineryDetailVo.java new file mode 100644 index 0000000..5c5a7df --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/domain/vo/machinerydetail/EqpMachineryDetailVo.java @@ -0,0 +1,104 @@ +package org.dromara.machinery.domain.vo.machinerydetail; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.machinery.domain.EqpMachineryDetail; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 机械详情视图对象 eqp_machinery_detail + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = EqpMachineryDetail.class) +public class EqpMachineryDetailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 检验证编号 + */ + @ExcelProperty(value = "检验证编号") + private String checkoutNumber; + + /** + * 检验单位 + */ + @ExcelProperty(value = "检验单位") + private String checkoutUnit; + + /** + * 检定日期/有效期 + */ + @ExcelProperty(value = "检定日期/有效期") + private String checkoutDate; + + /** + * 施工类型状态(0正常 1停用) + */ + @ExcelProperty(value = "施工类型状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 0入场 1出场 + */ + @ExcelProperty(value = "0入场 1出场") + private String type; + + /** + * 入场时间 + */ + @ExcelProperty(value = "入场时间") + private Date entryTime; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 图片(英文逗号分隔) + */ + @ExcelProperty(value = "图片(英文逗号分隔)") + private String picture; + + /** + * 图片详情列表 + */ + private List pictureList; + + /** + * 机械主键id + */ + @ExcelProperty(value = "机械主键id") + private Long machineryId; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/mapper/EqpMachineryDetailMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/mapper/EqpMachineryDetailMapper.java new file mode 100644 index 0000000..e23be33 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/mapper/EqpMachineryDetailMapper.java @@ -0,0 +1,15 @@ +package org.dromara.machinery.mapper; + +import org.dromara.machinery.domain.EqpMachineryDetail; +import org.dromara.machinery.domain.vo.machinerydetail.EqpMachineryDetailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 机械详情Mapper接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface EqpMachineryDetailMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/mapper/EqpMachineryMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/mapper/EqpMachineryMapper.java new file mode 100644 index 0000000..670e8de --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/mapper/EqpMachineryMapper.java @@ -0,0 +1,15 @@ +package org.dromara.machinery.mapper; + +import org.dromara.machinery.domain.EqpMachinery; +import org.dromara.machinery.domain.vo.machinery.EqpMachineryVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 机械Mapper接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface EqpMachineryMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/IEqpMachineryDetailService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/IEqpMachineryDetailService.java new file mode 100644 index 0000000..0d4ce95 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/IEqpMachineryDetailService.java @@ -0,0 +1,98 @@ +package org.dromara.machinery.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.machinery.domain.EqpMachineryDetail; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailCreateReq; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailQueryReq; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailUpdateReq; +import org.dromara.machinery.domain.vo.machinerydetail.EqpMachineryDetailVo; + +import java.util.Collection; +import java.util.List; + +/** + * 机械详情Service接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface IEqpMachineryDetailService extends IService { + + /** + * 查询机械详情 + * + * @param id 主键 + * @return 机械详情 + */ + EqpMachineryDetailVo queryById(Long id); + + /** + * 分页查询机械详情列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 机械详情分页列表 + */ + TableDataInfo queryPageList(EqpMachineryDetailQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的机械详情列表 + * + * @param req 查询条件 + * @return 机械详情列表 + */ + List queryList(EqpMachineryDetailQueryReq req); + + /** + * 新增机械详情 + * + * @param req 机械详情 + * @return 是否新增成功 + */ + Long insertByBo(EqpMachineryDetailCreateReq req); + + /** + * 修改机械详情 + * + * @param req 机械详情 + * @return 是否修改成功 + */ + Boolean updateByBo(EqpMachineryDetailUpdateReq req); + + /** + * 校验并批量删除机械详情信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取机械详情视图对象 + * + * @param machineryDetail 机械详情对象 + * @return 机械详情视图对象 + */ + EqpMachineryDetailVo getVo(EqpMachineryDetail machineryDetail); + + /** + * 获取机械详情查询条件封装 + * + * @param req 机械详情查询条件 + * @return 机械详情查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(EqpMachineryDetailQueryReq req); + + /** + * 获取机械详情分页对象视图 + * + * @param machineryDetailPage 机械详情分页对象 + * @return 机械详情分页对象视图 + */ + Page getVoPage(Page machineryDetailPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/IEqpMachineryService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/IEqpMachineryService.java new file mode 100644 index 0000000..378f690 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/IEqpMachineryService.java @@ -0,0 +1,108 @@ +package org.dromara.machinery.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.machinery.domain.EqpMachinery; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryCreateReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryGisReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryQueryReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryUpdateReq; +import org.dromara.machinery.domain.vo.machinery.EqpMachineryVo; +import org.dromara.machinery.domain.vo.machinery.EqpMachineryGisVo; + +import java.util.Collection; +import java.util.List; + +/** + * 机械Service接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface IEqpMachineryService extends IService { + + /** + * 查询机械 + * + * @param id 主键 + * @return 机械 + */ + EqpMachineryVo queryById(Long id); + + /** + * 分页查询机械列表 + * + * @param req 查询条件 + * @param pageQuery 分页条件 + * @return 机械分页列表 + */ + TableDataInfo queryPageList(EqpMachineryQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的机械列表 + * + * @param req 查询条件 + * @return 机械列表 + */ + List queryList(EqpMachineryQueryReq req); + + /** + * 查询机械大屏数据列表 + * + * @param req 筛选条件 + * @return 大屏数据列表 + */ + List queryGisList(EqpMachineryGisReq req); + + /** + * 新增机械 + * + * @param req 机械 + * @return 新增机械id + */ + Long insertByBo(EqpMachineryCreateReq req); + + /** + * 修改机械 + * + * @param req 机械 + * @return 是否修改成功 + */ + Boolean updateByBo(EqpMachineryUpdateReq req); + + /** + * 校验并批量删除机械信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取机械视图对象 + * + * @param machinery 机械对象 + * @return 机械视图对象 + */ + EqpMachineryVo getVo(EqpMachinery machinery); + + /** + * 获取机械查询条件封装 + * + * @param req 机械查询条件 + * @return 机械查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(EqpMachineryQueryReq req); + + /** + * 获取机械分页对象视图 + * + * @param machineryPage 机械分页对象 + * @return 机械分页对象视图 + */ + Page getVoPage(Page machineryPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/impl/EqpMachineryDetailServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/impl/EqpMachineryDetailServiceImpl.java new file mode 100644 index 0000000..698c10d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/impl/EqpMachineryDetailServiceImpl.java @@ -0,0 +1,304 @@ +package org.dromara.machinery.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.machinery.domain.EqpMachinery; +import org.dromara.machinery.domain.EqpMachineryDetail; +import org.dromara.machinery.domain.enums.EqpMachineryDetailTypeEnum; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailCreateReq; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailQueryReq; +import org.dromara.machinery.domain.dto.machinerydetail.EqpMachineryDetailUpdateReq; +import org.dromara.machinery.domain.vo.machinerydetail.EqpMachineryDetailVo; +import org.dromara.machinery.mapper.EqpMachineryDetailMapper; +import org.dromara.machinery.service.IEqpMachineryDetailService; +import org.dromara.machinery.service.IEqpMachineryService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +/** + * 机械详情Service业务层处理 + * + * @author lilemy + * @date 2025-03-07 + */ +@Service +public class EqpMachineryDetailServiceImpl extends ServiceImpl + implements IEqpMachineryDetailService { + + @Resource + private IEqpMachineryService machineryService; + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + /** + * 查询机械详情 + * + * @param id 主键 + * @return 机械详情 + */ + @Override + public EqpMachineryDetailVo queryById(Long id) { + EqpMachineryDetail machineryDetail = this.getById(id); + if (machineryDetail == null) { + throw new ServiceException("机械详情信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(machineryDetail); + } + + /** + * 分页查询机械详情列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 机械详情分页列表 + */ + @Override + public TableDataInfo queryPageList(EqpMachineryDetailQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的机械详情列表 + * + * @param req 查询条件 + * @return 机械详情列表 + */ + @Override + public List queryList(EqpMachineryDetailQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + List list = this.list(lqw); + return list.stream().map(this::getVo).toList(); + } + + /** + * 新增机械详情 + * + * @param req 机械详情 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(EqpMachineryDetailCreateReq req) { + // 将实体类和 DTO 进行转换 + EqpMachineryDetail machineryDetail = new EqpMachineryDetail(); + BeanUtils.copyProperties(req, machineryDetail); + // 数据校验 + req.setType(EqpMachineryDetailTypeEnum.PUT.getValue()); + validEntityBeforeSave(machineryDetail); + // 判断是否存在 + Long count = this.lambdaQuery() + .eq(EqpMachineryDetail::getCheckoutNumber, req.getCheckoutNumber()) + .count(); + if (count > 0) { + throw new ServiceException("该编号机械已存在", HttpStatus.BAD_REQUEST); + } + // 操作数据库 + boolean save = this.save(machineryDetail); + if (!save) { + throw new ServiceException("新增机械详情失败,数据库异常", HttpStatus.ERROR); + } + // 修改机械数量 + LambdaUpdateWrapper lqw = new LambdaUpdateWrapper<>(); + lqw.eq(EqpMachinery::getId, machineryDetail.getMachineryId()); + lqw.setSql("number = number + 1"); + boolean update = machineryService.update(lqw); + if (!update) { + throw new ServiceException("修改机械数量失败,数据库异常", HttpStatus.ERROR); + } + return machineryDetail.getId(); + } + + /** + * 修改机械详情 + * + * @param req 机械详情 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(EqpMachineryDetailUpdateReq req) { + // 将实体类和 DTO 进行转换 + EqpMachineryDetail machineryDetail = new EqpMachineryDetail(); + BeanUtils.copyProperties(req, machineryDetail); + // 数据校验 + validEntityBeforeSave(machineryDetail); + // 判断是否存在 + EqpMachineryDetail oldMachineryDetail = this.getById(machineryDetail.getId()); + if (oldMachineryDetail == null) { + throw new ServiceException("修改机械详情失败,数据不存在", HttpStatus.NOT_FOUND); + } + String type = req.getType(); + Long machineryId = machineryDetail.getMachineryId(); + if (!type.equals(oldMachineryDetail.getType())) { + if (EqpMachineryDetailTypeEnum.PUT.getValue().equals(type)) { + LambdaUpdateWrapper lqw = new LambdaUpdateWrapper<>(); + lqw.eq(EqpMachinery::getId, machineryId); + lqw.setSql("number = number + 1"); + boolean update = machineryService.update(lqw); + if (!update) { + throw new ServiceException("修改机械数量失败,数据库异常", HttpStatus.ERROR); + } + } else if (EqpMachineryDetailTypeEnum.OUT.getValue().equals(type)) { + LambdaUpdateWrapper lqw = new LambdaUpdateWrapper<>(); + lqw.eq(EqpMachinery::getId, machineryId); + lqw.setSql("number = number - 1"); + boolean update = machineryService.update(lqw); + if (!update) { + throw new ServiceException("修改机械数量失败,数据库异常", HttpStatus.ERROR); + } + } + } + // 操作数据库 + return this.updateById(machineryDetail); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(EqpMachineryDetail entity) { + // 做一些数据校验,如唯一约束 + Long machineryId = entity.getMachineryId(); + if (machineryId == null) { + throw new ServiceException("机械 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (machineryService.getById(machineryId) == null) { + throw new ServiceException("对应机械不存在", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除机械详情信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List machineryDetailList = this.listByIds(ids); + // 做一些业务上的校验,判断是否需要校验 + if (isValid) { + // 获取机械id列表 + List machineryIdList = machineryDetailList.stream().map(EqpMachineryDetail::getMachineryId).toList(); + List machineryList = machineryService.listByIds(machineryIdList); + // 获取对应项目id列表 + List projectIdList = machineryList.stream().map(EqpMachinery::getProjectId).toList(); + projectService.validAuth(projectIdList, userId); + } + if (machineryDetailList.size() != ids.size()) { + throw new ServiceException("删除机械详情失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取机械详情视图对象 + * + * @param machineryDetail 机械详情对象 + * @return 机械详情视图对象 + */ + @Override + public EqpMachineryDetailVo getVo(EqpMachineryDetail machineryDetail) { + // 对象转封装类 + EqpMachineryDetailVo machineryDetailVo = new EqpMachineryDetailVo(); + if (machineryDetail == null) { + return machineryDetailVo; + } + BeanUtils.copyProperties(machineryDetail, machineryDetailVo); + // 获取图片信息 + String picture = machineryDetail.getPicture(); + if (StringUtils.isNotEmpty(picture)) { + List picList = Arrays.stream(picture.split(",")) + .map(Long::parseLong) + .toList(); + List pictureList = ossService.listByIds(picList); + machineryDetailVo.setPictureList(pictureList); + } + return machineryDetailVo; + } + + /** + * 获取机械详情查询条件封装 + * + * @param req 机械详情查询条件 + * @return 机械详情查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(EqpMachineryDetailQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + String checkoutNumber = req.getCheckoutNumber(); + String checkoutUnit = req.getCheckoutUnit(); + String checkoutDate = req.getCheckoutDate(); + String status = req.getStatus(); + String type = req.getType(); + Date entryTime = req.getEntryTime(); + String remark = req.getRemark(); + Long machineryId = req.getMachineryId(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(checkoutNumber), EqpMachineryDetail::getCheckoutNumber, checkoutNumber); + lqw.like(StringUtils.isNotBlank(checkoutUnit), EqpMachineryDetail::getCheckoutUnit, checkoutUnit); + lqw.like(StringUtils.isNotBlank(checkoutDate), EqpMachineryDetail::getCheckoutDate, checkoutDate); + lqw.like(StringUtils.isNotBlank(remark), EqpMachineryDetail::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), EqpMachineryDetail::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(status), EqpMachineryDetail::getStatus, status); + lqw.eq(ObjectUtils.isNotEmpty(type), EqpMachineryDetail::getType, type); + lqw.eq(ObjectUtils.isNotEmpty(entryTime), EqpMachineryDetail::getEntryTime, entryTime); + lqw.eq(ObjectUtils.isNotEmpty(machineryId), EqpMachineryDetail::getMachineryId, machineryId); + return lqw; + } + + /** + * 获取机械详情分页对象视图 + * + * @param machineryDetailPage 机械详情分页对象 + * @return 机械详情分页对象视图 + */ + @Override + public Page getVoPage(Page machineryDetailPage) { + List machineryDetailList = machineryDetailPage.getRecords(); + Page machineryDetailVoPage = new Page<>( + machineryDetailPage.getCurrent(), + machineryDetailPage.getSize(), + machineryDetailPage.getTotal()); + if (CollUtil.isEmpty(machineryDetailList)) { + return machineryDetailVoPage; + } + List machineryDetailVoList = machineryDetailList.stream().map(this::getVo).toList(); + machineryDetailVoPage.setRecords(machineryDetailVoList); + return machineryDetailVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/impl/EqpMachineryServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/impl/EqpMachineryServiceImpl.java new file mode 100644 index 0000000..4b4eb50 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/machinery/service/impl/EqpMachineryServiceImpl.java @@ -0,0 +1,302 @@ +package org.dromara.machinery.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.PhoneUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.machinery.domain.EqpMachinery; +import org.dromara.machinery.domain.EqpMachineryDetail; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryCreateReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryGisReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryQueryReq; +import org.dromara.machinery.domain.dto.machinery.EqpMachineryUpdateReq; +import org.dromara.machinery.domain.vo.machinery.EqpMachineryVo; +import org.dromara.machinery.domain.vo.machinery.EqpMachineryGisVo; +import org.dromara.machinery.mapper.EqpMachineryMapper; +import org.dromara.machinery.service.IEqpMachineryDetailService; +import org.dromara.machinery.service.IEqpMachineryService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 机械Service业务层处理 + * + * @author lilemy + * @date 2025-03-07 + */ +@Service +public class EqpMachineryServiceImpl extends ServiceImpl + implements IEqpMachineryService { + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private IEqpMachineryDetailService machineryDetailService; + + /** + * 查询机械 + * + * @param id 主键 + * @return 机械 + */ + @Override + public EqpMachineryVo queryById(Long id) { + EqpMachinery machinery = this.getById(id); + if (machinery == null) { + throw new ServiceException("机械信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(machinery); + } + + /** + * 分页查询机械列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 机械分页列表 + */ + @Override + public TableDataInfo queryPageList(EqpMachineryQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的机械列表 + * + * @param req 查询条件 + * @return 机械列表 + */ + @Override + public List queryList(EqpMachineryQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + List list = this.list(lqw); + return list.stream().map(this::getVo).toList(); + } + + /** + * 查询机械大屏数据列表 + * + * @param req 筛选条件 + * @return 大屏数据列表 + */ + @Override + public List queryGisList(EqpMachineryGisReq req) { + Long projectId = req.getProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + List list = this.lambdaQuery() + .eq(EqpMachinery::getProjectId, projectId).list(); + return list.stream().map(machinery -> { + EqpMachineryGisVo machineryGisVo = new EqpMachineryGisVo(); + machineryGisVo.setMachineryName(machinery.getMachineryName()); + machineryGisVo.setMachineryCount(machinery.getNumber()); + return machineryGisVo; + }).toList(); + } + + /** + * 新增机械 + * + * @param req 机械 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(EqpMachineryCreateReq req) { + // 将实体类和 DTO 进行转换 + EqpMachinery machinery = new EqpMachinery(); + BeanUtils.copyProperties(req, machinery); + // 数据校验 + validEntityBeforeSave(machinery, true); + // 操作数据库 + boolean save = this.save(machinery); + if (!save) { + throw new ServiceException("新增机械失败,数据库异常", HttpStatus.ERROR); + } + return machinery.getId(); + } + + /** + * 修改机械 + * + * @param req 机械 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(EqpMachineryUpdateReq req) { + // 将实体类和 DTO 进行转换 + EqpMachinery machinery = new EqpMachinery(); + BeanUtils.copyProperties(req, machinery); + // 数据校验 + validEntityBeforeSave(machinery, false); + // 判断是否存在 + EqpMachinery oldMachinery = this.getById(machinery.getId()); + if (oldMachinery == null) { + throw new ServiceException("修改机械失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(machinery); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(EqpMachinery entity, Boolean create) { + // 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + String machineryName = entity.getMachineryName(); + String principal = entity.getPrincipal(); + String principalPhone = entity.getPrincipalPhone(); + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (create) { + if (StrUtil.isBlank(machineryName)) { + throw new ServiceException("机械名称不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(principal)) { + throw new ServiceException("负责人不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(principalPhone)) { + throw new ServiceException("负责人手机号不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (StringUtils.isNotBlank(principalPhone) && !PhoneUtil.isPhone(principalPhone)) { + throw new ServiceException("负责人手机号格式不正确", HttpStatus.BAD_REQUEST); + } + // 判断用户是否对项目下的内容有操作权限 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(projectId, userId); + } + + /** + * 校验并批量删除机械信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List machineryList = this.listByIds(ids); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + // 获取项目id列表 + List projectIdList = machineryList.stream().map(EqpMachinery::getProjectId).toList(); + // 判断是否有权限操作对应项目下的内容 + projectService.validAuth(projectIdList, userId); + // 判断是否还存在机械详情信息 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("machinery_id", ids); + if (machineryDetailService.count(queryWrapper) > 0) { + throw new ServiceException("删除机械失败,机械存在机械详情信息", HttpStatus.BAD_REQUEST); + } + } + if (machineryList.size() != ids.size()) { + throw new ServiceException("删除机械失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取机械视图对象 + * + * @param machinery 机械对象 + * @return 机械视图对象 + */ + @Override + public EqpMachineryVo getVo(EqpMachinery machinery) { + // 对象转封装类 + EqpMachineryVo machineryVo = new EqpMachineryVo(); + if (machinery == null) { + return machineryVo; + } + BeanUtils.copyProperties(machinery, machineryVo); + return machineryVo; + } + + /** + * 获取机械查询条件封装 + * + * @param req 机械查询条件 + * @return 机械查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(EqpMachineryQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + String machineryName = req.getMachineryName(); + String machineryNumber = req.getMachineryNumber(); + Long projectId = req.getProjectId(); + Long number = req.getNumber(); + String principal = req.getPrincipal(); + String principalPhone = req.getPrincipalPhone(); + String provider = req.getProvider(); + String remark = req.getRemark(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(machineryName), EqpMachinery::getMachineryName, machineryName); + lqw.like(StringUtils.isNotBlank(principal), EqpMachinery::getPrincipal, principal); + lqw.like(StringUtils.isNotBlank(principalPhone), EqpMachinery::getPrincipalPhone, principalPhone); + lqw.like(StringUtils.isNotBlank(provider), EqpMachinery::getProvider, provider); + lqw.like(StringUtils.isNotBlank(machineryNumber), EqpMachinery::getMachineryNumber, machineryNumber); + lqw.like(StringUtils.isNotBlank(remark), EqpMachinery::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), EqpMachinery::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), EqpMachinery::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(number), EqpMachinery::getNumber, number); + return lqw; + } + + /** + * 获取机械分页对象视图 + * + * @param machineryPage 机械分页对象 + * @return 机械分页对象视图 + */ + @Override + public Page getVoPage(Page machineryPage) { + List machineryList = machineryPage.getRecords(); + Page machineryVoPage = new Page<>( + machineryPage.getCurrent(), + machineryPage.getSize(), + machineryPage.getTotal()); + if (CollUtil.isEmpty(machineryList)) { + return machineryVoPage; + } + List machineryVoList = machineryList.stream().map(this::getVo).toList(); + machineryVoPage.setRecords(machineryVoList); + return machineryVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerConstant.java new file mode 100644 index 0000000..60df3df --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerConstant.java @@ -0,0 +1,14 @@ +package org.dromara.manager.recognizermanager; + +/** + * @author lilemy + * @date 2025/7/21 10:33 + */ +public interface RecognizerConstant { + + /** + * 识别 api 路径 + */ + String RECOGNIZE_API_PATH_POST = "/detect_image"; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerManager.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerManager.java new file mode 100644 index 0000000..c5b8986 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerManager.java @@ -0,0 +1,124 @@ +package org.dromara.manager.recognizermanager; + +import cn.hutool.core.io.FileUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.manager.recognizermanager.enums.RecognizerTypeEnum; +import org.dromara.manager.recognizermanager.vo.RecognizeImageStreamResult; +import org.dromara.manager.recognizermanager.vo.RecognizeTargetVo; +import org.dromara.manager.recognizermanager.vo.RecognizeVo; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.FileNameMap; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLConnection; +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/21 10:56 + */ +@Slf4j +@Component +public class RecognizerManager { + + @Resource + private RecognizerProperties recognizerProperties; + + /** + * 识别图片 + * + * @param capUrl 图片地址 + * @param recTypeList 识别类型 + * @param extract 是否返回图片 + * @return 识别结果 + */ + public RecognizeVo recognize(String capUrl, List recTypeList, Boolean extract) { + String recType = RecognizerTypeEnum.joinRecTypes(recTypeList); + return RecognizerUtils.recognize(recognizerProperties.getUrl(), capUrl, recType, extract); + } + + /** + * 识别图片 + * + * @param capUrl 图片地址 + * @param recTypeList 识别类型 + * @return 识别结果 + */ + public RecognizeVo recognize(String capUrl, List recTypeList) { + return recognize(capUrl, recTypeList, false); + } + + /** + * 绘制图片 + * + * @param imgUrl 图片地址 + * @param targets 识别结果 + * @return 绘制后的图片 + */ + public RecognizeImageStreamResult drawImageToStream(String imgUrl, List targets) throws IOException, URISyntaxException { + // 1. 加载图片 + URI uri = new URI(imgUrl); + BufferedImage image = ImageIO.read(uri.toURL()); + // 2. 开始绘图 + Graphics2D g = image.createGraphics(); + g.setColor(Color.RED); + g.setStroke(new BasicStroke(5)); + // 设置中文兼容字体(或使用指定字体) + g.setFont(new Font("SansSerif", Font.BOLD, 18)); + for (RecognizeTargetVo target : targets) { + int x = target.getLeftTopPoint().get(0); + int y = target.getLeftTopPoint().get(1); + int w = target.getSize().get(0); + int h = target.getSize().get(1); + // 画矩形框 + g.drawRect(x, y, w, h); + // 写文字(类型 + 置信度) + String label = target.getType() + " (" + String.format("%.2f", target.getScore()) + ")"; + g.drawString(label, x, y - 5); + } + g.dispose(); + // 3. 输出为 InputStream + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + String filename = extractFilename(imgUrl); + String suffix = FileUtil.getSuffix(filename); + ImageIO.write(image, suffix == null ? "jpg" : suffix, baos); + return new RecognizeImageStreamResult(new ByteArrayInputStream(baos.toByteArray()), baos.size(), getContentTypeByFilename(filename)); + } + + /** + * 提取文件名 + * + * @param url 文件路径 + * @return 文件名 + */ + private static String extractFilename(String url) { + int start = url.lastIndexOf("/") + 1; + int end = url.indexOf("?", start); + if (end == -1) { + return url.substring(start); + } + if (start > 0 && end > start) { + return url.substring(start, end); + } + return null; + } + + /** + * 根据文件名获取文件类型 + * + * @param filename 文件名 + * @return 文件类型 + */ + private static String getContentTypeByFilename(String filename) { + FileNameMap fileNameMap = URLConnection.getFileNameMap(); + return fileNameMap.getContentTypeFor(filename); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerProperties.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerProperties.java new file mode 100644 index 0000000..e986e8f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerProperties.java @@ -0,0 +1,21 @@ +package org.dromara.manager.recognizermanager; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author lilemy + * @date 2025/7/21 10:39 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "recognizer") +public class RecognizerProperties { + + /** + * 请求地址 + */ + private String url; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerUtils.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerUtils.java new file mode 100644 index 0000000..f8ae063 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/RecognizerUtils.java @@ -0,0 +1,69 @@ +package org.dromara.manager.recognizermanager; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpStatus; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.manager.recognizermanager.enums.RecognizerHasTargetEnum; +import org.dromara.manager.recognizermanager.vo.RecognizeTargetVo; +import org.dromara.manager.recognizermanager.vo.RecognizeVo; + +import java.util.HashMap; +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/21 10:41 + */ +@Slf4j +public class RecognizerUtils { + + /** + * 识别图片 + * + * @param host 域名 + * @param capUrl 在线图片地址 + * @param type 识别算法模型,多选模式每个参数之间用 "," 隔开例 + * @param extract 是否返回图片 + * @return 识别结果 + */ + public static RecognizeVo recognize(String host, String capUrl, String type, Boolean extract) { + if (StringUtils.isAnyBlank(host, capUrl, type)) { + throw new ServiceException("图片识别参数为空", HttpStatus.HTTP_BAD_REQUEST); + } + HashMap paramMap = new HashMap<>(); + paramMap.put("type", type); + paramMap.put("url", capUrl); + paramMap.put("extract", extract != null && extract ? "true" : "false"); + String errorMsg = "图片识别请求失败"; + String url = host + RecognizerConstant.RECOGNIZE_API_PATH_POST; + try (HttpResponse response = HttpRequest.post(url) + .body(JSONUtil.toJsonStr(paramMap)) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + if (body == null) { + log.error("{}:{}", errorMsg, "返回参数为空"); + } + JSONObject result = JSONUtil.parseObj(response.body()); + log.info("图片识别请求成功:{}", body); + RecognizeVo recognizeVo = new RecognizeVo(); + Integer hasTarget = result.getInt("hasTarget"); + recognizeVo.setHasTarget(hasTarget); + if (hasTarget.equals(RecognizerHasTargetEnum.YES.getValue())) { + recognizeVo.setOriginalImgSize(result.getJSONArray("originalImgSize").toList(Integer.class)); + List targetList = JSONUtil.toList(result.getJSONArray("targets"), RecognizeTargetVo.class); + recognizeVo.setTargets(targetList); + } + return recognizeVo; + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/enums/RecognizerHasTargetEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/enums/RecognizerHasTargetEnum.java new file mode 100644 index 0000000..a21c7ea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/enums/RecognizerHasTargetEnum.java @@ -0,0 +1,23 @@ +package org.dromara.manager.recognizermanager.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/7/21 10:53 + */ +@Getter +public enum RecognizerHasTargetEnum { + + YES("是", 1), + NO("否", 0); + + private final String text; + private final int value; + + RecognizerHasTargetEnum(String text, int value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/enums/RecognizerTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/enums/RecognizerTypeEnum.java new file mode 100644 index 0000000..cef51e8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/enums/RecognizerTypeEnum.java @@ -0,0 +1,60 @@ +package org.dromara.manager.recognizermanager.enums; + +import lombok.Getter; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author lilemy + * @date 2025/7/21 10:14 + */ +@Getter +public enum RecognizerTypeEnum { + + HARDHAT("安全帽识别", "nohelmet", "1"), + VEST("反光背心识别", "novest", ""), + SMOKING("吸烟识别", "smoking", "3"), + FIRE("火焰识别", "fire", "16"), + PHO("光伏板识别", "pho", ""), + SHELVES("光伏板支架识别", "shelves", ""), + PILE("光伏板立柱识别", "pile", ""), + HOLE("洞", "hole", ""); + + private final String text; + + private final String value; + + /** + * 描述:对应字典violation_level_type + */ + private final String code; + + RecognizerTypeEnum(String text, String value, String code) { + this.text = text; + this.value = value; + this.code = code; + } + + public static RecognizerTypeEnum fromValue(String value) { + for (RecognizerTypeEnum type : RecognizerTypeEnum.values()) { + if (type.getValue().equals(value)) { + return type; + } + } + return null; + } + + /** + * 将多个 RecognizerTypeEnum 拼接为接口识别参数字符串(","分隔) + */ + public static String joinRecTypes(List types) { + if (types == null || types.isEmpty()) { + return ""; + } + return types.stream() + .map(RecognizerTypeEnum::getValue) + .collect(Collectors.joining(",")); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeImageStreamResult.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeImageStreamResult.java new file mode 100644 index 0000000..6813b8a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeImageStreamResult.java @@ -0,0 +1,33 @@ +package org.dromara.manager.recognizermanager.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.InputStream; + +/** + * @author lilemy + * @date 2025/7/21 10:59 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RecognizeImageStreamResult { + + /** + * 图片输入流 + */ + private InputStream inputStream; + + /** + * 图片长度 + */ + private long length; + + /** + * 图片类型 + */ + private String contentType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeTargetVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeTargetVo.java new file mode 100644 index 0000000..7b17b39 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeTargetVo.java @@ -0,0 +1,38 @@ +package org.dromara.manager.recognizermanager.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/21 10:43 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RecognizeTargetVo { + + /** + * 目标类型 + */ + private String type; + + /** + * 目标外接矩形像素 + */ + private List size; + + /** + * 目标在画面中左上角位置信息 + */ + private List leftTopPoint; + + /** + * 置信度得分(0~1) + */ + private Double score; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeVo.java new file mode 100644 index 0000000..b9c45df --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/recognizermanager/vo/RecognizeVo.java @@ -0,0 +1,29 @@ +package org.dromara.manager.recognizermanager.vo; + +import lombok.Data; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/21 10:42 + */ +@Data +public class RecognizeVo { + + /** + * 是否监测到目标:1:是;0:否 + */ + private Integer hasTarget; + + /** + * 原始图片尺寸([宽,高]),ex:[1920,1080] + */ + private List originalImgSize; + + /** + * 目标信息 + */ + private List targets; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherConstant.java new file mode 100644 index 0000000..f3a81ac --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherConstant.java @@ -0,0 +1,144 @@ +package org.dromara.manager.weathermanager; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/5/12 17:57 + */ +public interface WeatherConstant { + + /** + * 城市三天的天气 + */ + String THREE_DAYS_WEATHER_PATH = "/v7/weather/3d"; + + /** + * 天气信息 + */ + String DAILY = "daily"; + + /** + * 日期 + */ + String FX_DATE = "fxDate"; + + /** + * 最高温度 + */ + String TEMP_MAX = "tempMax"; + + /** + * 最低温度 + */ + String TEMP_MIN = "tempMin"; + + /** + * 日出时间 + */ + String SUN_RISE = "sunrise"; + + /** + * 日落时间 + */ + String SUN_SET = "sunset"; + + /** + * 白天天气状态 + */ + String TEXT_DAY = "textDay"; + + /** + * 晚上天气状态 + */ + String TEXT_NIGHT = "textNight"; + + // region 天气情况 + + /** + * 晴 + */ + List SUNNY = List.of("晴"); + + /** + * 多云 + */ + List MANY_CLOUD = List.of("多云", "少云", "晴间多云"); + + /** + * 阴 + */ + List CLOUDY = List.of("阴", "阴天"); + + /** + * 小雨 + */ + List SMALL_RAIN = List.of("小雨", "毛毛雨", "细雨", "毛毛雨/细雨", "小到中雨"); + + /** + * 大雨 + */ + List BIG_RAIN = List.of("阵雨", "强阵雨", "中雨", "大雨", "极端降雨", "暴雨", "大暴雨", "特大暴雨", "中到大雨", "大到暴雨", "暴雨到大暴雨", "大暴雨到特大暴雨"); + + /** + * 小雪 + */ + List SMALL_SNOW = List.of("雪", "小雪", "中雪", "小到中雪"); + + /** + * 大雪 + */ + List BIG_SNOW = List.of("大雪", "暴雪", "阵雪", "中到大雪", "大到暴雪", "阵雨夹雪"); + + /** + * 雷雨 + */ + List THUNDERSTORM = List.of("雷阵雨", "强雷阵雨", "雷阵雨伴有冰雹"); + + /** + * 雨雪 + */ + List RAIN_SNOW = List.of("冻雨", "雨夹雪", "雨雪天气", "阵雨夹雪"); + + /** + * 霾 + */ + List HAZE = List.of("霾", "雾霾", "中度霾", "重度霾", "严重霾"); + + /** + * 雾 + */ + List FOG = List.of("薄雾", "雾", "浓雾", "强浓雾", "大雾", "特强浓雾"); + + /** + * 沙尘 + */ + List SANDSTORM = List.of("扬沙", "浮尘", "沙尘暴", "强沙尘暴"); + + /** + * 获取天气情况map + * + * @return 天气情况map + */ + static Map> getWeatherStatusMap() { + Map> weatherStatusMap = new HashMap<>(); + weatherStatusMap.put("sunny", SUNNY); + weatherStatusMap.put("manyCloud", MANY_CLOUD); + weatherStatusMap.put("cloudy", CLOUDY); + weatherStatusMap.put("smallRain", SMALL_RAIN); + weatherStatusMap.put("bigRain", BIG_RAIN); + weatherStatusMap.put("smallSnow", SMALL_SNOW); + weatherStatusMap.put("bigSnow", BIG_SNOW); + weatherStatusMap.put("thunderstorm", THUNDERSTORM); + weatherStatusMap.put("rainSnow", RAIN_SNOW); + weatherStatusMap.put("haze", HAZE); + weatherStatusMap.put("fog", FOG); + weatherStatusMap.put("sandstorm", SANDSTORM); + return weatherStatusMap; + } + + // endregion + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherManager.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherManager.java new file mode 100644 index 0000000..8c86337 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherManager.java @@ -0,0 +1,125 @@ +package org.dromara.manager.weathermanager; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Base64; + +/** + * @author lilemy + * @date 2025/5/12 17:33 + */ +@Slf4j +@Component +public class WeatherManager { + + @Resource + private WeatherProperties weatherProperties; + + /** + * 获取天气 + * + * @param lng 经度 + * @param lat 纬度 + * @param weatherPath 天气请求路径 + * @return 天气信息字符串 + */ + public String getWeather(String lng, String lat, String weatherPath) { + // 获取小数点后两位的经纬度 + String lngTwo = roundToTwoDecimalPlacesString(lng); + String latTwo = roundToTwoDecimalPlacesString(lat); + String location = lngTwo + "," + latTwo; + // 获取天气请求路径 + String dayWeatherUrl = getDayWeatherUrl(weatherPath, location); + String body; + try (HttpResponse result = HttpRequest.get(dayWeatherUrl) + .header("Authorization", "Bearer " + getJwt()) + .execute()) { + int status = result.getStatus(); + if (status != HttpStatus.SUCCESS) { + log.error("获取天气失败,状态码:{},body:{}", status, result.body()); + throw new ServiceException("获取天气失败,状态码:" + status, HttpStatus.ERROR); + } + body = result.body(); + } + return body; + } + + /** + * 获取天气预报 Url + * + * @param weatherPath 天气请求路径 + * @param location 位置 + */ + private String getDayWeatherUrl(String weatherPath, String location) { + return String.format("https://%s%s?location=%s", weatherProperties.getApiHost(), weatherPath, location); + } + + /** + * 获取小数点后两位的经纬度 + * + * @param value 经纬度 + */ + private String roundToTwoDecimalPlacesString(String value) { + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(2, RoundingMode.HALF_UP); // 使用 RoundingMode.HALF_UP + return bd.toPlainString(); // 防止科学计数法 + } + + + /** + * 获取 JWT + */ + private String getJwt() { + // Private key + String privateKeyString = weatherProperties.getPrivateKey() + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .trim(); + byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); + PrivateKey privateKey; + try { + KeyFactory keyFactory = KeyFactory.getInstance("EdDSA"); + privateKey = keyFactory.generatePrivate(keySpec); + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + throw new ServiceException("获取天气失败,加密错误", HttpStatus.ERROR); + } + // Header + String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"" + weatherProperties.getKeyId() + "\"}"; + // Payload + long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30; + long exp = iat + 900; + String payloadJson = "{\"sub\": \"" + weatherProperties.getProjectId() + "\", \"iat\": " + iat + ", \"exp\": " + exp + "}"; + // Base64url header + payload + String headerEncoded = Base64.getUrlEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); + String payloadEncoded = Base64.getUrlEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); + String data = headerEncoded + "." + payloadEncoded; + // Sign + byte[] signature; + try { + Signature signer = Signature.getInstance("EdDSA"); + signer.initSign(privateKey); + signer.update(data.getBytes(StandardCharsets.UTF_8)); + signature = signer.sign(); + } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { + throw new ServiceException("获取天气失败,加密错误", HttpStatus.ERROR); + } + String signatureString = Base64.getUrlEncoder().encodeToString(signature); + return data + "." + signatureString; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherProperties.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherProperties.java new file mode 100644 index 0000000..bfd91d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/weathermanager/WeatherProperties.java @@ -0,0 +1,36 @@ +package org.dromara.manager.weathermanager; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author lilemy + * @date 2025/5/12 17:28 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "weather") +public class WeatherProperties { + + /** + * 凭据 id + */ + private String keyId; + + /** + * 项目 id + */ + private String projectId; + + /** + * 私钥 + */ + private String privateKey; + + /** + * 接口地址 + */ + private String apiHost; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Constant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Constant.java new file mode 100644 index 0000000..d2ebf00 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Constant.java @@ -0,0 +1,59 @@ +package org.dromara.manager.ys7manager; + +/** + * @author lilemy + * @date 2025/6/12 16:56 + */ +public interface Ys7Constant { + + /** + * token redis 缓存 key 前缀 + */ + String TOKEN_REDIS_KEY = "ys7:token"; + + /** + * 分页查询设备列表最大条数 + */ + Integer MAX_PAGE_SIZE = 50; + + /** + * 设备在线状态类型 + */ + String ON_OFF_LINE_TOPIC_TYPE = "ys.onoffline"; + + /** + * 获取 token 请求地址 Post + */ + String getTokenUrlByPost = "https://open.ys7.com/api/lapp/token/get"; + + /** + * 分页查询设备列表请求地址 Post + */ + String queryDevicePageUrlByPost = "https://open.ys7.com/api/lapp/device/list"; + + /** + * 修改设备名称请求地址 Post + */ + String updateDeviceNameUrlByPost = "https://open.ys7.com/api/lapp/device/name/update"; + + /** + * 添加设备预置点请求地址 Post + */ + String addDevicePresetUrlByPost = "https://open.ys7.com/api/lapp/device/preset/add"; + + /** + * 调用设备预置点请求地址 Post + */ + String moveDevicePresetUrlByPost = "https://open.ys7.com/api/lapp/device/preset/move"; + + /** + * 清除设备预置点请求地址 Post + */ + String deleteDevicePresetUrlByPost = "https://open.ys7.com/api/lapp/device/preset/clear"; + + /** + * 设备抓拍照片请求地址 Post + */ + String captureDeviceUrlByPost = "https://open.ys7.com/api/lapp/device/capture"; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Manager.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Manager.java new file mode 100644 index 0000000..5939c75 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Manager.java @@ -0,0 +1,126 @@ +package org.dromara.manager.ys7manager; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author lilemy + * @date 2025/6/13 11:10 + */ +@Slf4j +@Component +public class Ys7Manager { + + @Resource + private Ys7Properties ys7Properties; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 获取所有设备列表 + * + * @return 设备列表 + */ + public List queryAllDeviceList() { + String token = getToken(); + int pageStart = 0; + int pageSize = 50; + List deviceList = new ArrayList<>(); + while (true) { + // 分页获取设备 + List list = Ys7RequestUtils.queryDeviceVoList(token, pageStart, pageSize); + deviceList.addAll(list); + // 获取设备数量小于分页大小,则结束循环 + if (list.size() < pageSize) { + break; + } + pageStart++; + } + return deviceList; + } + + /** + * 获取 token + * + * @return token + */ + public String getToken() { + String tokenRedisKey = Ys7Constant.TOKEN_REDIS_KEY; + String token = stringRedisTemplate.opsForValue().get(tokenRedisKey); + // 不为空,直接返回 token + if (token != null) { + return token; + } + // 向云服务商请求新的 token + String newToken = Ys7RequestUtils.getToken(ys7Properties.getAppKey(), ys7Properties.getAppSecret()); + // 设置有效期 + stringRedisTemplate.opsForValue().set(tokenRedisKey, newToken, 6, TimeUnit.DAYS); + return newToken; + } + + /** + * 更新设备名称 + * + * @param deviceSerial 设备序列号 + * @param deviceName 设备名称 + * @return 是否成功 + */ + public Boolean updateDeviceName(String deviceSerial, String deviceName) { + return Ys7RequestUtils.updateDeviceName(getToken(), deviceSerial, deviceName); + } + + /** + * 添加设备预置点 + * + * @param deviceSerial 设备序列号 + * @param channelNo 通道号 + * @return 预置点编号 + */ + public Integer addDevicePreset(String deviceSerial, int channelNo) { + return Ys7RequestUtils.addDevicePreset(getToken(), deviceSerial, channelNo); + } + + /** + * 移动设备预置点 + * + * @param deviceSerial 设备序列号 + * @param channelNo 通道号 + * @param index 预置点编号 + * @return 是否成功 + */ + public Boolean moveDevicePreset(String deviceSerial, int channelNo, int index) { + return Ys7RequestUtils.moveDevicePreset(getToken(), deviceSerial, channelNo, index); + } + + /** + * 删除设备预置点 + * + * @param deviceSerial 设备序列号 + * @param channelNo 通道号 + * @param index 预置点编号 + * @return 是否成功 + */ + public Boolean deleteDevicePreset(String deviceSerial, int channelNo, int index) { + return Ys7RequestUtils.deleteDevicePreset(getToken(), deviceSerial, channelNo, index); + } + + /** + * 获取设备图片 + * + * @param deviceSerial 设备序列号 + * @param channelNo 通道号 + * @param quality 视频清晰度,0-流畅,1-高清(720P),2-4CIF,3-1080P,4-400w + * @return 抓拍后的图片路径 + */ + public String getCaptureDevicePic(String deviceSerial, int channelNo, int quality) { + return Ys7RequestUtils.getCaptureDevicePic(getToken(), deviceSerial, channelNo, quality); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Properties.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Properties.java new file mode 100644 index 0000000..0cf04e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7Properties.java @@ -0,0 +1,26 @@ +package org.dromara.manager.ys7manager; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author lilemy + * @date 2025/6/12 16:50 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "ys7") +public class Ys7Properties { + + /** + * appKey + */ + private String appKey; + + /** + * appSecret + */ + private String appSecret; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7RequestUtils.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7RequestUtils.java new file mode 100644 index 0000000..dfb29cb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/Ys7RequestUtils.java @@ -0,0 +1,293 @@ +package org.dromara.manager.ys7manager; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.manager.ys7manager.vo.Ys7NoDataResponseVo; +import org.dromara.manager.ys7manager.vo.Ys7PageResponseVo; +import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; +import org.dromara.manager.ys7manager.vo.Ys7ResponseVo; + +import java.util.HashMap; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/12 16:54 + */ +@Slf4j +public class Ys7RequestUtils { + + /** + * 获取 token + * + * @param appKey appKey + * @param appSecret appSecret + * @return token + */ + public static String getToken(String appKey, String appSecret) { + HashMap paramMap = new HashMap<>(); + paramMap.put("appKey", appKey); + paramMap.put("appSecret", appSecret); + String errorMsg = "Ys7 Token 请求失败"; + try (HttpResponse response = HttpRequest.post(Ys7Constant.getTokenUrlByPost) + .form(paramMap) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + Ys7ResponseVo responseVo = JSONUtil.toBean(body, Ys7ResponseVo.class); + if (!responseVo.getCode().equals("200")) { + log.error("{},状态码:{},{}", errorMsg, responseVo.getCode(), responseVo.getMsg()); + throw new ServiceException(errorMsg + responseVo.getMsg()); + } + log.info("Ys7 Token 请求成功:{}", body); + String data = responseVo.getData(); + JSONObject jsonObject = JSONUtil.parseObj(data); + return jsonObject.get("accessToken", String.class); + } + } + + /** + * 查询设备列表 + * + * @param accessToken 萤石开放API访问令牌 + * @param pageStart 分页页码,起始页从0开始,不超过400页 + * @param pageSize 分页大小,默认为10,不超过50 + * @return 设备列表 + */ + public static List queryDeviceVoList(String accessToken, Integer pageStart, Integer pageSize) { + if (pageStart < 0 || pageStart > 400) { + throw new ServiceException("分页页码超出范围"); + } + if (pageSize < 0 || pageSize > 50) { + pageSize = Ys7Constant.MAX_PAGE_SIZE; + } + HashMap paramMap = new HashMap<>(); + paramMap.put("accessToken", accessToken); + paramMap.put("pageStart", pageStart); + paramMap.put("pageSize", pageSize); + String errorMsg = String.format("Ys7 分页查询设备列表 第%s页大小%s 请求失败", pageStart, pageSize); + try (HttpResponse response = HttpRequest.post(Ys7Constant.queryDevicePageUrlByPost) + .form(paramMap) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + Ys7PageResponseVo responseVo = JSONUtil.toBean(body, Ys7PageResponseVo.class); + if (!responseVo.getCode().equals("200")) { + log.error("{},状态码:{},{}", errorMsg, responseVo.getCode(), responseVo.getMsg()); + throw new ServiceException(errorMsg + responseVo.getMsg()); + } + log.info("Ys7 分页查询设备列表 第{}页大小{} 请求成功:{}", pageStart, pageSize, responseVo.getPage()); + return JSONUtil.toList(responseVo.getData(), Ys7QueryDeviceResponseVo.class); + } + } + + /** + * 修改设备名称 + * + * @param accessToken accessToken + * @param deviceSerial 设备序列号 + * @param deviceName 设备名称,长度不大于50字节,不能包含特殊字符 + * @return 是否修改成功 + */ + public static Boolean updateDeviceName(String accessToken, String deviceSerial, String deviceName) { + // 参数校验 + if (StringUtils.isAnyBlank(accessToken, deviceSerial, deviceName)) { + throw new ServiceException("修改设备名称参数为空", HttpStatus.BAD_REQUEST); + } + if (deviceName.length() > 50) { + throw new ServiceException("设备名称长度不能超过50个字符", HttpStatus.BAD_REQUEST); + } + // 组合请求体 + HashMap paramMap = new HashMap<>(); + paramMap.put("accessToken", accessToken); + paramMap.put("deviceSerial", deviceSerial); + paramMap.put("deviceName", deviceName); + // 发送请求 + String errorMsg = "修改设备名称请求失败"; + try (HttpResponse response = HttpRequest.post(Ys7Constant.updateDeviceNameUrlByPost) + .form(paramMap) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + Ys7NoDataResponseVo responseVo = JSONUtil.toBean(body, Ys7NoDataResponseVo.class); + if (!responseVo.getCode().equals("200")) { + log.error("{},状态码:{},{}", errorMsg, responseVo.getCode(), responseVo.getMsg()); + throw new ServiceException(errorMsg + responseVo.getMsg()); + } + log.info("修改设备名称请求成功,设备 {} 名称修改为 {}", deviceSerial, deviceName); + return true; + } + } + + /** + * 添加设备预置位 + * + * @param accessToken accessToken + * @param deviceSerial 设备序列号 + * @param channelNo 通道号 + * @return 预置点序号 + */ + public static int addDevicePreset(String accessToken, String deviceSerial, int channelNo) { + if (StringUtils.isAnyBlank(accessToken, deviceSerial)) { + throw new ServiceException("添加设备预置位参数为空", HttpStatus.BAD_REQUEST); + } + HashMap paramMap = new HashMap<>(); + paramMap.put("accessToken", accessToken); + paramMap.put("deviceSerial", deviceSerial); + paramMap.put("channelNo", channelNo); + String errorMsg = "添加设备预置位请求失败"; + try (HttpResponse response = HttpRequest.post(Ys7Constant.addDevicePresetUrlByPost) + .form(paramMap) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + Ys7ResponseVo responseVo = JSONUtil.toBean(body, Ys7ResponseVo.class); + if (!responseVo.getCode().equals("200")) { + log.error("{},状态码:{},{}", errorMsg, responseVo.getCode(), responseVo.getMsg()); + throw new ServiceException(errorMsg + responseVo.getMsg()); + } + // 获取 data 中的 index + String data = responseVo.getData(); + // 解析为 JSONObject + JSONObject jsonObject = JSONUtil.parseObj(data); + Integer index = jsonObject.getInt("index"); + log.info("添加设备预置位请求成功,设备 {} 添加预置点成功,通道:{},序号 {}", deviceSerial, channelNo, index); + return index; + } + } + + /** + * 调用设备预置点 + * + * @param accessToken accessToken + * @param deviceSerial 设备序列号 + * @param channelNo 通道号 + * @param index 预置点序号 + * @return 是否调用成功 + */ + public static Boolean moveDevicePreset(String accessToken, String deviceSerial, int channelNo, int index) { + if (StringUtils.isAnyBlank(accessToken, deviceSerial)) { + throw new ServiceException("调用设备预置点参数为空", HttpStatus.BAD_REQUEST); + } + HashMap paramMap = new HashMap<>(); + paramMap.put("accessToken", accessToken); + paramMap.put("deviceSerial", deviceSerial); + paramMap.put("channelNo", channelNo); + paramMap.put("index", index); + String errorMsg = "调用设备预置点请求失败"; + try (HttpResponse response = HttpRequest.post(Ys7Constant.moveDevicePresetUrlByPost) + .form(paramMap) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + Ys7NoDataResponseVo responseVo = JSONUtil.toBean(body, Ys7NoDataResponseVo.class); + if (!responseVo.getCode().equals("200")) { + log.error("{},状态码:{},{}", errorMsg, responseVo.getCode(), responseVo.getMsg()); + throw new ServiceException(errorMsg + responseVo.getMsg()); + } + log.info("调用设备预置点请求成功,设备 {} 调用预置点成功,通道:{},序号 {}", deviceSerial, channelNo, index); + return true; + } + } + + /** + * 删除设备预置点 + * + * @param accessToken accessToken + * @param deviceSerial 设备序列号 + * @param channelNo 通道号 + * @param index 预置点序号 + * @return 是否删除成功 + */ + public static Boolean deleteDevicePreset(String accessToken, String deviceSerial, int channelNo, int index) { + if (StringUtils.isAnyBlank(accessToken, deviceSerial)) { + throw new ServiceException("删除设备预置点参数为空", HttpStatus.BAD_REQUEST); + } + HashMap paramMap = new HashMap<>(); + paramMap.put("accessToken", accessToken); + paramMap.put("deviceSerial", deviceSerial); + paramMap.put("channelNo", channelNo); + paramMap.put("index", index); + String errorMsg = "删除设备预置点请求失败"; + try (HttpResponse response = HttpRequest.post(Ys7Constant.deleteDevicePresetUrlByPost) + .form(paramMap) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + Ys7NoDataResponseVo responseVo = JSONUtil.toBean(body, Ys7NoDataResponseVo.class); + if (!responseVo.getCode().equals("200")) { + log.error("{},状态码:{},{}", errorMsg, responseVo.getCode(), responseVo.getMsg()); + throw new ServiceException(errorMsg + responseVo.getMsg()); + } + log.info("删除设备预置点请求成功,设备 {} 删除预置点成功,通道:{},序号 {}", deviceSerial, channelNo, index); + return true; + } + } + + /** + * 抓拍设备图片 + * + * @param accessToken accessToken + * @param deviceSerial 设备序列号 + * @param channelNo 通道号,IPC设备填写1 + * @param quality 视频清晰度,0-流畅,1-高清(720P),2-4CIF,3-1080P,4-400w + * @return 抓拍后的图片路径,图片保存有效期为2小时 + */ + public static String getCaptureDevicePic(String accessToken, String deviceSerial, int channelNo, int quality) { + if (StringUtils.isAnyBlank(accessToken, deviceSerial)) { + throw new ServiceException("抓拍设备图片参数为空", HttpStatus.BAD_REQUEST); + } + if (quality < 0 || quality > 4) { + quality = 0; + } + HashMap paramMap = new HashMap<>(); + paramMap.put("accessToken", accessToken); + paramMap.put("deviceSerial", deviceSerial); + paramMap.put("channelNo", channelNo); + paramMap.put("quality", quality); + String errorMsg = "抓拍设备图片请求失败"; + try (HttpResponse response = HttpRequest.post(Ys7Constant.captureDeviceUrlByPost) + .form(paramMap) + .execute()) { + if (!response.isOk()) { + log.error("{}:{}", errorMsg, response.getStatus()); + throw new ServiceException(errorMsg + response.getStatus()); + } + String body = response.body(); + Ys7ResponseVo responseVo = JSONUtil.toBean(body, Ys7ResponseVo.class); + if (!responseVo.getCode().equals("200")) { + log.error("{},状态码:{},{}", errorMsg, responseVo.getCode(), responseVo.getMsg()); + throw new ServiceException(errorMsg + responseVo.getMsg()); + } + String data = responseVo.getData(); + String picUrl = JSONUtil.parseObj(data).getStr("picUrl"); + log.info("抓拍设备图片请求成功,设备[{}]抓拍成功,通道:{},url:{}", deviceSerial, channelNo, picUrl); + return picUrl; + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/enums/DeviceOnOffLineEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/enums/DeviceOnOffLineEnum.java new file mode 100644 index 0000000..0a77699 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/enums/DeviceOnOffLineEnum.java @@ -0,0 +1,24 @@ +package org.dromara.manager.ys7manager.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/6/17 15:36 + */ +@Getter +public enum DeviceOnOffLineEnum { + + ONLINE("设备上线消息", "ONLINE"), + OFFLINE("设备离线消息", "OFFLINE"); + + private final String text; + + private final String value; + + DeviceOnOffLineEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7NoDataResponseVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7NoDataResponseVo.java new file mode 100644 index 0000000..06a893f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7NoDataResponseVo.java @@ -0,0 +1,22 @@ +package org.dromara.manager.ys7manager.vo; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/6/13 14:30 + */ +@Data +public class Ys7NoDataResponseVo { + + /** + * 响应码 + */ + private String code; + + /** + * 响应信息 + */ + private String msg; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7PageResponseVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7PageResponseVo.java new file mode 100644 index 0000000..2fcca07 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7PageResponseVo.java @@ -0,0 +1,32 @@ +package org.dromara.manager.ys7manager.vo; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/6/12 17:35 + */ +@Data +public class Ys7PageResponseVo { + + /** + * 响应码 + */ + private String code; + + /** + * 响应数据 + */ + private String data; + + /** + * 响应信息 + */ + private String msg; + + /** + * 分页信息 + */ + private String page; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7QueryDeviceResponseVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7QueryDeviceResponseVo.java new file mode 100644 index 0000000..51556f0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7QueryDeviceResponseVo.java @@ -0,0 +1,72 @@ +package org.dromara.manager.ys7manager.vo; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/6/12 17:33 + */ +@Data +public class Ys7QueryDeviceResponseVo { + + /** + * 条目索引 + */ + private String id; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 设备型号 + */ + private String deviceType; + + /** + * 设备在线状态,1-在线;0-离线 + */ + private Integer status; + + /** + * 布撤防状态 + */ + private Integer defence; + + /** + * 固件版本号 + */ + private String deviceVersion; + + /** + * 用户添加时间 + */ + private Long addTime; + + /** + * 设备最后更新时间 + */ + private Long updateTime; + + /** + * 设备二级类目名称 + */ + private String parentCategory; + + /** + * 设备风险安全等级,0-安全;大于0,有风险,风险越高,值越大 + */ + private Integer riskLevel; + + /** + * 设备IP地址 + */ + private String netAddress; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7ResponseVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7ResponseVo.java new file mode 100644 index 0000000..ec3b542 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/manager/ys7manager/vo/Ys7ResponseVo.java @@ -0,0 +1,27 @@ +package org.dromara.manager.ys7manager.vo; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/6/12 17:14 + */ +@Data +public class Ys7ResponseVo { + + /** + * 响应码 + */ + private String code; + + /** + * 响应数据 + */ + private String data; + + /** + * 响应信息 + */ + private String msg; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/constants/MatMaterialsConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/constants/MatMaterialsConstant.java new file mode 100644 index 0000000..52b3cfd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/constants/MatMaterialsConstant.java @@ -0,0 +1,67 @@ +package org.dromara.materials.constants; + +import org.dromara.common.core.utils.DateUtils; +import org.dromara.materials.domain.MatMaterialIssue; +import org.dromara.materials.domain.MatMaterialReceive; + +import java.text.SimpleDateFormat; + +/** + * @author lilemy + * @date 2025/7/4 18:26 + */ +public interface MatMaterialsConstant { + + /** + * 物料领料单文件路径 + */ + String MATERIALS_ISSUE_FILE_URL = "docs/materials/issue/"; + + /** + * 物料接收单文件路径 + */ + String MATERIALS_RECEIVE_FILE_URL = "docs/materials/receive/"; + + /** + * 物料领料单模版路径 + */ + String MATERIALS_ISSUE_TEMPLATE_PATH = "template/物料领料单模版.docx"; + + /** + * 物料接收单模版路径 + */ + String MATERIALS_RECEIVE_TEMPLATE_PATH = "template/物料接收单模版.docx"; + + /** + * 获取物料领料单文件名 + */ + static String getMatMaterialIssueFileUrl(MatMaterialIssue materialIssue) { + String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(materialIssue.getUpdateTime()); + return String.format("%s%s/%s", MATERIALS_ISSUE_FILE_URL, materialIssue.getId(), timestamp); + } + + /** + * 获取物料领料单文件名 + */ + static String getMatMaterialIssueFileName(MatMaterialIssue materialIssue) { + String createDate = DateUtils.formatDate(materialIssue.getCreateTime()); + return String.format("物料领料单(%s).docx", createDate); + } + + /** + * 获取物料接收单文件名 + */ + static String getMatMaterialReceiveFileUrl(MatMaterialReceive materialReceive) { + String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(materialReceive.getUpdateTime()); + return String.format("%s%s/%s", MATERIALS_ISSUE_FILE_URL, materialReceive.getId(), timestamp); + } + + /** + * 获取物料接收单文件名 + */ + static String getMatMaterialReceiveFileName(MatMaterialReceive materialReceive) { + String createDate = DateUtils.formatDate(materialReceive.getCreateTime()); + return String.format("物料接收单(%s).docx", createDate); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatCompanyController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatCompanyController.java new file mode 100644 index 0000000..6dbff39 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatCompanyController.java @@ -0,0 +1,113 @@ +package org.dromara.materials.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.materials.domain.dto.company.MatCompanyCreateReq; +import org.dromara.materials.domain.dto.company.MatCompanyQueryReq; +import org.dromara.materials.domain.dto.company.MatCompanyUpdateReq; +import org.dromara.materials.domain.vo.company.MatCompanyVo; +import org.dromara.materials.service.IMatCompanyService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 材料供应商 + * + * @author lilemy + * @date 2025-03-06 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/materials/company") +public class MatCompanyController extends BaseController { + + private final IMatCompanyService companyService; + + /** + * 查询材料供应商列表 + */ + @SaCheckPermission("materials:company:list") + @GetMapping("/list") + public TableDataInfo list(MatCompanyQueryReq req, PageQuery pageQuery) { + return companyService.queryPageList(req, pageQuery); + } + + /** + * 导出材料供应商列表 + */ + @SaCheckPermission("materials:company:export") + @Log(title = "材料供应商", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(MatCompanyQueryReq req, HttpServletResponse response) { + List list = companyService.queryList(req); + ExcelUtil.exportExcel(list, "材料供应商", MatCompanyVo.class, response); + } + + /** + * 获取材料供应商详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("materials:company:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(companyService.queryById(id)); + } + + /** + * 新增材料供应商 + */ + @SaCheckPermission("materials:company:add") + @Log(title = "材料供应商", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody MatCompanyCreateReq req) { + if (req == null) { + throw new ServiceException("参数不能为空", HttpStatus.BAD_REQUEST); + } + return R.ok(companyService.insertByBo(req)); + } + + /** + * 修改材料供应商 + */ + @SaCheckPermission("materials:company:edit") + @Log(title = "材料供应商", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody MatCompanyUpdateReq req) { + return toAjax(companyService.updateByBo(req)); + } + + /** + * 删除材料供应商 + * + * @param ids 主键串 + */ + @SaCheckPermission("materials:company:remove") + @Log(title = "材料供应商", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(companyService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialIssueController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialIssueController.java new file mode 100644 index 0000000..fb23c4b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialIssueController.java @@ -0,0 +1,105 @@ +package org.dromara.materials.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueCreateReq; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueQueryReq; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueUpdateReq; +import org.dromara.materials.domain.vo.materialissue.MatMaterialIssueVo; +import org.dromara.materials.service.IMatMaterialIssueService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 物料领料单 + * + * @author lilemy + * @date 2025-07-04 + */ +@Validated +@RestController +@RequestMapping("/materials/materialIssue") +public class MatMaterialIssueController extends BaseController { + + @Resource + private IMatMaterialIssueService matMaterialIssueService; + + /** + * 查询物料领料单列表 + */ + @SaCheckPermission("materials:materialIssue:list") + @GetMapping("/list") + public TableDataInfo list(MatMaterialIssueQueryReq req, PageQuery pageQuery) { + return matMaterialIssueService.queryPageList(req, pageQuery); + } + + /** + * 根据主键导出物料领料单详细信息 + */ + @SaCheckPermission("materials:materialIssue:export") + @Log(title = "物料领料单", businessType = BusinessType.EXPORT) + @PostMapping("/export/word") + public void exportWordById(@NotNull(message = "主键不能为空") Long id, + HttpServletResponse response) { + matMaterialIssueService.exportWordById(id, response); + } + + /** + * 获取物料领料单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("materials:materialIssue:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(matMaterialIssueService.queryById(id)); + } + + /** + * 新增物料领料单 + */ + @SaCheckPermission("materials:materialIssue:add") + @Log(title = "物料领料单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated @RequestBody MatMaterialIssueCreateReq req) { + return toAjax(matMaterialIssueService.insertByBo(req)); + } + + /** + * 修改物料领料单 + */ + @SaCheckPermission("materials:materialIssue:edit") + @Log(title = "物料领料单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated @RequestBody MatMaterialIssueUpdateReq req) { + return toAjax(matMaterialIssueService.updateByBo(req)); + } + + /** + * 删除物料领料单 + * + * @param ids 主键串 + */ + @SaCheckPermission("materials:materialIssue:remove") + @Log(title = "物料领料单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(matMaterialIssueService.deleteByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialReceiveController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialReceiveController.java new file mode 100644 index 0000000..f342701 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialReceiveController.java @@ -0,0 +1,105 @@ +package org.dromara.materials.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveCreateReq; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveQueryReq; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveUpdateReq; +import org.dromara.materials.domain.vo.materialreceive.MatMaterialReceiveVo; +import org.dromara.materials.service.IMatMaterialReceiveService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 物料接收单 + * + * @author lilemy + * @date 2025-07-04 + */ +@Validated +@RestController +@RequestMapping("/materials/materialReceive") +public class MatMaterialReceiveController extends BaseController { + + @Resource + private IMatMaterialReceiveService matMaterialReceiveService; + + /** + * 查询物料接收单列表 + */ + @SaCheckPermission("materials:materialReceive:list") + @GetMapping("/list") + public TableDataInfo list(MatMaterialReceiveQueryReq req, PageQuery pageQuery) { + return matMaterialReceiveService.queryPageList(req, pageQuery); + } + + /** + * 根据主键导出物料接收单详细信息 + */ + @SaCheckPermission("materials:materialReceive:export") + @Log(title = "物料接收单", businessType = BusinessType.EXPORT) + @PostMapping("/export/word") + public void exportWordById(@NotNull(message = "主键不能为空") Long id, + HttpServletResponse response) { + matMaterialReceiveService.exportWordById(id, response); + } + + /** + * 获取物料接收单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("materials:materialReceive:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(matMaterialReceiveService.queryById(id)); + } + + /** + * 新增物料接收单 + */ + @SaCheckPermission("materials:materialReceive:add") + @Log(title = "物料接收单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated @RequestBody MatMaterialReceiveCreateReq req) { + return toAjax(matMaterialReceiveService.insertByBo(req)); + } + + /** + * 修改物料接收单 + */ + @SaCheckPermission("materials:materialReceive:edit") + @Log(title = "物料接收单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated @RequestBody MatMaterialReceiveUpdateReq req) { + return toAjax(matMaterialReceiveService.updateByBo(req)); + } + + /** + * 删除物料接收单 + * + * @param ids 主键串 + */ + @SaCheckPermission("materials:materialReceive:remove") + @Log(title = "物料接收单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(matMaterialReceiveService.deleteByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialsController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialsController.java new file mode 100644 index 0000000..9e1f54a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialsController.java @@ -0,0 +1,119 @@ +package org.dromara.materials.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.materials.domain.dto.materials.MatMaterialsCreateReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsGisReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsQueryReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsUpdateReq; +import org.dromara.materials.domain.vo.materials.MatMaterialsVo; +import org.dromara.materials.domain.vo.materials.MatMaterialsGisVo; +import org.dromara.materials.service.IMatMaterialsService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 材料 + * + * @author lilemy + * @date 2025-03-06 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/materials/materials") +public class MatMaterialsController extends BaseController { + + private final IMatMaterialsService materialsService; + + /** + * 查询材料列表 + */ + @SaCheckPermission("materials:materials:list") + @GetMapping("/list") + public TableDataInfo list(MatMaterialsQueryReq req, PageQuery pageQuery) { + return materialsService.queryPageList(req, pageQuery); + } + + /** + * 导出材料列表 + */ + @SaCheckPermission("materials:materials:export") + @Log(title = "材料", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(MatMaterialsQueryReq req, HttpServletResponse response) { + List list = materialsService.queryList(req); + ExcelUtil.exportExcel(list, "材料名称", MatMaterialsVo.class, response); + } + + /** + * 查询大屏材料信息 + */ + @SaCheckPermission("materials:materials:list") + @GetMapping("/list/gis") + public R> queryGisList(MatMaterialsGisReq req) { + return R.ok(materialsService.queryGisList(req)); + } + + /** + * 获取材料详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("materials:materials:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(materialsService.queryById(id)); + } + + /** + * 新增材料 + */ + @SaCheckPermission("materials:materials:add") + @Log(title = "材料", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody MatMaterialsCreateReq req) { + return R.ok(materialsService.insertByBo(req)); + } + + /** + * 修改材料 + */ + @SaCheckPermission("materials:materials:edit") + @Log(title = "材料", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody MatMaterialsUpdateReq req) { + return toAjax(materialsService.updateByBo(req)); + } + + /** + * 删除材料 + * + * @param ids 主键串 + */ + @SaCheckPermission("materials:materials:remove") + @Log(title = "材料", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(materialsService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialsInventoryController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialsInventoryController.java new file mode 100644 index 0000000..b7aee42 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/controller/MatMaterialsInventoryController.java @@ -0,0 +1,108 @@ +package org.dromara.materials.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryCreateReq; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryQueryReq; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryUpdateReq; +import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryVo; +import org.dromara.materials.service.IMatMaterialsInventoryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 材料出/入库 + * + * @author lilemy + * @date 2025-03-06 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/materials/materialsInventory") +public class MatMaterialsInventoryController extends BaseController { + + private final IMatMaterialsInventoryService materialsInventoryService; + + /** + * 查询材料出/入库列表 + */ + @SaCheckPermission("materials:materialsInventory:list") + @GetMapping("/list") + public TableDataInfo list(MatMaterialsInventoryQueryReq req, PageQuery pageQuery) { + return materialsInventoryService.queryPageList(req, pageQuery); + } + + /** + * 导出材料出/入库列表 + */ + @SaCheckPermission("materials:materialsInventory:export") + @Log(title = "材料出/入库", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(MatMaterialsInventoryQueryReq req, HttpServletResponse response) { + List list = materialsInventoryService.queryList(req); + ExcelUtil.exportExcel(list, "材料出入库", MatMaterialsInventoryVo.class, response); + } + + /** + * 获取材料出/入库详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("materials:materialsInventory:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(materialsInventoryService.queryById(id)); + } + + /** + * 新增材料出/入库 + */ + @SaCheckPermission("materials:materialsInventory:add") + @Log(title = "材料出/入库", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody MatMaterialsInventoryCreateReq req) { + return R.ok(materialsInventoryService.insertByBo(req)); + } + + /** + * 修改材料出/入库 + */ + @SaCheckPermission("materials:materialsInventory:edit") + @Log(title = "材料出/入库", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody MatMaterialsInventoryUpdateReq req) { + return toAjax(materialsInventoryService.updateByBo(req)); + } + + /** + * 删除材料出/入库 + * + * @param ids 主键串 + */ + @SaCheckPermission("materials:materialsInventory:remove") + @Log(title = "材料出/入库", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(materialsInventoryService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatCompany.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatCompany.java new file mode 100644 index 0000000..7058ff6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatCompany.java @@ -0,0 +1,66 @@ +package org.dromara.materials.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 公司对象 mat_company + * + * @author lilemy + * @date 2025-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("mat_company") +public class MatCompany extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 公司名称 + */ + private String companyName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 资质情况 + */ + private String qualification; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialIssue.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialIssue.java new file mode 100644 index 0000000..c463e5b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialIssue.java @@ -0,0 +1,126 @@ +package org.dromara.materials.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 物料领料单对象 mat_material_issue + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("mat_material_issue") +public class MatMaterialIssue extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 领料单位 + */ + private String issueUnit; + + /** + * 保管单位 + */ + private String storageUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 合格证份数 + */ + private Integer certCount; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 出厂报告份数 + */ + private Integer reportCount; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 技术资料份数 + */ + private Integer techDocCount; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 厂家资质文件份数 + */ + private Integer licenseCount; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialIssueItem.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialIssueItem.java new file mode 100644 index 0000000..cf3faaa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialIssueItem.java @@ -0,0 +1,77 @@ +package org.dromara.materials.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 物料领料单明细项对象 mat_material_issue_item + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("mat_material_issue_item") +public class MatMaterialIssueItem extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 领料单id + */ + private Long issueId; + + /** + * 名称 + */ + private String name; + + /** + * 规格 + */ + private String specification; + + /** + * 单位 + */ + private String unit; + + /** + * 库存 + */ + private BigDecimal stockQuantity; + + /** + * 领取 + */ + private BigDecimal issuedQuantity; + + /** + * 剩余 + */ + private BigDecimal remainingQuantity; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialReceive.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialReceive.java new file mode 100644 index 0000000..56ace1c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialReceive.java @@ -0,0 +1,126 @@ +package org.dromara.materials.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 物料接收单对象 mat_material_receive + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("mat_material_receive") +public class MatMaterialReceive extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 合格证份数 + */ + private Integer certCount; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 出厂报告份数 + */ + private Integer reportCount; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 技术资料份数 + */ + private Integer techDocCount; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 厂家资质文件份数 + */ + private Integer licenseCount; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 设备材料入库/移交 + */ + private String storageType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialReceiveItem.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialReceiveItem.java new file mode 100644 index 0000000..c31b900 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialReceiveItem.java @@ -0,0 +1,77 @@ +package org.dromara.materials.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 物料接收单明细项对象 mat_material_receive_item + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("mat_material_receive_item") +public class MatMaterialReceiveItem extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 接收单id + */ + private Long receiveId; + + /** + * 名称 + */ + private String name; + + /** + * 规格 + */ + private String specification; + + /** + * 单位 + */ + private String unit; + + /** + * 数量 + */ + private BigDecimal quantity; + + /** + * 验收 + */ + private BigDecimal acceptedQuantity; + + /** + * 缺件 + */ + private BigDecimal shortageQuantity; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterials.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterials.java new file mode 100644 index 0000000..2428ebb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterials.java @@ -0,0 +1,81 @@ +package org.dromara.materials.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 材料名称对象 mat_materials + * + * @author lilemy + * @date 2025-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("mat_materials") +public class MatMaterials extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 材料名称 + */ + private String materialsName; + + /** + * 公司id + */ + private Long companyId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 规格型号名称 + */ + private String typeSpecificationName; + + /** + * 文件对象存储id列表 + */ + private String fileOssId; + + /** + * 使用部位 + */ + private String usePart; + + /** + * 计量单位 + */ + private String weightId; + + /** + * 备注 + */ + private String remark; + + /** + * 预计材料数量 + */ + private String quantityCount; + + /** + * 状态(0正常 1停用) + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialsInventory.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialsInventory.java new file mode 100644 index 0000000..68985d5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/MatMaterialsInventory.java @@ -0,0 +1,92 @@ +package org.dromara.materials.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 材料出/入库对象 mat_materials_inventory + * + * @author lilemy + * @date 2025-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("mat_materials_inventory") +public class MatMaterialsInventory extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 材料id + */ + private Long materialsId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 出入库状态 + */ + private String outPut; + + /** + * 出/入库的数量 + */ + private Long number; + + /** + * 出/入库操作时间 + */ + private Date outPutTime; + + /** + * 剩余库存数量(记录最后一次操作留下的库存数) + */ + private Long residue; + + /** + * 操作人(入库人、领料人) + */ + private String operator; + + /** + * 材料出入证明 + */ + private String path; + + /** + * 处理方式 + */ + private String disposition; + + /** + * 交接单位(班组) + */ + private String recipient; + + /** + * 领用人 + */ + private String shipper; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyCreateReq.java new file mode 100644 index 0000000..9542db9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyCreateReq.java @@ -0,0 +1,48 @@ +package org.dromara.materials.domain.dto.company; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class MatCompanyCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 公司名称 + */ + private String companyName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 备注 + */ + private String remark; + + /** + * 资质情况 + */ + private String qualification; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyQueryReq.java new file mode 100644 index 0000000..4725a12 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyQueryReq.java @@ -0,0 +1,58 @@ +package org.dromara.materials.domain.dto.company; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class MatCompanyQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5563677643070664671L; + + /** + * 主键id + */ + private Long id; + + /** + * 公司名称 + */ + private String companyName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 资质情况 + */ + private String qualification; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyUpdateReq.java new file mode 100644 index 0000000..bd5e978 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/company/MatCompanyUpdateReq.java @@ -0,0 +1,58 @@ +package org.dromara.materials.domain.dto.company; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class MatCompanyUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3431952359907567659L; + + /** + * 主键id + */ + private Long id; + + /** + * 公司名称 + */ + private String companyName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 资质情况 + */ + private String qualification; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueCreateReq.java new file mode 100644 index 0000000..ccdb0a4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueCreateReq.java @@ -0,0 +1,105 @@ +package org.dromara.materials.domain.dto.materialissue; + +import lombok.Data; +import org.dromara.materials.domain.dto.materialissueitem.MatMaterialIssueItemDto; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/4 15:02 + */ +@Data +public class MatMaterialIssueCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2742974667799153892L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 领料单位 + */ + private String issueUnit; + + /** + * 保管单位 + */ + private String storageUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 明细项 + */ + private List itemList; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueQueryReq.java new file mode 100644 index 0000000..e0c3b1b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueQueryReq.java @@ -0,0 +1,63 @@ +package org.dromara.materials.domain.dto.materialissue; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/4 15:02 + */ +@Data +public class MatMaterialIssueQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4011015750160760763L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 领料单位 + */ + private String issueUnit; + + /** + * 保管单位 + */ + private String storageUnit; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueUpdateReq.java new file mode 100644 index 0000000..12d81b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueUpdateReq.java @@ -0,0 +1,100 @@ +package org.dromara.materials.domain.dto.materialissue; + +import lombok.Data; +import org.dromara.materials.domain.dto.materialissueitem.MatMaterialIssueItemDto; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/4 15:02 + */ +@Data +public class MatMaterialIssueUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2053113999402012882L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 领料单位 + */ + private String issueUnit; + + /** + * 保管单位 + */ + private String storageUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 明细项 + */ + private List itemList; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueWordDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueWordDto.java new file mode 100644 index 0000000..a3ed7be --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissue/MatMaterialIssueWordDto.java @@ -0,0 +1,39 @@ +package org.dromara.materials.domain.dto.materialissue; + +import lombok.Data; +import org.dromara.materials.domain.dto.materialissueitem.MatMaterialIssueItemWordDto; + +import java.util.List; + +@Data +public class MatMaterialIssueWordDto { + + // 顶部信息 + private String projectName; + private String formCode; + private String materialName; + private String supplierUnit; + private String orderingUnit; + private String issueUnit; + private String storageUnit; + + // 表格数据 - 这是一个列表! + private List items; + + // 合计行数据 + private Integer totalStockQuantity; + private Integer totalIssuedQuantity; + private Integer totalRemainingQuantity; + + // 缺陷情况及附件 + private String defectDescription; + private String isCertCount; + private Integer certCount; + private String isReportCount; + private Integer reportCount; + private String isTechDocCount; + private Integer techDocCount; + private String isLicenseCount; + private Integer licenseCount; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissueitem/MatMaterialIssueItemDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissueitem/MatMaterialIssueItemDto.java new file mode 100644 index 0000000..6703d6b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissueitem/MatMaterialIssueItemDto.java @@ -0,0 +1,58 @@ +package org.dromara.materials.domain.dto.materialissueitem; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * @author lilemy + * @date 2025/7/4 15:21 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MatMaterialIssueItemDto { + + /** + * 主键id + */ + private Long id; + + /** + * 名称 + */ + private String name; + + /** + * 规格 + */ + private String specification; + + /** + * 单位 + */ + private String unit; + + /** + * 库存 + */ + private BigDecimal stockQuantity; + + /** + * 领取 + */ + private BigDecimal issuedQuantity; + + /** + * 剩余 + */ + private BigDecimal remainingQuantity; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissueitem/MatMaterialIssueItemWordDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissueitem/MatMaterialIssueItemWordDto.java new file mode 100644 index 0000000..d47d760 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialissueitem/MatMaterialIssueItemWordDto.java @@ -0,0 +1,21 @@ +package org.dromara.materials.domain.dto.materialissueitem; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MatMaterialIssueItemWordDto { + + private Integer no; // 序号 + private String name; // 名称 + private String specification; // 规格 + private String unit; // 单位 + private Integer stockQuantity; // 库存数量 + private Integer issuedQuantity; // 领取数量 + private Integer remainingQuantity;// 剩余数量 + private String remark; // 备注 + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveCreateReq.java new file mode 100644 index 0000000..d358d1f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveCreateReq.java @@ -0,0 +1,100 @@ +package org.dromara.materials.domain.dto.materialreceive; + +import lombok.Data; +import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemDto; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/4 15:03 + */ +@Data +public class MatMaterialReceiveCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1826521942178676812L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 明细项 + */ + private List itemList; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 设备材料入库/移交 + */ + private String storageType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveQueryReq.java new file mode 100644 index 0000000..4a960ba --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveQueryReq.java @@ -0,0 +1,63 @@ +package org.dromara.materials.domain.dto.materialreceive; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/4 15:03 + */ +@Data +public class MatMaterialReceiveQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5772774919127572167L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 设备材料入库/移交 + */ + private String storageType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveUpdateReq.java new file mode 100644 index 0000000..5feca7a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveUpdateReq.java @@ -0,0 +1,100 @@ +package org.dromara.materials.domain.dto.materialreceive; + +import lombok.Data; +import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemDto; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/4 15:03 + */ +@Data +public class MatMaterialReceiveUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5686357336524453994L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 明细项 + */ + private List itemList; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 设备材料入库/移交 + */ + private String storageType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveWordDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveWordDto.java new file mode 100644 index 0000000..687a767 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceive/MatMaterialReceiveWordDto.java @@ -0,0 +1,48 @@ +package org.dromara.materials.domain.dto.materialreceive; + +import lombok.Data; +import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemWordDto; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/7/6 13:56 + */ +@Data +public class MatMaterialReceiveWordDto { + + // 顶部信息 + private String formCode; + private String projectName; + private String materialName; + private String contractName; + private String orderingUnit; + private String supplierUnit; + + // 表格数据 - 这是一个列表! + private List items; + + // 合计行数据 + private Integer totalQuantity; + private Integer totalAcceptedQuantity; + private Integer totalShortageQuantity; + + // 缺陷情况及附件 + private String defectDescription; + private String isCertCount; + private Integer certCount; + private String isReportCount; + private Integer reportCount; + private String isTechDocCount; + private Integer techDocCount; + private String isLicenseCount; + private Integer licenseCount; + + + // 设备材料入库/移交 + private String storageType1; + private String storageType2; + private String storageType3; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceiveitem/MatMaterialReceiveItemDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceiveitem/MatMaterialReceiveItemDto.java new file mode 100644 index 0000000..c1c386f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceiveitem/MatMaterialReceiveItemDto.java @@ -0,0 +1,58 @@ +package org.dromara.materials.domain.dto.materialreceiveitem; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * @author lilemy + * @date 2025/7/4 15:24 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MatMaterialReceiveItemDto { + + /** + * 主键id + */ + private Long id; + + /** + * 名称 + */ + private String name; + + /** + * 规格 + */ + private String specification; + + /** + * 单位 + */ + private String unit; + + /** + * 数量 + */ + private BigDecimal quantity; + + /** + * 验收 + */ + private BigDecimal acceptedQuantity; + + /** + * 缺件 + */ + private BigDecimal shortageQuantity; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceiveitem/MatMaterialReceiveItemWordDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceiveitem/MatMaterialReceiveItemWordDto.java new file mode 100644 index 0000000..3509b27 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialreceiveitem/MatMaterialReceiveItemWordDto.java @@ -0,0 +1,56 @@ +package org.dromara.materials.domain.dto.materialreceiveitem; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author lilemy + * @date 2025/7/6 14:04 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MatMaterialReceiveItemWordDto { + + /** + * 序号 + */ + private Integer no; + + /** + * 名称 + */ + private String name; + + /** + * 规格 + */ + private String specification; + + /** + * 单位 + */ + private String unit; + + /** + * 数量 + */ + private Integer quantity; + + /** + * 验收 + */ + private Integer acceptedQuantity; + + /** + * 缺件 + */ + private Integer shortageQuantity; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsCreateReq.java new file mode 100644 index 0000000..6570f8e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsCreateReq.java @@ -0,0 +1,64 @@ +package org.dromara.materials.domain.dto.materials; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class MatMaterialsCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 材料名称 + */ + private String materialsName; + + /** + * 公司id + */ + private Long companyId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 规格型号名称 + */ + private String typeSpecificationName; + + /** + * 文件对象存储id列表 + */ + private Map fileOssIdMap; + + /** + * 使用部位 + */ + private String usePart; + + /** + * 计量单位 + */ + private String weightId; + + /** + * 备注 + */ + private String remark; + + /** + * 预计材料数量 + */ + private String quantityCount; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsGisReq.java new file mode 100644 index 0000000..32a0a2a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsGisReq.java @@ -0,0 +1,25 @@ +package org.dromara.materials.domain.dto.materials; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 10:38 + */ +@Data +public class MatMaterialsGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7069030786285421399L; + + /** + * 项目主键 + */ + @NotNull(message = "项目主键不能为空") + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsQueryReq.java new file mode 100644 index 0000000..55f538e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsQueryReq.java @@ -0,0 +1,74 @@ +package org.dromara.materials.domain.dto.materials; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class MatMaterialsQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5563677643070664671L; + + /** + * 主键id + */ + private Long id; + + /** + * 材料名称 + */ + private String materialsName; + + /** + * 公司id + */ + private Long companyId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 规格型号名称 + */ + private String typeSpecificationName; + + /** + * 文件对象存储id列表 + */ + private Map fileOssIdMap; + + /** + * 使用部位 + */ + private String usePart; + + /** + * 计量单位 + */ + private String weightId; + + /** + * 备注 + */ + private String remark; + + /** + * 预计材料数量 + */ + private String quantityCount; + + /** + * 状态(0正常 1停用) + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsUpdateReq.java new file mode 100644 index 0000000..70e1b41 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materials/MatMaterialsUpdateReq.java @@ -0,0 +1,74 @@ +package org.dromara.materials.domain.dto.materials; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class MatMaterialsUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3431952359907567659L; + + /** + * 主键id + */ + private Long id; + + /** + * 材料名称 + */ + private String materialsName; + + /** + * 公司id + */ + private Long companyId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 规格型号名称 + */ + private String typeSpecificationName; + + /** + * 文件对象存储id列表 + */ + private Map fileOssIdMap; + + /** + * 使用部位 + */ + private String usePart; + + /** + * 计量单位 + */ + private String weightId; + + /** + * 备注 + */ + private String remark; + + /** + * 预计材料数量 + */ + private String quantityCount; + + /** + * 状态(0正常 1停用) + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryCreateReq.java new file mode 100644 index 0000000..5857a5e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryCreateReq.java @@ -0,0 +1,74 @@ +package org.dromara.materials.domain.dto.materialsinventory; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class MatMaterialsInventoryCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 材料id + */ + private Long materialsId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 出入库状态 + */ + private String outPut; + + /** + * 出/入库的数量 + */ + private Long number; + + /** + * 出/入库操作时间 + */ + private Date outPutTime; + + /** + * 操作人(入库人、领料人) + */ + private String operator; + + /** + * 材料出入证明 + */ + private String path; + + /** + * 处理方式 + */ + private String disposition; + + /** + * 交接单位(班组) + */ + private String recipient; + + /** + * 领用人 + */ + private String shipper; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryQueryReq.java new file mode 100644 index 0000000..15d8ca4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryQueryReq.java @@ -0,0 +1,84 @@ +package org.dromara.materials.domain.dto.materialsinventory; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class MatMaterialsInventoryQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5563677643070664671L; + + /** + * 主键id + */ + private Long id; + + /** + * 材料id + */ + private Long materialsId; + + /** + * 材料名称 + */ + private String materialsName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 出入库状态 + */ + private String outPut; + + /** + * 出/入库的数量 + */ + private Long number; + + /** + * 出/入库操作时间 + */ + private Date outPutTime; + + /** + * 剩余库存数量(记录最后一次操作留下的库存数) + */ + private Long residue; + + /** + * 操作人(入库人、领料人) + */ + private String operator; + + /** + * 处理方式 + */ + private String disposition; + + /** + * 交接单位(班组) + */ + private String recipient; + + /** + * 领用人 + */ + private String shipper; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryUpdateReq.java new file mode 100644 index 0000000..6f4e44f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/dto/materialsinventory/MatMaterialsInventoryUpdateReq.java @@ -0,0 +1,69 @@ +package org.dromara.materials.domain.dto.materialsinventory; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class MatMaterialsInventoryUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3431952359907567659L; + + /** + * 主键id + */ + private Long id; + + /** + * 材料id + */ + private Long materialsId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 出入库状态 + */ + private String outPut; + + /** + * 出/入库操作时间 + */ + private Date outPutTime; + + /** + * 材料出入证明 + */ + private String path; + + /** + * 处理方式 + */ + private String disposition; + + /** + * 交接单位(班组) + */ + private String recipient; + + /** + * 领用人 + */ + private String shipper; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/enums/MatMaterialsInventoryOutPutEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/enums/MatMaterialsInventoryOutPutEnum.java new file mode 100644 index 0000000..9f0cb32 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/enums/MatMaterialsInventoryOutPutEnum.java @@ -0,0 +1,24 @@ +package org.dromara.materials.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/28 11:00 + */ +@Getter +public enum MatMaterialsInventoryOutPutEnum { + + PUT("入库", "0"), + OUT("出库", "1"); + + private final String text; + + private final String value; + + MatMaterialsInventoryOutPutEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/company/MatCompanyVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/company/MatCompanyVo.java new file mode 100644 index 0000000..86b6627 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/company/MatCompanyVo.java @@ -0,0 +1,85 @@ +package org.dromara.materials.domain.vo.company; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.materials.domain.MatCompany; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 公司视图对象 mat_company + * + * @author lilemy + * @date 2025-03-06 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = MatCompany.class) +public class MatCompanyVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 公司名称 + */ + @ExcelProperty(value = "公司名称") + private String companyName; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String principal; + + /** + * 负责人电话 + */ + @ExcelProperty(value = "负责人电话") + private String principalPhone; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 资质情况 + */ + @ExcelProperty(value = "资质情况") + private String qualification; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialissue/MatMaterialIssueVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialissue/MatMaterialIssueVo.java new file mode 100644 index 0000000..744ab07 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialissue/MatMaterialIssueVo.java @@ -0,0 +1,152 @@ +package org.dromara.materials.domain.vo.materialissue; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.materials.domain.MatMaterialIssue; +import org.dromara.materials.domain.vo.materialissueitem.MatMaterialIssueItemVo; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 物料领料单视图对象 mat_material_issue + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@AutoMapper(target = MatMaterialIssue.class) +public class MatMaterialIssueVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 领料单位 + */ + private String issueUnit; + + /** + * 保管单位 + */ + private String storageUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 合格证份数 + */ + private Integer certCount; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 合格证文件 + */ + private List certCountFile; + + /** + * 出厂报告份数 + */ + private Integer reportCount; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 出厂报告文件 + */ + private List reportCountFile; + + /** + * 技术资料份数 + */ + private Integer techDocCount; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 技术资料文件 + */ + private List techDocCountFile; + + /** + * 厂家资质文件份数 + */ + private Integer licenseCount; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 厂家资质文件 + */ + private List licenseCountFile; + + /** + * 备注 + */ + private String remark; + + /** + * 明细项列表 + */ + private List itemList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialissueitem/MatMaterialIssueItemVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialissueitem/MatMaterialIssueItemVo.java new file mode 100644 index 0000000..bbc3366 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialissueitem/MatMaterialIssueItemVo.java @@ -0,0 +1,75 @@ +package org.dromara.materials.domain.vo.materialissueitem; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.materials.domain.MatMaterialIssueItem; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + + +/** + * 物料领料单明细项视图对象 mat_material_issue_item + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@AutoMapper(target = MatMaterialIssueItem.class) +public class MatMaterialIssueItemVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 领料单id + */ + private Long issueId; + + /** + * 名称 + */ + private String name; + + /** + * 规格 + */ + private String specification; + + /** + * 单位 + */ + private String unit; + + /** + * 库存 + */ + private BigDecimal stockQuantity; + + /** + * 领取 + */ + private BigDecimal issuedQuantity; + + /** + * 剩余 + */ + private BigDecimal remainingQuantity; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialreceive/MatMaterialReceiveVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialreceive/MatMaterialReceiveVo.java new file mode 100644 index 0000000..d7eefef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialreceive/MatMaterialReceiveVo.java @@ -0,0 +1,152 @@ +package org.dromara.materials.domain.vo.materialreceive; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.materials.domain.MatMaterialReceive; +import org.dromara.materials.domain.vo.materialreceiveitem.MatMaterialReceiveItemVo; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 物料接收单视图对象 mat_material_receive + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@AutoMapper(target = MatMaterialReceive.class) +public class MatMaterialReceiveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 材料来源(1甲供 2乙供) + */ + private String materialSource; + + /** + * 表单编号 + */ + private String formCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 设备材料名称 + */ + private String materialName; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 订货单位 + */ + private String orderingUnit; + + /** + * 供货单位 + */ + private String supplierUnit; + + /** + * 缺陷情况(承包单位填写) + */ + private String defectDescription; + + /** + * 合格证份数 + */ + private Integer certCount; + + /** + * 合格证文件 + */ + private String certCountFileId; + + /** + * 合格证文件 + */ + private List certCountFile; + + /** + * 出厂报告份数 + */ + private Integer reportCount; + + /** + * 出厂报告文件 + */ + private String reportCountFileId; + + /** + * 出厂报告文件 + */ + private List reportCountFile; + + /** + * 技术资料份数 + */ + private Integer techDocCount; + + /** + * 技术资料文件 + */ + private String techDocCountFileId; + + /** + * 技术资料文件 + */ + private List techDocCountFile; + + /** + * 厂家资质文件份数 + */ + private Integer licenseCount; + + /** + * 厂家资质文件 + */ + private String licenseCountFileId; + + /** + * 厂家资质文件 + */ + private List licenseCountFile; + + /** + * 设备材料入库/移交 + */ + private String storageType; + + /** + * 备注 + */ + private String remark; + + /** + * 明细项列表 + */ + private List itemList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialreceiveitem/MatMaterialReceiveItemVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialreceiveitem/MatMaterialReceiveItemVo.java new file mode 100644 index 0000000..340d844 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialreceiveitem/MatMaterialReceiveItemVo.java @@ -0,0 +1,75 @@ +package org.dromara.materials.domain.vo.materialreceiveitem; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.materials.domain.MatMaterialReceiveItem; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + + +/** + * 物料接收单明细项视图对象 mat_material_receive_item + * + * @author lilemy + * @date 2025-07-04 + */ +@Data +@AutoMapper(target = MatMaterialReceiveItem.class) +public class MatMaterialReceiveItemVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 接收单id + */ + private Long receiveId; + + /** + * 名称 + */ + private String name; + + /** + * 规格 + */ + private String specification; + + /** + * 单位 + */ + private String unit; + + /** + * 数量 + */ + private BigDecimal quantity; + + /** + * 验收 + */ + private BigDecimal acceptedQuantity; + + /** + * 缺件 + */ + private BigDecimal shortageQuantity; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materials/MatMaterialsGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materials/MatMaterialsGisVo.java new file mode 100644 index 0000000..ea94e9e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materials/MatMaterialsGisVo.java @@ -0,0 +1,45 @@ +package org.dromara.materials.domain.vo.materials; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 10:39 + */ +@Data +public class MatMaterialsGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = 871786102998065916L; + + /** + * 材料名称 + */ + private String materialsName; + + /** + * 计量单位 + */ + private String weightId; + + /** + * 预计材料数量 + */ + private String quantityCount; + + /** + * 入库数量 + */ + private Long putCount; + + /** + * 出库数量 + */ + private Long outCount; + + private Integer value; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materials/MatMaterialsVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materials/MatMaterialsVo.java new file mode 100644 index 0000000..fa81166 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materials/MatMaterialsVo.java @@ -0,0 +1,110 @@ +package org.dromara.materials.domain.vo.materials; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.materials.domain.MatMaterials; +import org.dromara.materials.domain.vo.company.MatCompanyVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + + +/** + * 材料名称视图对象 mat_materials + * + * @author lilemy + * @date 2025-03-06 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = MatMaterials.class) +public class MatMaterialsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 材料名称 + */ + @ExcelProperty(value = "材料名称") + private String materialsName; + + /** + * 公司id + */ + @ExcelProperty(value = "公司id") + private Long companyId; + + /** + * 公司信息 + */ + @ExcelProperty(value = "公司信息") + private MatCompanyVo companyVo; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 规格型号名称 + */ + @ExcelProperty(value = "规格型号名称") + private String typeSpecificationName; + + /** + * 文件详情列表 + */ + private Map fileOssMap; + + /** + * 使用部位 + */ + @ExcelProperty(value = "使用部位") + private String usePart; + + /** + * 计量单位 + */ + @ExcelProperty(value = "计量单位") + private String weightId; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 预计材料数量 + */ + @ExcelProperty(value = "预计材料数量") + private String quantityCount; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialsinventory/MatMaterialsInventoryVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialsinventory/MatMaterialsInventoryVo.java new file mode 100644 index 0000000..ca910c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/domain/vo/materialsinventory/MatMaterialsInventoryVo.java @@ -0,0 +1,117 @@ +package org.dromara.materials.domain.vo.materialsinventory; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.materials.domain.MatMaterialsInventory; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 材料出/入库视图对象 mat_materials_inventory + * + * @author lilemy + * @date 2025-03-06 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = MatMaterialsInventory.class) +public class MatMaterialsInventoryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 材料id + */ + @ExcelProperty(value = "材料id") + private Long materialsId; + + /** + * 材料名称 + */ + private String materialsName; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 出入库状态 + */ + @ExcelProperty(value = "出入库状态") + private String outPut; + + /** + * 出/入库的数量 + */ + @ExcelProperty(value = "出入库的数量") + private Long number; + + /** + * 出/入库操作时间 + */ + @ExcelProperty(value = "出入库操作时间") + private Date outPutTime; + + /** + * 剩余库存数量(记录最后一次操作留下的库存数) + */ + @ExcelProperty(value = "剩余库存数量") + private Long residue; + + /** + * 操作人(入库人、领料人) + */ + @ExcelProperty(value = "操作人") + private String operator; + + /** + * 材料出入证明 + */ + @ExcelProperty(value = "材料出入证明") + private String path; + + /** + * 处理方式 + */ + @ExcelProperty(value = "处理方式") + private String disposition; + + /** + * 交接单位(班组) + */ + @ExcelProperty(value = "交接单位") + private String recipient; + + /** + * 领用人 + */ + @ExcelProperty(value = "领用人") + private String shipper; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatCompanyMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatCompanyMapper.java new file mode 100644 index 0000000..91497c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatCompanyMapper.java @@ -0,0 +1,15 @@ +package org.dromara.materials.mapper; + +import org.dromara.materials.domain.MatCompany; +import org.dromara.materials.domain.vo.company.MatCompanyVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 公司Mapper接口 + * + * @author lilemy + * @date 2025-03-06 + */ +public interface MatCompanyMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialIssueItemMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialIssueItemMapper.java new file mode 100644 index 0000000..35f3b81 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialIssueItemMapper.java @@ -0,0 +1,15 @@ +package org.dromara.materials.mapper; + +import org.dromara.materials.domain.MatMaterialIssueItem; +import org.dromara.materials.domain.vo.materialissueitem.MatMaterialIssueItemVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 物料领料单明细项Mapper接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface MatMaterialIssueItemMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialIssueMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialIssueMapper.java new file mode 100644 index 0000000..3172a15 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialIssueMapper.java @@ -0,0 +1,15 @@ +package org.dromara.materials.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.materials.domain.MatMaterialIssue; +import org.dromara.materials.domain.vo.materialissue.MatMaterialIssueVo; + +/** + * 物料领料单Mapper接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface MatMaterialIssueMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialReceiveItemMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialReceiveItemMapper.java new file mode 100644 index 0000000..67a749e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialReceiveItemMapper.java @@ -0,0 +1,15 @@ +package org.dromara.materials.mapper; + +import org.dromara.materials.domain.MatMaterialReceiveItem; +import org.dromara.materials.domain.vo.materialreceiveitem.MatMaterialReceiveItemVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 物料接收单明细项Mapper接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface MatMaterialReceiveItemMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialReceiveMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialReceiveMapper.java new file mode 100644 index 0000000..5b86bb9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialReceiveMapper.java @@ -0,0 +1,15 @@ +package org.dromara.materials.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.materials.domain.MatMaterialReceive; +import org.dromara.materials.domain.vo.materialreceive.MatMaterialReceiveVo; + +/** + * 物料接收单Mapper接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface MatMaterialReceiveMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialsInventoryMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialsInventoryMapper.java new file mode 100644 index 0000000..e3a6b6d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialsInventoryMapper.java @@ -0,0 +1,15 @@ +package org.dromara.materials.mapper; + +import org.dromara.materials.domain.MatMaterialsInventory; +import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 材料出/入库Mapper接口 + * + * @author lilemy + * @date 2025-03-06 + */ +public interface MatMaterialsInventoryMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialsMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialsMapper.java new file mode 100644 index 0000000..15ce73e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/mapper/MatMaterialsMapper.java @@ -0,0 +1,15 @@ +package org.dromara.materials.mapper; + +import org.dromara.materials.domain.MatMaterials; +import org.dromara.materials.domain.vo.materials.MatMaterialsVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 材料名称Mapper接口 + * + * @author lilemy + * @date 2025-03-06 + */ +public interface MatMaterialsMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatCompanyService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatCompanyService.java new file mode 100644 index 0000000..6a46fa8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatCompanyService.java @@ -0,0 +1,98 @@ +package org.dromara.materials.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.materials.domain.MatCompany; +import org.dromara.materials.domain.dto.company.MatCompanyCreateReq; +import org.dromara.materials.domain.dto.company.MatCompanyQueryReq; +import org.dromara.materials.domain.dto.company.MatCompanyUpdateReq; +import org.dromara.materials.domain.vo.company.MatCompanyVo; + +import java.util.Collection; +import java.util.List; + +/** + * 公司Service接口 + * + * @author lilemy + * @date 2025-03-06 + */ +public interface IMatCompanyService extends IService { + + /** + * 查询公司 + * + * @param id 主键 + * @return 公司 + */ + MatCompanyVo queryById(Long id); + + /** + * 分页查询公司列表 + * + * @param req 查询条件 + * @param pageQuery 分页条件 + * @return 公司分页列表 + */ + TableDataInfo queryPageList(MatCompanyQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的公司列表 + * + * @param req 查询条件 + * @return 公司列表 + */ + List queryList(MatCompanyQueryReq req); + + /** + * 新增公司 + * + * @param req 公司 + * @return 新增公司id + */ + Long insertByBo(MatCompanyCreateReq req); + + /** + * 修改公司 + * + * @param req 公司 + * @return 是否修改成功 + */ + Boolean updateByBo(MatCompanyUpdateReq req); + + /** + * 校验并批量删除公司信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取封装视图对象 + * + * @param company 实体对象 + * @return 封装视图对象 + */ + MatCompanyVo getVo(MatCompany company); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(MatCompanyQueryReq req); + + /** + * 获取公司分页对象视图 + * + * @param companyPage 公司分页对象 + * @return 公司分页对象视图 + */ + Page getCompanyVoPage(Page companyPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialIssueItemService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialIssueItemService.java new file mode 100644 index 0000000..bcf33b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialIssueItemService.java @@ -0,0 +1,41 @@ +package org.dromara.materials.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.materials.domain.MatMaterialIssueItem; +import org.dromara.materials.domain.vo.materialissueitem.MatMaterialIssueItemVo; + +import java.util.List; + +/** + * 物料领料单明细项Service接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface IMatMaterialIssueItemService extends IService { + + /** + * 查询物料领料单明细项列表 + * + * @param issueId 领料单id + * @return 物料领料单明细项列表 + */ + List queryListByIssueId(Long issueId); + + /** + * 获取物料领料单明细项视图对象 + * + * @param matMaterialIssueItem 物料领料单明细项对象 + * @return 物料领料单明细项视图对象 + */ + MatMaterialIssueItemVo getVo(MatMaterialIssueItem matMaterialIssueItem); + + /** + * 获取物料领料单明细项视图对象列表 + * + * @param matMaterialIssueItemList 物料领料单明细项对象列表 + * @return 物料领料单明细项视图对象列表 + */ + List getVoList(List matMaterialIssueItemList); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialIssueService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialIssueService.java new file mode 100644 index 0000000..ab420cb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialIssueService.java @@ -0,0 +1,106 @@ +package org.dromara.materials.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.materials.domain.MatMaterialIssue; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueCreateReq; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueQueryReq; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueUpdateReq; +import org.dromara.materials.domain.vo.materialissue.MatMaterialIssueVo; + +import java.util.Collection; +import java.util.List; + +/** + * 物料领料单Service接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface IMatMaterialIssueService extends IService { + + /** + * 查询物料领料单 + * + * @param id 主键 + * @return 物料领料单 + */ + MatMaterialIssueVo queryById(Long id); + + /** + * 分页查询物料领料单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 物料领料单分页列表 + */ + TableDataInfo queryPageList(MatMaterialIssueQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的物料领料单列表 + * + * @param req 查询条件 + * @return 物料领料单列表 + */ + List queryList(MatMaterialIssueQueryReq req); + + /** + * 根据id导出word + * + * @param id 主键 + * @param response 响应 + */ + void exportWordById(Long id, HttpServletResponse response); + + /** + * 新增物料领料单 + * + * @param req 物料领料单 + * @return 是否新增成功 + */ + Boolean insertByBo(MatMaterialIssueCreateReq req); + + /** + * 修改物料领料单 + * + * @param req 物料领料单 + * @return 是否修改成功 + */ + Boolean updateByBo(MatMaterialIssueUpdateReq req); + + /** + * 批量删除物料领料单信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteByIds(Collection ids); + + /** + * 获取物料领料单视图对象 + * + * @param materialIssue 物料领料单对象 + * @return 物料领料单视图对象 + */ + MatMaterialIssueVo getVo(MatMaterialIssue materialIssue); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(MatMaterialIssueQueryReq req); + + /** + * 获取物料领料单分页对象视图 + * + * @param materialIssuePage 物料领料单分页对象 + * @return 物料领料单分页对象视图 + */ + Page getVoPage(Page materialIssuePage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialReceiveItemService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialReceiveItemService.java new file mode 100644 index 0000000..1438aba --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialReceiveItemService.java @@ -0,0 +1,41 @@ +package org.dromara.materials.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.materials.domain.MatMaterialReceiveItem; +import org.dromara.materials.domain.vo.materialreceiveitem.MatMaterialReceiveItemVo; + +import java.util.List; + +/** + * 物料接收单明细项Service接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface IMatMaterialReceiveItemService extends IService { + + /** + * 查询物料接收单明细项列表 + * + * @param issueId 接收单id + * @return 物料接收单明细项列表 + */ + List queryListByReceiveId(Long issueId); + + /** + * 获取物料接收单明细项视图对象 + * + * @param matMaterialReceiveItem 物料接收单明细项对象 + * @return 物料接收单明细项视图对象 + */ + MatMaterialReceiveItemVo getVo(MatMaterialReceiveItem matMaterialReceiveItem); + + /** + * 获取物料接收单明细项视图对象列表 + * + * @param matMaterialReceiveItemList 物料接收单明细项对象列表 + * @return 物料接收单明细项视图对象列表 + */ + List getVoList(List matMaterialReceiveItemList); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialReceiveService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialReceiveService.java new file mode 100644 index 0000000..a51e0ea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialReceiveService.java @@ -0,0 +1,106 @@ +package org.dromara.materials.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.materials.domain.MatMaterialReceive; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveCreateReq; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveQueryReq; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveUpdateReq; +import org.dromara.materials.domain.vo.materialreceive.MatMaterialReceiveVo; + +import java.util.Collection; +import java.util.List; + +/** + * 物料接收单Service接口 + * + * @author lilemy + * @date 2025-07-04 + */ +public interface IMatMaterialReceiveService extends IService { + + /** + * 查询物料接收单 + * + * @param id 主键 + * @return 物料接收单 + */ + MatMaterialReceiveVo queryById(Long id); + + /** + * 分页查询物料接收单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 物料接收单分页列表 + */ + TableDataInfo queryPageList(MatMaterialReceiveQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的物料接收单列表 + * + * @param req 查询条件 + * @return 物料接收单列表 + */ + List queryList(MatMaterialReceiveQueryReq req); + + /** + * 根据id导出word + * + * @param id 主键 + * @param response 响应 + */ + void exportWordById(Long id, HttpServletResponse response); + + /** + * 新增物料接收单 + * + * @param req 物料接收单 + * @return 是否新增成功 + */ + Boolean insertByBo(MatMaterialReceiveCreateReq req); + + /** + * 修改物料接收单 + * + * @param req 物料接收单 + * @return 是否修改成功 + */ + Boolean updateByBo(MatMaterialReceiveUpdateReq req); + + /** + * 批量删除物料接收单信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteByIds(Collection ids); + + /** + * 获取物料接收单视图对象 + * + * @param materialReceive 物料接收单对象 + * @return 物料接收单视图对象 + */ + MatMaterialReceiveVo getVo(MatMaterialReceive materialReceive); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(MatMaterialReceiveQueryReq req); + + /** + * 获取物料接收单分页对象视图 + * + * @param materialReceivePage 物料接收单分页对象 + * @return 物料接收单分页对象视图 + */ + Page getVoPage(Page materialReceivePage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialsInventoryService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialsInventoryService.java new file mode 100644 index 0000000..9adbe4f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialsInventoryService.java @@ -0,0 +1,99 @@ +package org.dromara.materials.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.materials.domain.MatMaterialsInventory; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryCreateReq; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryQueryReq; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryUpdateReq; +import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryVo; + +import java.util.Collection; +import java.util.List; + +/** + * 材料出/入库Service接口 + * + * @author lilemy + * @date 2025-03-06 + */ +public interface IMatMaterialsInventoryService extends IService { + + /** + * 查询材料出/入库 + * + * @param id 主键 + * @return 材料出/入库 + */ + MatMaterialsInventoryVo queryById(Long id); + + /** + * 分页查询材料出/入库列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 材料出/入库分页列表 + */ + TableDataInfo queryPageList(MatMaterialsInventoryQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的材料出/入库列表 + * + * @param req 查询条件 + * @return 材料出/入库列表 + */ + List queryList(MatMaterialsInventoryQueryReq req); + + /** + * 新增材料出/入库 + * + * @param req 材料出/入库 + * @return 是否新增成功 + */ + Long insertByBo(MatMaterialsInventoryCreateReq req); + + /** + * 修改材料出/入库 + * + * @param req 材料出/入库 + * @return 是否修改成功 + */ + Boolean updateByBo(MatMaterialsInventoryUpdateReq req); + + /** + * 校验并批量删除材料出/入库信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取材料出/入库视图对象 + * + * @param MaterialsInventory 材料出/入库对象 + * @return 材料出/入库视图对象 + */ + MatMaterialsInventoryVo getVo(MatMaterialsInventory MaterialsInventory); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(MatMaterialsInventoryQueryReq req); + + /** + * 获取材料出/入库分页对象视图 + * + * @param materialsInventoryPage 材料出/入库分页对象 + * @return 材料出/入库分页对象视图 + */ + Page getVoPage(Page materialsInventoryPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialsService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialsService.java new file mode 100644 index 0000000..22def9a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/IMatMaterialsService.java @@ -0,0 +1,108 @@ +package org.dromara.materials.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.materials.domain.MatMaterials; +import org.dromara.materials.domain.dto.materials.MatMaterialsCreateReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsGisReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsQueryReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsUpdateReq; +import org.dromara.materials.domain.vo.materials.MatMaterialsVo; +import org.dromara.materials.domain.vo.materials.MatMaterialsGisVo; + +import java.util.Collection; +import java.util.List; + +/** + * 材料名称Service接口 + * + * @author lilemy + * @date 2025-03-06 + */ +public interface IMatMaterialsService extends IService { + + /** + * 查询材料名称 + * + * @param id 主键 + * @return 材料名称 + */ + MatMaterialsVo queryById(Long id); + + /** + * 分页查询材料名称列表 + * + * @param req 查询条件 + * @param pageQuery 分页条件 + * @return 材料名称分页列表 + */ + TableDataInfo queryPageList(MatMaterialsQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的材料名称列表 + * + * @param req 查询条件 + * @return 材料名称列表 + */ + List queryList(MatMaterialsQueryReq req); + + /** + * 查询材料大屏信息列表 + * + * @param req 查询条件 + * @return 材料大屏信息列表 + */ + List queryGisList(MatMaterialsGisReq req); + + /** + * 新增材料名称 + * + * @param req 材料名称 + * @return 是否新增成功 + */ + Long insertByBo(MatMaterialsCreateReq req); + + /** + * 修改材料名称 + * + * @param req 材料名称 + * @return 是否修改成功 + */ + Boolean updateByBo(MatMaterialsUpdateReq req); + + /** + * 校验并批量删除材料名称信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取材料视图 + * + * @param materials 材料 + * @return 材料视图 + */ + MatMaterialsVo getBusMaterialsVo(MatMaterials materials); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(MatMaterialsQueryReq req); + + /** + * 获取材料分页对象视图 + * + * @param materialsPage 材料分页对象 + * @return 材料分页对象视图 + */ + Page getMaterialsVoPage(Page materialsPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatCompanyServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatCompanyServiceImpl.java new file mode 100644 index 0000000..f772f17 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatCompanyServiceImpl.java @@ -0,0 +1,284 @@ +package org.dromara.materials.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.PhoneUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.materials.domain.MatCompany; +import org.dromara.materials.domain.MatMaterials; +import org.dromara.materials.domain.dto.company.MatCompanyCreateReq; +import org.dromara.materials.domain.dto.company.MatCompanyQueryReq; +import org.dromara.materials.domain.dto.company.MatCompanyUpdateReq; +import org.dromara.materials.domain.vo.company.MatCompanyVo; +import org.dromara.materials.mapper.MatCompanyMapper; +import org.dromara.materials.service.IMatCompanyService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 公司Service业务层处理 + * + * @author lilemy + * @date 2025-03-06 + */ +@Service +public class MatCompanyServiceImpl extends ServiceImpl + implements IMatCompanyService { + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private MatMaterialsServiceImpl materialService; + + /** + * 查询公司 + * + * @param id 主键 + * @return 公司 + */ + @Override + public MatCompanyVo queryById(Long id) { + MatCompany company = this.getById(id); + if (company == null) { + throw new ServiceException("对应材料提供商不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(company); + } + + /** + * 分页查询公司列表 + * + * @param req 查询条件 + * @param pageQuery 分页信息 + * @return 公司分页列表 + */ + @Override + public TableDataInfo queryPageList(MatCompanyQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getCompanyVoPage(result)); + } + + /** + * 查询符合条件的公司列表 + * + * @param req 查询条件 + * @return 公司列表 + */ + @Override + public List queryList(MatCompanyQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增公司 + * + * @param req 公司 + * @return 新增公司id + */ + @Override + public Long insertByBo(MatCompanyCreateReq req) { + // 将实体类和 DTO 进行转换 + MatCompany company = new MatCompany(); + BeanUtils.copyProperties(req, company); + // 数据校验 + validEntityBeforeSave(company, true); + // 公司名不能重复 + Long count = this.lambdaQuery().eq(MatCompany::getCompanyName, req.getCompanyName()).count(); + if (count > 0) { + throw new ServiceException("公司名重复", HttpStatus.BAD_REQUEST); + } + // 写入数据库 + boolean save = this.save(company); + if (!save) { + throw new ServiceException("新增公司失败,数据库异常", HttpStatus.ERROR); + } + return company.getId(); + } + + /** + * 修改公司 + * + * @param req 公司 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(MatCompanyUpdateReq req) { + // 将实体类和 DTO 进行转换 + MatCompany company = new MatCompany(); + BeanUtils.copyProperties(req, company); + // 数据校验 + validEntityBeforeSave(company, false); + // 判断是否存在 + MatCompany oldCompany = this.getById(company.getId()); + if (oldCompany == null) { + throw new ServiceException("修改公司失败,数据不存在", HttpStatus.NOT_FOUND); + } + if (!req.getCompanyName().equals(oldCompany.getCompanyName())) { + Long count = this.lambdaQuery().eq(MatCompany::getCompanyName, oldCompany.getCompanyName()).count(); + if (count > 0) { + throw new ServiceException("公司名重复", HttpStatus.BAD_REQUEST); + } + } + // 操作数据库 + return this.updateById(company); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(MatCompany entity, Boolean create) { + // 做一些数据校验,如唯一约束 + String companyName = entity.getCompanyName(); + Long projectId = entity.getProjectId(); + String principal = entity.getPrincipal(); + String principalPhone = entity.getPrincipalPhone(); + if (create) { + if (StringUtils.isBlank(principal)) { + throw new ServiceException("负责人不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(principalPhone)) { + throw new ServiceException("负责人手机号不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(companyName)) { + throw new ServiceException("公司名称不能为空", HttpStatus.BAD_REQUEST); + } + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + } + // 查询项目是否存在 + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (StringUtils.isNotBlank(principalPhone) && !PhoneUtil.isPhone(principalPhone)) { + throw new ServiceException("负责人手机号格式不正确", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除公司信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + // 获取当前登录用户 + Long userId = LoginHelper.getUserId(); + List companyList = this.listByIds(ids); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + // 获取项目id列表 + List projectIdList = companyList.stream().map(MatCompany::getProjectId).toList(); + // 判断是否有权限操作对应项目下的内容 + projectService.validAuth(projectIdList, userId); + // 判断公司中是否还存在材料信息 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("company_id", ids); + if (materialService.count(queryWrapper) > 0) { + throw new ServiceException("删除公司失败,公司中存在材料信息", HttpStatus.BAD_REQUEST); + } + } + // 判断对应数据是否都存在 + if (companyList.size() != ids.size()) { + throw new ServiceException("删除公司失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取封装视图对象 + * + * @param company 实体对象 + * @return 封装视图对象 + */ + @Override + public MatCompanyVo getVo(MatCompany company) { + // 对象转封装类 + MatCompanyVo companyVo = new MatCompanyVo(); + if (company == null) { + return companyVo; + } + BeanUtils.copyProperties(company, companyVo); + return companyVo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(MatCompanyQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + String companyName = req.getCompanyName(); + Long projectId = req.getProjectId(); + String principal = req.getPrincipal(); + String principalPhone = req.getPrincipalPhone(); + String status = req.getStatus(); + String remark = req.getRemark(); + String qualification = req.getQualification(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(companyName), MatCompany::getCompanyName, companyName); + lqw.like(StringUtils.isNotBlank(principal), MatCompany::getPrincipal, principal); + lqw.like(StringUtils.isNotBlank(principalPhone), MatCompany::getPrincipalPhone, principalPhone); + lqw.like(StringUtils.isNotBlank(qualification), MatCompany::getQualification, qualification); + lqw.like(StringUtils.isNotBlank(remark), MatCompany::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(status), MatCompany::getStatus, status); + lqw.eq(ObjectUtils.isNotEmpty(id), MatCompany::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), MatCompany::getProjectId, projectId); + return lqw; + } + + /** + * 获取公司分页对象视图 + * + * @param companyPage 公司分页对象 + * @return 公司分页对象视图 + */ + @Override + public Page getCompanyVoPage(Page companyPage) { + List companyList = companyPage.getRecords(); + Page companyVoPage = new Page<>(companyPage.getCurrent(), companyPage.getSize(), companyPage.getTotal()); + if (CollUtil.isEmpty(companyList)) { + return companyVoPage; + } + // 对象列表 => 封装对象列表 + List companyVoList = companyList.stream().map(company -> { + MatCompanyVo companyVo = new MatCompanyVo(); + BeanUtils.copyProperties(company, companyVo); + return companyVo; + }).toList(); + companyVoPage.setRecords(companyVoList); + return companyVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialIssueItemServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialIssueItemServiceImpl.java new file mode 100644 index 0000000..c80879f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialIssueItemServiceImpl.java @@ -0,0 +1,59 @@ +package org.dromara.materials.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.dromara.materials.domain.MatMaterialIssueItem; +import org.dromara.materials.domain.vo.materialissueitem.MatMaterialIssueItemVo; +import org.dromara.materials.mapper.MatMaterialIssueItemMapper; +import org.dromara.materials.service.IMatMaterialIssueItemService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 物料领料单明细项Service业务层处理 + * + * @author lilemy + * @date 2025-07-04 + */ +@Service +public class MatMaterialIssueItemServiceImpl extends ServiceImpl + implements IMatMaterialIssueItemService { + + /** + * 查询物料领料单明细项列表 + * + * @param issueId 领料单id + * @return 物料领料单明细项列表 + */ + @Override + public List queryListByIssueId(Long issueId) { + return this.lambdaQuery() + .eq(MatMaterialIssueItem::getIssueId, issueId) + .list(); + } + + /** + * 获取物料领料单明细项视图对象 + * + * @param matMaterialIssueItem 物料领料单明细项对象 + * @return 物料领料单明细项视图对象 + */ + @Override + public MatMaterialIssueItemVo getVo(MatMaterialIssueItem matMaterialIssueItem) { + MatMaterialIssueItemVo vo = new MatMaterialIssueItemVo(); + BeanUtils.copyProperties(matMaterialIssueItem, vo); + return vo; + } + + /** + * 获取物料领料单明细项视图对象列表 + * + * @param matMaterialIssueItemList 物料领料单明细项对象列表 + * @return 物料领料单明细项视图对象列表 + */ + @Override + public List getVoList(List matMaterialIssueItemList) { + return matMaterialIssueItemList.stream().map(this::getVo).toList(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialIssueServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialIssueServiceImpl.java new file mode 100644 index 0000000..65a1913 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialIssueServiceImpl.java @@ -0,0 +1,529 @@ +package org.dromara.materials.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.deepoove.poi.XWPFTemplate; +import com.deepoove.poi.config.Configure; +import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.exception.OssException; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.utils.DocumentUtil; +import org.dromara.materials.constants.MatMaterialsConstant; +import org.dromara.materials.domain.MatMaterialIssue; +import org.dromara.materials.domain.MatMaterialIssueItem; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueCreateReq; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueQueryReq; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueUpdateReq; +import org.dromara.materials.domain.dto.materialissue.MatMaterialIssueWordDto; +import org.dromara.materials.domain.dto.materialissueitem.MatMaterialIssueItemDto; +import org.dromara.materials.domain.dto.materialissueitem.MatMaterialIssueItemWordDto; +import org.dromara.materials.domain.vo.materialissue.MatMaterialIssueVo; +import org.dromara.materials.mapper.MatMaterialIssueMapper; +import org.dromara.materials.service.IMatMaterialIssueItemService; +import org.dromara.materials.service.IMatMaterialIssueService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.zip.ZipOutputStream; + +/** + * 物料领料单Service业务层处理 + * + * @author lilemy + * @date 2025-07-04 + */ +@Slf4j +@Service +public class MatMaterialIssueServiceImpl extends ServiceImpl + implements IMatMaterialIssueService { + + @Resource + private ISysOssService ossService; + + @Resource + private IBusProjectService projectService; + + @Resource + private IMatMaterialIssueItemService materialIssueItemService; + + /** + * 查询物料领料单 + * + * @param id 主键 + * @return 物料领料单 + */ + @Override + public MatMaterialIssueVo queryById(Long id) { + MatMaterialIssue materialIssue = this.getById(id); + if (materialIssue == null) { + throw new ServiceException("物料领料单信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(materialIssue); + } + + /** + * 分页查询物料领料单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 物料领料单分页列表 + */ + @Override + public TableDataInfo queryPageList(MatMaterialIssueQueryReq req, PageQuery pageQuery) { + Page issuePage = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(issuePage)); + } + + /** + * 查询符合条件的物料领料单列表 + * + * @param req 查询条件 + * @return 物料领料单列表 + */ + @Override + public List queryList(MatMaterialIssueQueryReq req) { + return this.list(this.buildQueryWrapper(req)).stream().map(this::getVo).toList(); + } + + /** + * 根据id导出word + * + * @param id 主键 + * @param response 响应 + */ + @Override + public void exportWordById(Long id, HttpServletResponse response) { + MatMaterialIssue materialIssue = this.getById(id); + if (materialIssue == null) { + throw new ServiceException("物料领料单不存在"); + } + Path targetDir = Paths.get(MatMaterialsConstant.getMatMaterialIssueFileUrl(materialIssue)); + // 如果存在目录则直接返回,不存在则生成文件并返回 + if (!Files.exists(targetDir)) { + // 清理旧文件 + String baseUrl = MatMaterialsConstant.MATERIALS_ISSUE_FILE_URL + materialIssue.getId(); + try { + Path dirPath = Paths.get(baseUrl); + if (Files.exists(dirPath)) { + FileUtils.deleteDirectory(dirPath); + } + } catch (IOException e) { + log.error("文件目录:{},清理失败", baseUrl, e); + } + // 准备数据 + List itemList = materialIssueItemService.queryListByIssueId(id); + MatMaterialIssueWordDto data = this.getReplacementDto(materialIssue, itemList); + // 生成文件 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(MatMaterialsConstant.MATERIALS_ISSUE_TEMPLATE_PATH)) { + if (is == null) { + throw new ServiceException("模板文件不存在"); + } + LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy(); + Configure config = Configure.builder().bind("items", hackLoopTableRenderPolicy).build(); + XWPFTemplate template = XWPFTemplate.compile(is, config); + template.render(data); + // 创建目标目录 + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); + } + // 组合目标文件名 + String fileName = MatMaterialsConstant.getMatMaterialIssueFileName(materialIssue); + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) { + template.write(fos); + } + template.close(); + // 获取附件 + String certCountFileId = materialIssue.getCertCountFileId(); + String reportCountFileId = materialIssue.getReportCountFileId(); + String techDocCountFileId = materialIssue.getTechDocCountFileId(); + String licenseCountFileId = materialIssue.getLicenseCountFileId(); + if (StringUtils.isNotBlank(certCountFileId)) { + List ossIdList = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialIssueFileUrl(materialIssue) + "/合格证"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + if (StringUtils.isNotBlank(reportCountFileId)) { + List ossIdList = Arrays.stream(reportCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialIssueFileUrl(materialIssue) + "/出厂报告"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + if (StringUtils.isNotBlank(techDocCountFileId)) { + List ossIdList = Arrays.stream(techDocCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialIssueFileUrl(materialIssue) + "/技术资料"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + if (StringUtils.isNotBlank(licenseCountFileId)) { + List ossIdList = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialIssueFileUrl(materialIssue) + "/厂家资质文件"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + + } catch (IOException e) { + throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + } + } + // 设置响应头,返回ZIP文件 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + DocumentUtil.zipDirectory(targetDir, targetDir, zos); + zos.flush(); + } catch (Exception e) { + throw new OssException("生成ZIP文件失败,错误信息: " + e.getMessage()); + } + } + + /** + * 新增物料领料单 + * + * @param req 物料领料单 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(MatMaterialIssueCreateReq req) { + MatMaterialIssue materialIssue = new MatMaterialIssue(); + BeanUtils.copyProperties(req, materialIssue); + validEntityBeforeSave(materialIssue, true); + getFileSize(materialIssue, + req.getLicenseCountFileId(), + req.getReportCountFileId(), + req.getTechDocCountFileId(), + req.getCertCountFileId()); + boolean save = this.save(materialIssue); + if (!save) { + throw new ServiceException("物料领料单新增失败", HttpStatus.ERROR); + } + List itemList = req.getItemList(); + if (CollUtil.isNotEmpty(itemList)) { + List materialIssueItemList = itemList.stream().map(item -> { + MatMaterialIssueItem materialIssueItem = new MatMaterialIssueItem(); + BeanUtils.copyProperties(item, materialIssueItem); + materialIssueItem.setIssueId(materialIssue.getId()); + materialIssueItem.setProjectId(materialIssue.getProjectId()); + return materialIssueItem; + }).toList(); + boolean result = materialIssueItemService.saveBatch(materialIssueItemList); + if (!result) { + throw new ServiceException("物料领料单明细项新增失败", HttpStatus.ERROR); + } + } + return true; + } + + /** + * 修改物料领料单 + * + * @param req 物料领料单 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(MatMaterialIssueUpdateReq req) { + Long id = req.getId(); + MatMaterialIssue oldMaterialIssue = this.getById(id); + if (oldMaterialIssue == null) { + throw new ServiceException("修改物料收货单失败,数据不存在", HttpStatus.NOT_FOUND); + } + MatMaterialIssue materialIssue = new MatMaterialIssue(); + BeanUtils.copyProperties(req, materialIssue); + validEntityBeforeSave(materialIssue, false); + getFileSize(materialIssue, + req.getLicenseCountFileId(), + req.getReportCountFileId(), + req.getTechDocCountFileId(), + req.getCertCountFileId()); + boolean update = this.updateById(materialIssue); + if (!update) { + throw new ServiceException("物料领料单修改失败", HttpStatus.ERROR); + } + // 删除旧的 + List oldMaterialIssueItemList = materialIssueItemService.queryListByIssueId(id); + if (CollUtil.isNotEmpty(oldMaterialIssueItemList)) { + boolean result = materialIssueItemService.removeBatchByIds(oldMaterialIssueItemList); + if (!result) { + throw new ServiceException("物料领料单明细项删除失败", HttpStatus.ERROR); + } + } + // 重新添加 + List itemList = req.getItemList(); + if (CollUtil.isNotEmpty(itemList)) { + List materialIssueItemList = itemList.stream().map(item -> { + MatMaterialIssueItem materialIssueItem = new MatMaterialIssueItem(); + BeanUtils.copyProperties(item, materialIssueItem); + materialIssueItem.setIssueId(id); + materialIssueItem.setProjectId(materialIssue.getProjectId()); + return materialIssueItem; + }).toList(); + boolean result = materialIssueItemService.saveBatch(materialIssueItemList); + if (!result) { + throw new ServiceException("物料领料单明细项新增失败", HttpStatus.ERROR); + } + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(MatMaterialIssue entity, Boolean create) { + // 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + String materialSource = entity.getMaterialSource(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(materialSource)) { + throw new ServiceException("物料来源不能为空", HttpStatus.BAD_REQUEST); + } + } + // 查询项目是否存在 + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 批量删除物料领料单信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteByIds(Collection ids) { + List itemList = materialIssueItemService.lambdaQuery() + .in(MatMaterialIssueItem::getIssueId, ids) + .list(); + if (CollUtil.isNotEmpty(itemList)) { + materialIssueItemService.removeBatchByIds(itemList); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取物料领料单视图对象 + * + * @param materialIssue 物料领料单对象 + * @return 物料领料单视图对象 + */ + @Override + public MatMaterialIssueVo getVo(MatMaterialIssue materialIssue) { + MatMaterialIssueVo vo = new MatMaterialIssueVo(); + BeanUtils.copyProperties(materialIssue, vo); + List itemList = materialIssueItemService.queryListByIssueId(materialIssue.getId()); + if (CollUtil.isNotEmpty(itemList)) { + vo.setItemList(materialIssueItemService.getVoList(itemList)); + } + String licenseCountFileId = materialIssue.getLicenseCountFileId(); + if (StringUtils.isNotBlank(licenseCountFileId)) { + List ossIdList = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setLicenseCountFile(ossVoList); + } + String reportCountFileId = materialIssue.getReportCountFileId(); + if (StringUtils.isNotBlank(reportCountFileId)) { + List ossIdList = Arrays.stream(reportCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setReportCountFile(ossVoList); + } + String techDocCountFileId = materialIssue.getTechDocCountFileId(); + if (StringUtils.isNotBlank(techDocCountFileId)) { + List ossIdList = Arrays.stream(techDocCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setTechDocCountFile(ossVoList); + } + String certCountFileId = materialIssue.getCertCountFileId(); + if (StringUtils.isNotBlank(certCountFileId)) { + List ossIdList = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setCertCountFile(ossVoList); + } + return vo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(MatMaterialIssueQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String materialSource = req.getMaterialSource(); + String formCode = req.getFormCode(); + String projectName = req.getProjectName(); + String materialName = req.getMaterialName(); + String orderingUnit = req.getOrderingUnit(); + String supplierUnit = req.getSupplierUnit(); + String issueUnit = req.getIssueUnit(); + String storageUnit = req.getStorageUnit(); + lqw.like(StringUtils.isNotBlank(projectName), MatMaterialIssue::getProjectName, projectName); + lqw.like(StringUtils.isNotBlank(materialName), MatMaterialIssue::getMaterialName, materialName); + lqw.like(StringUtils.isNotBlank(orderingUnit), MatMaterialIssue::getOrderingUnit, orderingUnit); + lqw.like(StringUtils.isNotBlank(supplierUnit), MatMaterialIssue::getSupplierUnit, supplierUnit); + lqw.like(StringUtils.isNotBlank(issueUnit), MatMaterialIssue::getIssueUnit, issueUnit); + lqw.like(StringUtils.isNotBlank(storageUnit), MatMaterialIssue::getStorageUnit, storageUnit); + lqw.like(StringUtils.isNotBlank(formCode), MatMaterialIssue::getFormCode, formCode); + lqw.eq(ObjectUtils.isNotEmpty(projectId), MatMaterialIssue::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(materialSource), MatMaterialIssue::getMaterialSource, materialSource); + return lqw; + } + + /** + * 获取物料领料单分页对象视图 + * + * @param materialIssuePage 物料领料单分页对象 + * @return 物料领料单分页对象视图 + */ + @Override + public Page getVoPage(Page materialIssuePage) { + List materialIssueList = materialIssuePage.getRecords(); + Page materialIssueVoPage = new Page<>( + materialIssuePage.getCurrent(), + materialIssuePage.getSize(), + materialIssuePage.getTotal()); + if (CollUtil.isEmpty(materialIssueList)) { + return materialIssueVoPage; + } + // 对象列表 => 封装对象列表 + List materialIssueVoList = materialIssueList.stream().map(materialIssue -> { + MatMaterialIssueVo materialIssueVo = new MatMaterialIssueVo(); + BeanUtils.copyProperties(materialIssue, materialIssueVo); + return materialIssueVo; + }).toList(); + materialIssueVoPage.setRecords(materialIssueVoList); + return materialIssueVoPage; + } + + /** + * 获取文件数量 + * + * @param materialIssue 物料领料单对象 + * @param licenseCountFileId 证书文件id + * @param reportCountFileId 报表文件id + * @param techDocCountFileId 技术文档文件id + * @param certCountFileId 证书文件id + */ + private void getFileSize(MatMaterialIssue materialIssue, String licenseCountFileId, + String reportCountFileId, String techDocCountFileId, String certCountFileId) { + if (StringUtils.isNotBlank(licenseCountFileId)) { + int size = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialIssue.setLicenseCount(size); + } + if (StringUtils.isNotBlank(reportCountFileId)) { + int size = Arrays.stream(reportCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialIssue.setReportCount(size); + } + if (StringUtils.isNotBlank(techDocCountFileId)) { + int size = Arrays.stream(techDocCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialIssue.setTechDocCount(size); + } + if (StringUtils.isNotBlank(certCountFileId)) { + int size = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialIssue.setLicenseCount(size); + } + } + + /** + * 根据实体获取替换数据 + * + * @param materialIssue 物料领料单对象 + * @param items 物料领料单明细列表 + * @return 替换 Word 数据 + */ + private MatMaterialIssueWordDto getReplacementDto(MatMaterialIssue materialIssue, List items) { + MatMaterialIssueWordDto dto = new MatMaterialIssueWordDto(); + BeanUtils.copyProperties(materialIssue, dto); + // 领料总数量 + int issuedQuantity = items.stream() + .map(MatMaterialIssueItem::getIssuedQuantity) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .intValue(); + dto.setTotalIssuedQuantity(issuedQuantity); + int stockQuantity = items.stream() + .map(MatMaterialIssueItem::getStockQuantity) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .intValue(); + dto.setTotalStockQuantity(stockQuantity); + int remainingQuantity = items.stream() + .map(MatMaterialIssueItem::getRemainingQuantity) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .intValue(); + dto.setTotalRemainingQuantity(remainingQuantity); + Integer certCount = materialIssue.getCertCount(); + dto.setIsCertCount(certCount > 0 ? "☑" : "□"); + Integer licenseCount = materialIssue.getLicenseCount(); + dto.setIsLicenseCount(licenseCount > 0 ? "☑" : "□"); + Integer reportCount = materialIssue.getReportCount(); + dto.setIsReportCount(reportCount > 0 ? "☑" : "□"); + Integer techDocCount = materialIssue.getTechDocCount(); + dto.setIsTechDocCount(techDocCount > 0 ? "☑" : "□"); + // 明细项信息 + List dtoItems = new ArrayList<>(); + for (int i = 1; i <= items.size(); i++) { + MatMaterialIssueItem item = items.get(i - 1); + MatMaterialIssueItemWordDto itemDto = new MatMaterialIssueItemWordDto(); + BeanUtils.copyProperties(item, itemDto); + itemDto.setNo(i); + itemDto.setIssuedQuantity(item.getIssuedQuantity().intValue()); + itemDto.setRemainingQuantity(item.getRemainingQuantity().intValue()); + itemDto.setStockQuantity(item.getStockQuantity().intValue()); + dtoItems.add(itemDto); + } + dto.setItems(dtoItems); + return dto; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialReceiveItemServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialReceiveItemServiceImpl.java new file mode 100644 index 0000000..e8d8475 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialReceiveItemServiceImpl.java @@ -0,0 +1,59 @@ +package org.dromara.materials.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.dromara.materials.domain.MatMaterialReceiveItem; +import org.dromara.materials.domain.vo.materialreceiveitem.MatMaterialReceiveItemVo; +import org.dromara.materials.mapper.MatMaterialReceiveItemMapper; +import org.dromara.materials.service.IMatMaterialReceiveItemService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 物料接收单明细项Service业务层处理 + * + * @author lilemy + * @date 2025-07-04 + */ +@Service +public class MatMaterialReceiveItemServiceImpl extends ServiceImpl + implements IMatMaterialReceiveItemService { + + /** + * 查询物料接收单明细项列表 + * + * @param issueId 接收单id + * @return 物料接收单明细项列表 + */ + @Override + public List queryListByReceiveId(Long issueId) { + return this.lambdaQuery() + .eq(MatMaterialReceiveItem::getReceiveId, issueId) + .list(); + } + + /** + * 获取物料接收单明细项视图对象 + * + * @param matMaterialReceiveItem 物料接收单明细项对象 + * @return 物料接收单明细项视图对象 + */ + @Override + public MatMaterialReceiveItemVo getVo(MatMaterialReceiveItem matMaterialReceiveItem) { + MatMaterialReceiveItemVo vo = new MatMaterialReceiveItemVo(); + BeanUtils.copyProperties(matMaterialReceiveItem, vo); + return vo; + } + + /** + * 获取物料接收单明细项视图对象列表 + * + * @param matMaterialReceiveItemList 物料接收单明细项对象列表 + * @return 物料接收单明细项视图对象列表 + */ + @Override + public List getVoList(List matMaterialReceiveItemList) { + return matMaterialReceiveItemList.stream().map(this::getVo).toList(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialReceiveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialReceiveServiceImpl.java new file mode 100644 index 0000000..f53d643 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialReceiveServiceImpl.java @@ -0,0 +1,546 @@ +package org.dromara.materials.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.deepoove.poi.XWPFTemplate; +import com.deepoove.poi.config.Configure; +import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.exception.OssException; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.utils.DocumentUtil; +import org.dromara.materials.constants.MatMaterialsConstant; +import org.dromara.materials.domain.MatMaterialReceive; +import org.dromara.materials.domain.MatMaterialReceiveItem; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveCreateReq; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveQueryReq; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveUpdateReq; +import org.dromara.materials.domain.dto.materialreceive.MatMaterialReceiveWordDto; +import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemDto; +import org.dromara.materials.domain.dto.materialreceiveitem.MatMaterialReceiveItemWordDto; +import org.dromara.materials.domain.vo.materialreceive.MatMaterialReceiveVo; +import org.dromara.materials.mapper.MatMaterialReceiveMapper; +import org.dromara.materials.service.IMatMaterialReceiveItemService; +import org.dromara.materials.service.IMatMaterialReceiveService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.zip.ZipOutputStream; + +/** + * 物料接收单Service业务层处理 + * + * @author lilemy + * @date 2025-07-04 + */ +@Slf4j +@Service +public class MatMaterialReceiveServiceImpl extends ServiceImpl + implements IMatMaterialReceiveService { + + @Resource + private ISysOssService ossService; + + @Resource + private IBusProjectService projectService; + + @Resource + private IMatMaterialReceiveItemService materialReceiveItemService; + + /** + * 查询物料接收单 + * + * @param id 主键 + * @return 物料接收单 + */ + @Override + public MatMaterialReceiveVo queryById(Long id) { + MatMaterialReceive materialReceive = this.getById(id); + if (materialReceive == null) { + throw new ServiceException("物料接收单信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(materialReceive); + } + + /** + * 分页查询物料接收单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 物料接收单分页列表 + */ + @Override + public TableDataInfo queryPageList(MatMaterialReceiveQueryReq req, PageQuery pageQuery) { + Page receivePage = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(receivePage)); + } + + /** + * 查询符合条件的物料接收单列表 + * + * @param req 查询条件 + * @return 物料接收单列表 + */ + @Override + public List queryList(MatMaterialReceiveQueryReq req) { + return this.list(this.buildQueryWrapper(req)).stream().map(this::getVo).toList(); + } + + /** + * 根据id导出word + * + * @param id 主键 + * @param response 响应 + */ + @Override + public void exportWordById(Long id, HttpServletResponse response) { + MatMaterialReceive materialReceive = this.getById(id); + if (materialReceive == null) { + throw new ServiceException("物料接收单不存在"); + } + Path targetDir = Paths.get(MatMaterialsConstant.getMatMaterialReceiveFileUrl(materialReceive)); + // 如果存在目录则直接返回,不存在则生成文件并返回 + if (!Files.exists(targetDir)) { + // 清理旧文件 + String baseUrl = MatMaterialsConstant.MATERIALS_RECEIVE_FILE_URL + materialReceive.getId(); + try { + Path dirPath = Paths.get(baseUrl); + if (Files.exists(dirPath)) { + FileUtils.deleteDirectory(dirPath); + } + } catch (IOException e) { + log.error("文件目录:{},清理失败", baseUrl, e); + } + // 准备数据 + List itemList = materialReceiveItemService.queryListByReceiveId(id); + MatMaterialReceiveWordDto data = this.getReplacementDto(materialReceive, itemList); + // 生成文件 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(MatMaterialsConstant.MATERIALS_RECEIVE_TEMPLATE_PATH)) { + if (is == null) { + throw new ServiceException("模板文件不存在"); + } + LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy(); + Configure config = Configure.builder().bind("items", hackLoopTableRenderPolicy).build(); + XWPFTemplate template = XWPFTemplate.compile(is, config); + template.render(data); + // 创建目标目录 + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); + } + // 组合目标文件名 + String fileName = MatMaterialsConstant.getMatMaterialReceiveFileName(materialReceive); + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) { + template.write(fos); + } + template.close(); + // 获取附件 + String certCountFileId = materialReceive.getCertCountFileId(); + String reportCountFileId = materialReceive.getReportCountFileId(); + String techDocCountFileId = materialReceive.getTechDocCountFileId(); + String licenseCountFileId = materialReceive.getLicenseCountFileId(); + if (StringUtils.isNotBlank(certCountFileId)) { + List ossIdList = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialReceiveFileUrl(materialReceive) + "/合格证"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + if (StringUtils.isNotBlank(reportCountFileId)) { + List ossIdList = Arrays.stream(reportCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialReceiveFileUrl(materialReceive) + "/出厂报告"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + if (StringUtils.isNotBlank(techDocCountFileId)) { + List ossIdList = Arrays.stream(techDocCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialReceiveFileUrl(materialReceive) + "/技术资料"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + if (StringUtils.isNotBlank(licenseCountFileId)) { + List ossIdList = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = MatMaterialsConstant.getMatMaterialReceiveFileUrl(materialReceive) + "/厂家资质文件"; + for (SysOssVo ossVo : ossVoList) { + OssClient storage = OssFactory.instance(ossVo.getService()); + storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + } + } + + } catch (IOException e) { + throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + } + } + // 设置响应头,返回ZIP文件 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + DocumentUtil.zipDirectory(targetDir, targetDir, zos); + zos.flush(); + } catch (Exception e) { + throw new OssException("生成ZIP文件失败,错误信息: " + e.getMessage()); + } + } + + /** + * 新增物料接收单 + * + * @param req 物料接收单 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(MatMaterialReceiveCreateReq req) { + MatMaterialReceive materialReceive = new MatMaterialReceive(); + BeanUtils.copyProperties(req, materialReceive); + validEntityBeforeSave(materialReceive, true); + getFileSize(materialReceive, + req.getLicenseCountFileId(), + req.getReportCountFileId(), + req.getTechDocCountFileId(), + req.getCertCountFileId()); + boolean save = this.save(materialReceive); + if (!save) { + throw new ServiceException("物料接收单新增失败", HttpStatus.ERROR); + } + List itemList = req.getItemList(); + if (CollUtil.isNotEmpty(itemList)) { + List materialReceiveItemList = itemList.stream().map(item -> { + MatMaterialReceiveItem materialReceiveItem = new MatMaterialReceiveItem(); + BeanUtils.copyProperties(item, materialReceiveItem); + materialReceiveItem.setReceiveId(materialReceive.getId()); + materialReceiveItem.setProjectId(materialReceive.getProjectId()); + return materialReceiveItem; + }).toList(); + boolean result = materialReceiveItemService.saveBatch(materialReceiveItemList); + if (!result) { + throw new RuntimeException("物料接收单明细项新增失败"); + } + } + return true; + } + + /** + * 修改物料接收单 + * + * @param req 物料接收单 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(MatMaterialReceiveUpdateReq req) { + Long id = req.getId(); + MatMaterialReceive oldMaterialReceive = this.getById(id); + if (oldMaterialReceive == null) { + throw new ServiceException("修改物料收货单失败,数据不存在", HttpStatus.NOT_FOUND); + } + MatMaterialReceive materialReceive = new MatMaterialReceive(); + BeanUtils.copyProperties(req, materialReceive); + validEntityBeforeSave(materialReceive, false); + getFileSize(materialReceive, + req.getLicenseCountFileId(), + req.getReportCountFileId(), + req.getTechDocCountFileId(), + req.getCertCountFileId()); + boolean update = this.updateById(materialReceive); + if (!update) { + throw new ServiceException("物料接收单修改失败", HttpStatus.ERROR); + } + List oldMaterialReceiveItemList = materialReceiveItemService.queryListByReceiveId(id); + if (CollUtil.isNotEmpty(oldMaterialReceiveItemList)) { + boolean result = materialReceiveItemService.removeByIds(oldMaterialReceiveItemList); + if (!result) { + throw new ServiceException("物料接收单明细项删除失败", HttpStatus.ERROR); + } + } + List itemList = req.getItemList(); + if (CollUtil.isNotEmpty(itemList)) { + List materialReceiveItemList = itemList.stream().map(item -> { + MatMaterialReceiveItem materialReceiveItem = new MatMaterialReceiveItem(); + BeanUtils.copyProperties(item, materialReceiveItem); + materialReceiveItem.setReceiveId(materialReceive.getId()); + materialReceiveItem.setProjectId(materialReceive.getProjectId()); + return materialReceiveItem; + }).toList(); + boolean result = materialReceiveItemService.saveOrUpdateBatch(materialReceiveItemList); + if (!result) { + throw new ServiceException("物料接收单明细项新增失败", HttpStatus.ERROR); + } + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(MatMaterialReceive entity, Boolean create) { + // 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + String materialSource = entity.getMaterialSource(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(materialSource)) { + throw new ServiceException("物料来源不能为空", HttpStatus.BAD_REQUEST); + } + } + // 查询项目是否存在 + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 批量删除物料接收单信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteByIds(Collection ids) { + List itemList = materialReceiveItemService.lambdaQuery() + .in(MatMaterialReceiveItem::getReceiveId, ids) + .list(); + if (CollUtil.isNotEmpty(itemList)) { + materialReceiveItemService.removeBatchByIds(itemList); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取物料接收单视图对象 + * + * @param materialReceive 物料接收单对象 + * @return 物料接收单视图对象 + */ + @Override + public MatMaterialReceiveVo getVo(MatMaterialReceive materialReceive) { + MatMaterialReceiveVo vo = new MatMaterialReceiveVo(); + BeanUtils.copyProperties(materialReceive, vo); + List itemList = materialReceiveItemService.queryListByReceiveId(materialReceive.getId()); + if (CollUtil.isNotEmpty(itemList)) { + vo.setItemList(materialReceiveItemService.getVoList(itemList)); + } + String certCountFileId = materialReceive.getCertCountFileId(); + if (StringUtils.isNotBlank(certCountFileId)) { + List ossIdList = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setCertCountFile(ossVoList); + } + String reportCountFileId = materialReceive.getReportCountFileId(); + if (StringUtils.isNotBlank(reportCountFileId)) { + List ossIdList = Arrays.stream(reportCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setReportCountFile(ossVoList); + } + String techDocCountFileId = materialReceive.getTechDocCountFileId(); + if (StringUtils.isNotBlank(techDocCountFileId)) { + List ossIdList = Arrays.stream(techDocCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setTechDocCountFile(ossVoList); + } + String licenseCountFileId = materialReceive.getLicenseCountFileId(); + if (StringUtils.isNotBlank(licenseCountFileId)) { + List ossIdList = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + vo.setLicenseCountFile(ossVoList); + } + return vo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(MatMaterialReceiveQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String materialSource = req.getMaterialSource(); + String formCode = req.getFormCode(); + String projectName = req.getProjectName(); + String materialName = req.getMaterialName(); + String contractName = req.getContractName(); + String orderingUnit = req.getOrderingUnit(); + String supplierUnit = req.getSupplierUnit(); + String storageType = req.getStorageType(); + lqw.like(StringUtils.isNotBlank(projectName), MatMaterialReceive::getProjectName, projectName); + lqw.like(StringUtils.isNotBlank(materialName), MatMaterialReceive::getMaterialName, materialName); + lqw.like(StringUtils.isNotBlank(contractName), MatMaterialReceive::getContractName, contractName); + lqw.like(StringUtils.isNotBlank(orderingUnit), MatMaterialReceive::getOrderingUnit, orderingUnit); + lqw.like(StringUtils.isNotBlank(supplierUnit), MatMaterialReceive::getSupplierUnit, supplierUnit); + lqw.like(StringUtils.isNotBlank(formCode), MatMaterialReceive::getFormCode, formCode); + lqw.like(StringUtils.isNotBlank(storageType), MatMaterialReceive::getStorageType, storageType); + lqw.eq(ObjectUtils.isNotEmpty(projectId), MatMaterialReceive::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(materialSource), MatMaterialReceive::getMaterialSource, materialSource); + return lqw; + } + + /** + * 获取物料接收单分页对象视图 + * + * @param materialReceivePage 物料接收单分页对象 + * @return 物料接收单分页对象视图 + */ + @Override + public Page getVoPage(Page materialReceivePage) { + List materialReceiveList = materialReceivePage.getRecords(); + Page materialReceiveVoPage = new Page<>( + materialReceivePage.getCurrent(), + materialReceivePage.getSize(), + materialReceivePage.getTotal()); + if (CollUtil.isEmpty(materialReceiveList)) { + return materialReceiveVoPage; + } + // 对象列表 => 封装对象列表 + List materialReceiveVoList = materialReceiveList.stream().map(materialReceive -> { + MatMaterialReceiveVo materialReceiveVo = new MatMaterialReceiveVo(); + BeanUtils.copyProperties(materialReceive, materialReceiveVo); + return materialReceiveVo; + }).toList(); + materialReceiveVoPage.setRecords(materialReceiveVoList); + return materialReceiveVoPage; + } + + /** + * 获取文件数量 + * + * @param materialReceive 物料接收单对象 + * @param licenseCountFileId 证书文件id + * @param reportCountFileId 报表文件id + * @param techDocCountFileId 技术文档文件id + * @param certCountFileId 证书文件id + */ + private void getFileSize(MatMaterialReceive materialReceive, String licenseCountFileId, + String reportCountFileId, String techDocCountFileId, String certCountFileId) { + if (StringUtils.isNotBlank(licenseCountFileId)) { + int size = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialReceive.setLicenseCount(size); + } + if (StringUtils.isNotBlank(reportCountFileId)) { + int size = Arrays.stream(reportCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialReceive.setReportCount(size); + } + if (StringUtils.isNotBlank(techDocCountFileId)) { + int size = Arrays.stream(techDocCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialReceive.setTechDocCount(size); + } + if (StringUtils.isNotBlank(certCountFileId)) { + int size = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList().size(); + materialReceive.setLicenseCount(size); + } + } + + /** + * 根据实体获取替换数据 + * + * @param materialReceive 物料接收单对象 + * @param items 物料接收单明细列表 + * @return 替换 Word 数据 + */ + private MatMaterialReceiveWordDto getReplacementDto(MatMaterialReceive materialReceive, List items) { + MatMaterialReceiveWordDto dto = new MatMaterialReceiveWordDto(); + BeanUtils.copyProperties(materialReceive, dto); + // 接收总数量 + int quantity = items.stream() + .map(MatMaterialReceiveItem::getQuantity) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .intValue(); + dto.setTotalQuantity(quantity); + int shortageQuantity = items.stream() + .map(MatMaterialReceiveItem::getShortageQuantity) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .intValue(); + dto.setTotalShortageQuantity(shortageQuantity); + int acceptedQuantity = items.stream() + .map(MatMaterialReceiveItem::getAcceptedQuantity) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .intValue(); + dto.setTotalAcceptedQuantity(acceptedQuantity); + Integer certCount = materialReceive.getCertCount(); + dto.setIsCertCount(certCount > 0 ? "☑" : "□"); + Integer licenseCount = materialReceive.getLicenseCount(); + dto.setIsLicenseCount(licenseCount > 0 ? "☑" : "□"); + Integer reportCount = materialReceive.getReportCount(); + dto.setIsReportCount(reportCount > 0 ? "☑" : "□"); + Integer techDocCount = materialReceive.getTechDocCount(); + dto.setIsTechDocCount(techDocCount > 0 ? "☑" : "□"); + // 明细项信息 + List dtoItems = new ArrayList<>(); + for (int i = 1; i <= items.size(); i++) { + MatMaterialReceiveItem item = items.get(i - 1); + MatMaterialReceiveItemWordDto itemDto = new MatMaterialReceiveItemWordDto(); + BeanUtils.copyProperties(item, itemDto); + itemDto.setNo(i); + itemDto.setQuantity(item.getQuantity().intValue()); + itemDto.setShortageQuantity(item.getShortageQuantity().intValue()); + itemDto.setAcceptedQuantity(item.getAcceptedQuantity().intValue()); + dtoItems.add(itemDto); + } + dto.setItems(dtoItems); + // 设备材料入库/移交 + String storageType = materialReceive.getStorageType(); + dto.setStorageType1("□"); + dto.setStorageType2("□"); + dto.setStorageType3("□"); + if (StringUtils.isNotBlank(storageType)) { + List storageTypeList = Arrays.stream(storageType.split(",")).map(Integer::parseInt).toList(); + for (Integer type : storageTypeList) { + if (type == 1) { + dto.setStorageType1("☑"); + } + if (type == 2) { + dto.setStorageType2("☑"); + } + if (type == 3) { + dto.setStorageType3("☑"); + } + } + } + // 封装数据 + return dto; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialsInventoryServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialsInventoryServiceImpl.java new file mode 100644 index 0000000..70234dd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialsInventoryServiceImpl.java @@ -0,0 +1,325 @@ +package org.dromara.materials.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.materials.domain.MatMaterials; +import org.dromara.materials.domain.MatMaterialsInventory; +import org.dromara.materials.domain.enums.MatMaterialsInventoryOutPutEnum; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryCreateReq; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryQueryReq; +import org.dromara.materials.domain.dto.materialsinventory.MatMaterialsInventoryUpdateReq; +import org.dromara.materials.domain.vo.materialsinventory.MatMaterialsInventoryVo; +import org.dromara.materials.mapper.MatMaterialsInventoryMapper; +import org.dromara.materials.service.IMatMaterialsInventoryService; +import org.dromara.materials.service.IMatMaterialsService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 材料出/入库Service业务层处理 + * + * @author lilemy + * @date 2025-03-06 + */ +@Service +public class MatMaterialsInventoryServiceImpl extends ServiceImpl + implements IMatMaterialsInventoryService { + + @Resource + private IMatMaterialsService materialsService; + + @Resource + private IBusProjectService projectService; + + /** + * 查询材料出/入库 + * + * @param id 主键 + * @return 材料出/入库 + */ + @Override + public MatMaterialsInventoryVo queryById(Long id) { + MatMaterialsInventory materialsInventory = this.getById(id); + if (materialsInventory == null) { + throw new ServiceException("材料出/入库信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(materialsInventory); + } + + /** + * 分页查询材料出/入库列表 + * + * @param req 查询条件 + * @return 材料出/入库分页列表 + */ + @Override + public TableDataInfo queryPageList(MatMaterialsInventoryQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的材料出/入库列表 + * + * @param req 查询条件 + * @return 材料出/入库列表 + */ + @Override + public List queryList(MatMaterialsInventoryQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + List list = this.list(lqw); + return list.stream().map(this::getVo).toList(); + } + + /** + * 新增材料出/入库 + * + * @param req 材料出/入库 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(MatMaterialsInventoryCreateReq req) { + // 将实体类和 DTO 进行转换 + MatMaterialsInventory materialsInventory = new MatMaterialsInventory(); + BeanUtils.copyProperties(req, materialsInventory); + // 数据校验 + validEntityBeforeSave(materialsInventory, true); + // 获取最后一次库存数量 + MatMaterialsInventory lastMaterialsInventory = this.getOne(Wrappers.lambdaQuery() + .eq(MatMaterialsInventory::getMaterialsId, req.getMaterialsId()) + .eq(MatMaterialsInventory::getProjectId, req.getProjectId()) + .orderByDesc(MatMaterialsInventory::getCreateTime) + .last("limit 1")); + if (lastMaterialsInventory != null) { + if (MatMaterialsInventoryOutPutEnum.OUT.getValue().equals(req.getOutPut())) { + long left = lastMaterialsInventory.getResidue() - req.getNumber(); + if (left < 0) { + throw new ServiceException("库存不足", HttpStatus.BAD_REQUEST); + } + materialsInventory.setResidue(left); + } else { + materialsInventory.setResidue(lastMaterialsInventory.getResidue() + req.getNumber()); + } + } else { + if (MatMaterialsInventoryOutPutEnum.OUT.getValue().equals(req.getOutPut())) { + throw new ServiceException("库存不足", HttpStatus.BAD_REQUEST); + } else { + materialsInventory.setResidue(req.getNumber()); + } + } + // 操作数据库 + boolean save = this.save(materialsInventory); + if (!save) { + throw new ServiceException("新增材料出/入库失败,数据库异常", HttpStatus.ERROR); + } + return materialsInventory.getId(); + } + + /** + * 修改材料出/入库 + * + * @param req 材料出/入库 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(MatMaterialsInventoryUpdateReq req) { + // 将实体类和 DTO 进行转换 + MatMaterialsInventory materialsInventory = new MatMaterialsInventory(); + BeanUtils.copyProperties(req, materialsInventory); + // 数据校验 + validEntityBeforeSave(materialsInventory, false); + // 判断是否存在 + MatMaterialsInventory oldBusMaterialsInventory = this.getById(materialsInventory.getId()); + if (oldBusMaterialsInventory == null) { + throw new ServiceException("修改材料出/入库失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(materialsInventory); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(MatMaterialsInventory entity, Boolean create) { + Long materialsId = entity.getMaterialsId(); + Long projectId = entity.getProjectId(); + String outPut = entity.getOutPut(); + Long number = entity.getNumber(); + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (create) { + if (number == null) { + throw new ServiceException("出/入库数量不能为空", HttpStatus.BAD_REQUEST); + } + if (materialsId == null) { + throw new ServiceException("材料信息 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(outPut)) { + throw new ServiceException("出入库状态不能为空", HttpStatus.BAD_REQUEST); + } + } + if (materialsService.getById(materialsId) == null) { + throw new ServiceException("对应材料信息不存在", HttpStatus.BAD_REQUEST); + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除材料出/入库信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + // 获取当前登录用户 + Long userId = LoginHelper.getUserId(); + List materialsInventoryList = this.listByIds(ids); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + // 获取项目id列表 + List projectIdList = materialsInventoryList.stream().map(MatMaterialsInventory::getProjectId).toList(); + // 判断是否有权限操作对应项目下的内容 + projectService.validAuth(projectIdList, userId); + } + // 判断对应数据是否都存在 + if (materialsInventoryList.size() != ids.size()) { + throw new ServiceException("删除材料出/入库失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取材料出/入库视图对象 + * + * @param materialsInventory 材料出/入库对象 + * @return 材料出/入库视图对象 + */ + @Override + public MatMaterialsInventoryVo getVo(MatMaterialsInventory materialsInventory) { + // 对象转封装类 + MatMaterialsInventoryVo materialsInventoryVo = new MatMaterialsInventoryVo(); + if (materialsInventory == null) { + return materialsInventoryVo; + } + BeanUtils.copyProperties(materialsInventory, materialsInventoryVo); + // 关联查询材料信息 + Long materialsId = materialsInventory.getMaterialsId(); + if (materialsId != null) { + materialsInventoryVo.setMaterialsName(materialsService.queryById(materialsId).getMaterialsName()); + } + return materialsInventoryVo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(MatMaterialsInventoryQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + Long materialsId = req.getMaterialsId(); + String materialsName = req.getMaterialsName(); + Long projectId = req.getProjectId(); + String outPut = req.getOutPut(); + Long number = req.getNumber(); + Date outPutTime = req.getOutPutTime(); + Long residue = req.getResidue(); + String operator = req.getOperator(); + String disposition = req.getDisposition(); + String recipient = req.getRecipient(); + String shipper = req.getShipper(); + String remark = req.getRemark(); + // 联表查询 + if (StringUtils.isNotBlank(materialsName)) { + LambdaQueryWrapper materialsQueryWrapper = Wrappers.lambdaQuery(MatMaterials.class) + .select(MatMaterials::getId) + .like(MatMaterials::getMaterialsName, materialsName); + List materialsIdList = materialsService.listObjs(materialsQueryWrapper, obj -> (Long) obj); + lqw.in(MatMaterialsInventory::getMaterialsId, materialsIdList); + } + // 模糊查询 + lqw.like(StringUtils.isNotBlank(operator), MatMaterialsInventory::getOperator, operator); + lqw.like(StringUtils.isNotBlank(remark), MatMaterialsInventory::getRemark, remark); + lqw.like(StringUtils.isNotBlank(disposition), MatMaterialsInventory::getDisposition, disposition); + lqw.like(StringUtils.isNotBlank(recipient), MatMaterialsInventory::getRecipient, recipient); + lqw.like(StringUtils.isNotBlank(shipper), MatMaterialsInventory::getShipper, shipper); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), MatMaterialsInventory::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), MatMaterialsInventory::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(materialsId), MatMaterialsInventory::getMaterialsId, materialsId); + lqw.eq(ObjectUtils.isNotEmpty(number), MatMaterialsInventory::getNumber, number); + lqw.eq(ObjectUtils.isNotEmpty(outPutTime), MatMaterialsInventory::getOutPutTime, outPutTime); + lqw.eq(ObjectUtils.isNotEmpty(residue), MatMaterialsInventory::getResidue, residue); + lqw.eq(ObjectUtils.isNotEmpty(outPut), MatMaterialsInventory::getOutPut, outPut); + // 排序 + lqw.orderByDesc(MatMaterialsInventory::getCreateTime); + return lqw; + } + + /** + * 获取材料出/入库分页对象视图 + * + * @param materialsInventoryPage 材料出/入库分页对象 + * @return 材料出/入库分页对象视图 + */ + @Override + public Page getVoPage(Page materialsInventoryPage) { + List materialsInventoryList = materialsInventoryPage.getRecords(); + Page materialsInventoryVoPage = new Page<>( + materialsInventoryPage.getCurrent(), + materialsInventoryPage.getSize(), + materialsInventoryPage.getTotal()); + if (CollUtil.isEmpty(materialsInventoryList)) { + return materialsInventoryVoPage; + } + // 获取材料id列表 + Set materialsIdList = materialsInventoryList.stream().map(MatMaterialsInventory::getMaterialsId).collect(Collectors.toSet()); + Map> materialsIdBusMaterialsMap = materialsService.listByIds(materialsIdList).stream() + .collect(Collectors.groupingBy(MatMaterials::getId)); + // 对象列表 => 封装对象列表 + List materialsInventoryVoList = materialsInventoryList.stream().map(materialsInventory -> { + MatMaterialsInventoryVo materialsInventoryVo = new MatMaterialsInventoryVo(); + BeanUtils.copyProperties(materialsInventory, materialsInventoryVo); + // 关联查询材料信息 + Long materialsId = materialsInventory.getMaterialsId(); + String materialsName = null; + if (materialsIdBusMaterialsMap.containsKey(materialsId)) { + materialsName = materialsIdBusMaterialsMap.get(materialsId).get(0).getMaterialsName(); + } + materialsInventoryVo.setMaterialsName(materialsName); + return materialsInventoryVo; + }).toList(); + materialsInventoryVoPage.setRecords(materialsInventoryVoList); + return materialsInventoryVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialsServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialsServiceImpl.java new file mode 100644 index 0000000..5becedd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/materials/service/impl/MatMaterialsServiceImpl.java @@ -0,0 +1,348 @@ +package org.dromara.materials.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.materials.domain.MatMaterials; +import org.dromara.materials.domain.MatMaterialsInventory; +import org.dromara.materials.domain.enums.MatMaterialsInventoryOutPutEnum; +import org.dromara.materials.domain.dto.materials.MatMaterialsCreateReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsGisReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsQueryReq; +import org.dromara.materials.domain.dto.materials.MatMaterialsUpdateReq; +import org.dromara.materials.domain.vo.materials.MatMaterialsGisVo; +import org.dromara.materials.domain.vo.materials.MatMaterialsVo; +import org.dromara.materials.mapper.MatMaterialsMapper; +import org.dromara.materials.service.IMatCompanyService; +import org.dromara.materials.service.IMatMaterialsInventoryService; +import org.dromara.materials.service.IMatMaterialsService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 材料名称Service业务层处理 + * + * @author lilemy + * @date 2025-03-06 + */ +@Service +public class MatMaterialsServiceImpl extends ServiceImpl + implements IMatMaterialsService { + + @Resource + private IMatCompanyService companyService; + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private IMatMaterialsInventoryService materialsInventoryService; + + /** + * 查询材料名称 + * + * @param id 主键 + * @return 材料名称 + */ + @Override + public MatMaterialsVo queryById(Long id) { + MatMaterials materials = this.getById(id); + if (materials == null) { + throw new ServiceException("材料名称信息不存在", HttpStatus.NOT_FOUND); + } + return this.getBusMaterialsVo(materials); + } + + /** + * 分页查询材料名称列表 + * + * @param req 查询条件 + * @param pageQuery 分页条件 + * @return 材料名称分页列表 + */ + @Override + public TableDataInfo queryPageList(MatMaterialsQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getMaterialsVoPage(result)); + } + + /** + * 查询符合条件的材料名称列表 + * + * @param req 查询条件 + * @return 材料名称列表 + */ + @Override + public List queryList(MatMaterialsQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return baseMapper.selectVoList(lqw); + } + + /** + * 查询材料大屏信息列表 + * + * @param req 查询条件 + * @return 材料大屏信息列表 + */ + @Override + public List queryGisList(MatMaterialsGisReq req) { + Long projectId = req.getProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + List materialsList = this.lambdaQuery() + .eq(MatMaterials::getProjectId, projectId).list(); + if (CollUtil.isEmpty(materialsList)) { + return List.of(); + } + List materialsInventoryList = materialsInventoryService.lambdaQuery() + .eq(MatMaterialsInventory::getProjectId, projectId).list(); + Map> inventoryMap = materialsInventoryList.stream() + .collect(Collectors.groupingBy(MatMaterialsInventory::getMaterialsId)); + final int[] value = {1}; + return materialsList.stream().map(materials -> { + MatMaterialsGisVo materialsGisVo = new MatMaterialsGisVo(); + BeanUtils.copyProperties(materials, materialsGisVo); + Long id = materials.getId(); + long putCount = 0L; + long outCount = 0L; + if (CollUtil.isNotEmpty(inventoryMap) && inventoryMap.containsKey(id)) { + List inventoryList = inventoryMap.get(id); + for (MatMaterialsInventory record : inventoryList) { + if (MatMaterialsInventoryOutPutEnum.PUT.getValue().equals(record.getOutPut())) { + putCount += record.getNumber() != null ? record.getNumber() : 0; + } else if (MatMaterialsInventoryOutPutEnum.OUT.getValue().equals(record.getOutPut())) { + outCount += record.getNumber() != null ? record.getNumber() : 0; + } + } + } + materialsGisVo.setPutCount(putCount); + materialsGisVo.setOutCount(outCount); + materialsGisVo.setValue(value[0]); + value[0] += 1; + return materialsGisVo; + }).toList(); + } + + /** + * 新增材料名称 + * + * @param req 材料名称 + * @return 新增材料信息id + */ + @Override + public Long insertByBo(MatMaterialsCreateReq req) { + // 将实体类和 DTO 进行转换 + MatMaterials materials = new MatMaterials(); + BeanUtils.copyProperties(req, materials); + // 数据转换 + Map fileOssIdList = req.getFileOssIdMap(); + String fileOssIdStr = JsonUtils.toJsonString(fileOssIdList); + materials.setFileOssId(fileOssIdStr); + // 数据校验 + validEntityBeforeSave(materials); + // 写入数据库 + boolean save = this.save(materials); + if (!save) { + throw new ServiceException("新增材料信息失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return materials.getId(); + } + + /** + * 修改材料名称 + * + * @param req 材料名称 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(MatMaterialsUpdateReq req) { + // 将实体类和 DTO 进行转换 + MatMaterials materials = new MatMaterials(); + BeanUtils.copyProperties(req, materials); + // 数据转换 + Map fileOssIdList = req.getFileOssIdMap(); + String fileOssIdStr = JSONUtil.toJsonStr(fileOssIdList); + materials.setFileOssId(fileOssIdStr); + // 数据校验 + validEntityBeforeSave(materials); + // 判断是否存在 + MatMaterials oldMaterials = this.getById(materials.getId()); + if (oldMaterials == null) { + throw new ServiceException("修改材料信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(materials); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(MatMaterials entity) { + // 做一些数据校验,如唯一约束 + String materialsName = entity.getMaterialsName(); + Long companyId = entity.getCompanyId(); + Long projectId = entity.getProjectId(); + if (StringUtils.isEmpty(materialsName)) { + throw new ServiceException("请填写材料名称", HttpStatus.BAD_REQUEST); + } + if (companyId == null) { + throw new ServiceException("请填写公司ID", HttpStatus.BAD_REQUEST); + } + if (companyService.getById(companyId) == null) { + throw new ServiceException("对应公司不存在", HttpStatus.BAD_REQUEST); + } + if (projectId == null) { + throw new ServiceException("请填写项目ID", HttpStatus.BAD_REQUEST); + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除材料名称信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List materialsList = this.listByIds(ids); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + // 获取项目id列表 + List projectIdList = materialsList.stream().map(MatMaterials::getProjectId).toList(); + // 判断是否有权限操作对应项目下的内容 + projectService.validAuth(projectIdList, userId); + // 判断公司中是否还存在材料信息 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("materials", ids); + if (materialsInventoryService.count(queryWrapper) > 0) { + throw new ServiceException("删除材料失败,材料存在库存信息", HttpStatus.BAD_REQUEST); + } + } + if (materialsList.size() != ids.size()) { + throw new ServiceException("删除材料信息失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 获取材料视图 + * + * @param materials 材料 + * @return 材料视图 + */ + @Override + public MatMaterialsVo getBusMaterialsVo(MatMaterials materials) { + // 对象转封装类 + MatMaterialsVo materialsVo = new MatMaterialsVo(); + if (materials == null) { + return materialsVo; + } + BeanUtils.copyProperties(materials, materialsVo); + // 关联查询项目信息 + Long companyId = materials.getCompanyId(); + if (companyId != null) { + materialsVo.setCompanyVo(companyService.queryById(companyId)); + } + // 关联对象存储文件信息 + String fileOssId = materials.getFileOssId(); + if (StringUtils.isEmpty(fileOssId)) { + return materialsVo; + } + Map fileOssMap = new HashMap<>(); + JSONObject parseObj = JSONUtil.parseObj(fileOssId); + parseObj.forEach((key, value) -> fileOssMap.put(key, (Long) value)); + materialsVo.setFileOssMap(fileOssMap); + return materialsVo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(MatMaterialsQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + String materialsName = req.getMaterialsName(); + Long companyId = req.getCompanyId(); + Long projectId = req.getProjectId(); + String typeSpecificationName = req.getTypeSpecificationName(); + String usePart = req.getUsePart(); + String weightId = req.getWeightId(); + String remark = req.getRemark(); + String quantityCount = req.getQuantityCount(); + String status = req.getStatus(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(materialsName), MatMaterials::getMaterialsName, materialsName); + lqw.like(StringUtils.isNotBlank(typeSpecificationName), MatMaterials::getTypeSpecificationName, typeSpecificationName); + lqw.like(StringUtils.isNotBlank(usePart), MatMaterials::getUsePart, usePart); + lqw.like(StringUtils.isNotBlank(remark), MatMaterials::getRemark, remark); + lqw.like(StringUtils.isNotBlank(weightId), MatMaterials::getWeightId, weightId); + lqw.like(StringUtils.isNotBlank(quantityCount), MatMaterials::getQuantityCount, quantityCount); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(status), MatMaterials::getStatus, status); + lqw.eq(ObjectUtils.isNotEmpty(id), MatMaterials::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), MatMaterials::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(companyId), MatMaterials::getCompanyId, companyId); + return lqw; + } + + /** + * 获取材料分页对象视图 + * + * @param materialsPage 材料分页对象 + * @return 材料分页对象视图 + */ + @Override + public Page getMaterialsVoPage(Page materialsPage) { + // 获取材料数据 + List materialsList = materialsPage.getRecords(); + // 添加分页信息 + Page materialsVoPage = new Page<>(materialsPage.getCurrent(), materialsPage.getSize(), materialsPage.getTotal()); + if (CollUtil.isEmpty(materialsList)) { + return materialsVoPage; + } + // 对象列表 => 封装对象列表 + List materialsVoList = materialsList.stream().map(this::getBusMaterialsVo).toList(); + materialsVoPage.setRecords(materialsVoList); + return materialsVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/constant/Ys7DeviceImgConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/constant/Ys7DeviceImgConstant.java new file mode 100644 index 0000000..3c1973b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/constant/Ys7DeviceImgConstant.java @@ -0,0 +1,47 @@ +package org.dromara.other.constant; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import org.dromara.common.core.utils.DateUtils; + +/** + * @author lilemy + * @date 2025/6/18 19:11 + */ +public interface Ys7DeviceImgConstant { + + /** + * 设备图片oss前缀 + */ + String DEVICE_IMG_OSS_URL_PREFIX = "ys7/device/img/"; + + /** + * 获取设备图片oss路径 + * + * @param originalFilename 文件名原始名 + * @param deviceSerial 设备序列号 + * @return oss路径 + */ + static String getDeviceImgOssPath(String originalFilename, String deviceSerial) { + String suffix = FileUtil.getSuffix(originalFilename); + String uuid = IdUtil.fastSimpleUUID(); + String date = DateUtils.getDate(); + String fileName = String.format("%s_%s.%s", date, uuid, suffix); + return DEVICE_IMG_OSS_URL_PREFIX + deviceSerial + "/" + fileName; + } + + /** + * 获取设备图片oss路径 + * + * @param originalFilename 文件名原始名 + * @param deviceSerial 设备序列号 + * @return oss路径 + */ + static String getTargetImgOssPath(String originalFilename, String deviceSerial) { + String suffix = FileUtil.getSuffix(originalFilename); + String uuid = IdUtil.fastSimpleUUID(); + String date = DateUtils.getDate(); + String fileName = String.format("%s_%s.%s", date, uuid, suffix); + return DEVICE_IMG_OSS_URL_PREFIX + deviceSerial + "/target/" + fileName; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthDevicePresetController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthDevicePresetController.java new file mode 100644 index 0000000..6998018 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthDevicePresetController.java @@ -0,0 +1,120 @@ +package org.dromara.other.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetCreateReq; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetQueryReq; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetUpdateReq; +import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo; +import org.dromara.other.service.IOthDevicePresetService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 摄像头预置位 + * + * @author lilemy + * @date 2025-06-13 + */ +@Validated +@RestController +@RequestMapping("/other/devicePreset") +public class OthDevicePresetController extends BaseController { + + @Resource + private IOthDevicePresetService othDevicePresetService; + + /** + * 查询摄像头预置位列表 + */ + @SaCheckPermission("other:devicePreset:list") + @GetMapping("/list") + public TableDataInfo list(OthDevicePresetQueryReq req, PageQuery pageQuery) { + return othDevicePresetService.queryPageList(req, pageQuery); + } + + /** + * 导出摄像头预置位列表 + */ + @SaCheckPermission("other:devicePreset:export") + @Log(title = "摄像头预置位", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(OthDevicePresetQueryReq req, HttpServletResponse response) { + List list = othDevicePresetService.queryList(req); + ExcelUtil.exportExcel(list, "摄像头预置位", OthDevicePresetVo.class, response); + } + + /** + * 获取摄像头预置位详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("other:devicePreset:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(othDevicePresetService.queryById(id)); + } + + /** + * 新增摄像头预置位 + */ + @SaCheckPermission("other:devicePreset:add") + @Log(title = "摄像头预置位", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody OthDevicePresetCreateReq req) { + return R.ok(othDevicePresetService.insertByBo(req)); + } + + /** + * 修改摄像头预置位 + */ + @SaCheckPermission("other:devicePreset:edit") + @Log(title = "摄像头预置位", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody OthDevicePresetUpdateReq req) { + return toAjax(othDevicePresetService.updateByBo(req)); + } + + /** + * 调用摄像头预置位 + * + * @param id 主键 + */ + @SaCheckPermission("other:devicePreset:edit") + @Log(title = "摄像头预置位", businessType = BusinessType.UPDATE) + @PutMapping("/move/{id}") + public R move(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(othDevicePresetService.moveById(id)); + } + + /** + * 删除摄像头预置位 + * + * @param id 主键串 + */ + @SaCheckPermission("other:devicePreset:remove") + @Log(title = "摄像头预置位", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(othDevicePresetService.deleteById(id)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthYs7DeviceController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthYs7DeviceController.java new file mode 100644 index 0000000..9daa7f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthYs7DeviceController.java @@ -0,0 +1,160 @@ +package org.dromara.other.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.json.JSONUtil; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.manager.ys7manager.Ys7Manager; +import org.dromara.other.domain.dto.ys7device.*; +import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo; +import org.dromara.other.service.IOthYs7DeviceService; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 萤石摄像头 + * + * @author lilemy + * @date 2025-06-13 + */ +@Slf4j +@Validated +@RestController +@RequestMapping("/other/ys7Device") +public class OthYs7DeviceController extends BaseController { + + @Resource + private IOthYs7DeviceService othYs7DeviceService; + + @Resource + private Ys7Manager ys7Manager; + + /** + * 查询萤石摄像头列表 + */ + @SaCheckPermission("other:ys7Device:list") + @GetMapping("/list") + public TableDataInfo list(OthYs7DeviceQueryReq req, PageQuery pageQuery) { + return othYs7DeviceService.queryPageList(req, pageQuery); + } + + /** + * 根据项目查询萤石摄像头列表 + */ + @SaCheckPermission("other:ys7Device:list") + @GetMapping("/list/project") + public TableDataInfo listByProject(Long projectId, PageQuery pageQuery) { + return othYs7DeviceService.queryPageListByProject(projectId, pageQuery); + } + + /** + * 导出萤石摄像头列表 + */ + @SaCheckPermission("other:ys7Device:export") + @Log(title = "萤石摄像头", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(OthYs7DeviceQueryReq req, HttpServletResponse response) { + List list = othYs7DeviceService.queryList(req); + ExcelUtil.exportExcel(list, "萤石摄像头", OthYs7DeviceVo.class, response); + } + + /** + * 获取萤石摄像头详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("other:ys7Device:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(othYs7DeviceService.queryById(id)); + } + + /** + * 修改萤石摄像头 + */ + @SaCheckPermission("other:ys7Device:edit") + @Log(title = "萤石摄像头", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody OthYs7DeviceUpdateReq req) { + return toAjax(othYs7DeviceService.updateByBo(req)); + } + + /** + * 修改萤石摄像头所属项目 + */ + @SaCheckPermission("other:ys7Device:edit") + @Log(title = "萤石摄像头", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/with/project") + public R updateWithProject(@Validated @RequestBody OthYs7DeviceWithProjectReq req) { + return toAjax(othYs7DeviceService.updateWithProject(req)); + } + + /** + * 修改萤石摄像头视频加密 + */ + @SaCheckPermission("other:ys7Device:edit") + @Log(title = "萤石摄像头", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/video/encrypted") + public R updateVideoEncrypted(@Validated @RequestBody OthYs7DeviceUpdateEncryptedReq req) { + return toAjax(othYs7DeviceService.updateVideoEncrypted(req)); + } + + /** + * 删除萤石摄像头 + * + * @param ids 主键串 + */ + @SaCheckPermission("other:ys7Device:remove") + @Log(title = "萤石摄像头", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(othYs7DeviceService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 获取 token + */ + @SaCheckPermission("other:ys7Device:query") + @GetMapping("/get/token") + public R getToken() { + return R.ok("操作成功", ys7Manager.getToken()); + } + + @RequestMapping(value = "/webhook") + public ResponseEntity webhook(@RequestHeader HttpHeaders header, @RequestBody String body) { + WebhookMessage receiveMessage; + log.info("消息获取时间:{}, 收到的消息:{}", System.currentTimeMillis(), body); + receiveMessage = JSONUtil.toBean(body, WebhookMessage.class); + othYs7DeviceService.webhook(receiveMessage); + // 必须进行返回 + Map result = new HashMap<>(1); + assert receiveMessage != null; + String messageId = receiveMessage.getHeader().getMessageId(); + result.put("messageId", messageId); + return ResponseEntity.ok(JSONUtil.toJsonStr(result)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthYs7DeviceImgController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthYs7DeviceImgController.java new file mode 100644 index 0000000..7b1a135 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/controller/OthYs7DeviceImgController.java @@ -0,0 +1,82 @@ +package org.dromara.other.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq; +import org.dromara.other.domain.vo.ys7deviceimg.OthYs7DeviceImgVo; +import org.dromara.other.service.IOthYs7DeviceImgService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 萤石摄像头图片 + * + * @author lilemy + * @date 2025-06-18 + */ +@Validated +@RestController +@RequestMapping("/other/ys7DeviceImg") +public class OthYs7DeviceImgController extends BaseController { + + @Resource + private IOthYs7DeviceImgService othYs7DeviceImgService; + + /** + * 查询萤石摄像头图片列表 + */ + @SaCheckPermission("other:ys7DeviceImg:list") + @GetMapping("/list") + public TableDataInfo list(OthYs7DeviceImgQueryReq req, PageQuery pageQuery) { + return othYs7DeviceImgService.queryPageList(req, pageQuery); + } + + /** + * 导出萤石摄像头图片列表 + */ + @SaCheckPermission("other:ys7DeviceImg:export") + @Log(title = "萤石摄像头图片", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(OthYs7DeviceImgQueryReq req, HttpServletResponse response) { + List list = othYs7DeviceImgService.queryList(req); + ExcelUtil.exportExcel(list, "萤石摄像头图片", OthYs7DeviceImgVo.class, response); + } + + /** + * 获取萤石摄像头图片详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("other:ys7DeviceImg:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(othYs7DeviceImgService.queryById(id)); + } + + /** + * 删除萤石摄像头图片 + * + * @param ids 主键串 + */ + @SaCheckPermission("other:ys7DeviceImg:remove") + @Log(title = "萤石摄像头图片", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(othYs7DeviceImgService.deleteWithValidByIds(List.of(ids))); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthDevicePreset.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthDevicePreset.java new file mode 100644 index 0000000..285e54c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthDevicePreset.java @@ -0,0 +1,60 @@ +package org.dromara.other.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 摄像头预置位对象 oth_device_preset + * + * @author lilemy + * @date 2025-06-13 + */ +@Data +@TableName("oth_device_preset") +public class OthDevicePreset implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 通道号 + */ + private Integer channelNo; + + /** + * 预置点序号 + */ + private Integer presetIndex; + + /** + * 预置点 + */ + private String presetName; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthYs7Device.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthYs7Device.java new file mode 100644 index 0000000..c04b9be --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthYs7Device.java @@ -0,0 +1,105 @@ +package org.dromara.other.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 萤石摄像头对象 oth_ys7_device + * + * @author lilemy + * @date 2025-06-13 + */ +@Data +@TableName("oth_ys7_device") +public class OthYs7Device implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 设备型号 + */ + private String deviceType; + + /** + * 设备在线状态(0离线 1在线) + */ + private Integer status; + + /** + * 布撤防状态 + */ + private Long defence; + + /** + * 固件版本号 + */ + private String deviceVersion; + + /** + * 摄像头坐标信息 + */ + private String position; + + /** + * 设备添加时间 + */ + private Date deviceCreateTime; + + /** + * 设备最后更新时间 + */ + private Date deviceUpdateTime; + + /** + * 设备风险安全等级(0安全 大于0,值越大,风险越高) + */ + private Integer riskLevel; + + /** + * 视频加密(0关闭 1开启) + */ + private Integer videoEncrypted; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthYs7DeviceImg.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthYs7DeviceImg.java new file mode 100644 index 0000000..b7890e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/OthYs7DeviceImg.java @@ -0,0 +1,85 @@ +package org.dromara.other.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 萤石摄像头图片对象 oth_ys7_device_img + * + * @author lilemy + * @date 2025-06-18 + */ +@Data +@TableName("oth_ys7_device_img") +public class OthYs7DeviceImg implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 图片地址 + */ + private String url; + + /** + * 识别算法模型 + */ + private String recType; + + /** + * 是否监测到目标(1是 0否) + */ + private Integer isRecognize; + + /** + * 原始图片尺寸 + */ + private String imgSize; + + /** + * 目标信息 + */ + private String targets; + + /** + * 识别结果图片地址 + */ + private String recognizeUrl; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetCreateReq.java new file mode 100644 index 0000000..7a25ba8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetCreateReq.java @@ -0,0 +1,35 @@ +package org.dromara.other.domain.dto.devicepreset; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/13 17:16 + */ +@Data +public class OthDevicePresetCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6326735809456235573L; + + /** + * 设备序列号 + */ + @NotNull(message = "设备序列号不能为空") + private String deviceSerial; + + /** + * 通道号 + */ + private Integer channelNo; + + /** + * 预置点 + */ + private String presetName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetQueryReq.java new file mode 100644 index 0000000..3a71beb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetQueryReq.java @@ -0,0 +1,40 @@ +package org.dromara.other.domain.dto.devicepreset; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/13 17:17 + */ +@Data +public class OthDevicePresetQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 440026959610596318L; + + /** + * 设备序列号 + */ + @NotNull(message = "设备序列号不能为空") + private String deviceSerial; + + /** + * 通道号 + */ + private Integer channelNo; + + /** + * 预置点序号 + */ + private Integer presetIndex; + + /** + * 预置点 + */ + private String presetName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetUpdateReq.java new file mode 100644 index 0000000..cb00f56 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/devicepreset/OthDevicePresetUpdateReq.java @@ -0,0 +1,31 @@ +package org.dromara.other.domain.dto.devicepreset; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/13 17:17 + */ +@Data +public class OthDevicePresetUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5204788392612423553L; + + /** + * 主键id + */ + @NotNull(message = "主键id不能为空") + private Long id; + + /** + * 预置点 + */ + @NotNull(message = "预置点名称不能为空") + private String presetName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceQueryReq.java new file mode 100644 index 0000000..15c417c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceQueryReq.java @@ -0,0 +1,48 @@ +package org.dromara.other.domain.dto.ys7device; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/13 10:19 + */ +@Data +public class OthYs7DeviceQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4341677730149529815L; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 项目id + */ + private Long projectId; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 设备型号 + */ + private String deviceType; + + /** + * 固件版本号 + */ + private String deviceVersion; + + /** + * 设备在线状态(0离线 1在线) + */ + private Long status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceUpdateEncryptedReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceUpdateEncryptedReq.java new file mode 100644 index 0000000..ad003e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceUpdateEncryptedReq.java @@ -0,0 +1,28 @@ +package org.dromara.other.domain.dto.ys7device; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/13 16:20 + */ +@Data +public class OthYs7DeviceUpdateEncryptedReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5570966854443595312L; + + /** + * 主键 + */ + private Long id; + + /** + * 视频加密(0关闭 1开启) + */ + private Integer videoEncrypted; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceUpdateReq.java new file mode 100644 index 0000000..740298e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceUpdateReq.java @@ -0,0 +1,43 @@ +package org.dromara.other.domain.dto.ys7device; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/13 10:19 + */ +@Data +public class OthYs7DeviceUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3434796275594146484L; + + /** + * 主键id + */ + private Long id; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 设备型号 + */ + private String deviceType; + + /** + * 固件版本号 + */ + private String deviceVersion; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceWithProjectReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceWithProjectReq.java new file mode 100644 index 0000000..615c914 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/OthYs7DeviceWithProjectReq.java @@ -0,0 +1,32 @@ +package org.dromara.other.domain.dto.ys7device; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/13 16:04 + */ +@Data +public class OthYs7DeviceWithProjectReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5874710543055812819L; + + /** + * 主键 + */ + @NotNull(message = "主键不能为空") + private List id; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/WebhookMessage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/WebhookMessage.java new file mode 100644 index 0000000..2dd0b4e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7device/WebhookMessage.java @@ -0,0 +1,63 @@ +package org.dromara.other.domain.dto.ys7device; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/17 11:30 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WebhookMessage implements Serializable { + + @Serial + private static final long serialVersionUID = -3462174422247941389L; + + /** + * 消息头 + */ + private WebhookMessageHeader header; + + /** + * 消息体 + */ + private Object body; + + @Data + @NoArgsConstructor + public static class WebhookMessageHeader { + + /** + * 消息id + */ + private String messageId; + + /** + * 设备序列号 + */ + private String deviceId; + + /** + * 消息类型,需向消息管道服务申请 + */ + private String type; + + /** + * 通道号 + */ + private Integer channelNo; + + /** + * 消息推送时间 + */ + private Long messageTime; + + } +} + diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7deviceimg/OthYs7DeviceImgCreateByCapture.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7deviceimg/OthYs7DeviceImgCreateByCapture.java new file mode 100644 index 0000000..8d80615 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7deviceimg/OthYs7DeviceImgCreateByCapture.java @@ -0,0 +1,44 @@ +package org.dromara.other.domain.dto.ys7deviceimg; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/18 18:34 + */ +@Data +public class OthYs7DeviceImgCreateByCapture implements Serializable { + + @Serial + private static final long serialVersionUID = 9152300524686055187L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 图片地址 + */ + private String url; + + /** + * 图片创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7deviceimg/OthYs7DeviceImgQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7deviceimg/OthYs7DeviceImgQueryReq.java new file mode 100644 index 0000000..32cbae7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/dto/ys7deviceimg/OthYs7DeviceImgQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.other.domain.dto.ys7deviceimg; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/18 15:06 + */ +@Data +public class OthYs7DeviceImgQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5264959525029608917L; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 创建时间 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/enums/OthDeviceStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/enums/OthDeviceStatusEnum.java new file mode 100644 index 0000000..6389a3f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/enums/OthDeviceStatusEnum.java @@ -0,0 +1,34 @@ +package org.dromara.other.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/6/17 10:54 + */ +@Getter +public enum OthDeviceStatusEnum { + + ONLINE("在线", 1), + OFFLINE("离线", 0); + + private final String text; + + private final int value; + + OthDeviceStatusEnum(String text, int value) { + this.text = text; + this.value = value; + } + + // 根据 value 获取对应的 text + public static String getTextByValue(int value) { + for (OthDeviceStatusEnum type : values()) { + if (type.getValue() == value) { + return type.getText(); + } + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/enums/OthVideoEncryptedEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/enums/OthVideoEncryptedEnum.java new file mode 100644 index 0000000..c2f9294 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/enums/OthVideoEncryptedEnum.java @@ -0,0 +1,34 @@ +package org.dromara.other.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/6/13 16:25 + */ +@Getter +public enum OthVideoEncryptedEnum { + + OFF("关闭", 0), + OPEN("开启", 1); + + private final String text; + + private final int value; + + OthVideoEncryptedEnum(String text, int value) { + this.text = text; + this.value = value; + } + + // 根据 value 获取对应的 text + public static String getTextByValue(int value) { + for (OthVideoEncryptedEnum type : values()) { + if (type.getValue() == value) { + return type.getText(); + } + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/devicepreset/OthDevicePresetVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/devicepreset/OthDevicePresetVo.java new file mode 100644 index 0000000..77985fd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/devicepreset/OthDevicePresetVo.java @@ -0,0 +1,57 @@ +package org.dromara.other.domain.vo.devicepreset; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.other.domain.OthDevicePreset; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 摄像头预置位视图对象 oth_device_preset + * + * @author lilemy + * @date 2025-06-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = OthDevicePreset.class) +public class OthDevicePresetVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 设备序列号 + */ + @ExcelProperty(value = "设备序列号") + private String deviceSerial; + + /** + * 通道号 + */ + @ExcelProperty(value = "通道号") + private Integer channelNo; + + /** + * 预置点序号 + */ + @ExcelProperty(value = "预置点序号") + private Integer presetIndex; + + /** + * 预置点 + */ + @ExcelProperty(value = "预置点") + private String presetName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/ys7device/OthYs7DeviceVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/ys7device/OthYs7DeviceVo.java new file mode 100644 index 0000000..f9fd246 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/ys7device/OthYs7DeviceVo.java @@ -0,0 +1,93 @@ +package org.dromara.other.domain.vo.ys7device; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.other.domain.OthYs7Device; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 萤石摄像头视图对象 oth_ys7_device + * + * @author lilemy + * @date 2025-06-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = OthYs7Device.class) +public class OthYs7DeviceVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 设备序列号 + */ + @ExcelProperty(value = "设备序列号") + private String deviceSerial; + + /** + * 设备名称 + */ + @ExcelProperty(value = "设备名称") + private String deviceName; + + /** + * 设备型号 + */ + @ExcelProperty(value = "设备型号") + private String deviceType; + + /** + * 设备在线状态(0离线 1在线) + */ + @ExcelProperty(value = "设备在线状态(0离线 1在线)") + private Integer status; + + /** + * 固件版本号 + */ + @ExcelProperty(value = "固件版本号") + private String deviceVersion; + + /** + * 设备添加时间 + */ + @ExcelProperty(value = "设备添加时间") + private Date deviceCreateTime; + + /** + * 视频加密(0关闭 1开启) + */ + @ExcelProperty(value = "视频加密(0关闭 1开启)") + private Integer videoEncrypted; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/ys7deviceimg/OthYs7DeviceImgVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/ys7deviceimg/OthYs7DeviceImgVo.java new file mode 100644 index 0000000..106ab44 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/domain/vo/ys7deviceimg/OthYs7DeviceImgVo.java @@ -0,0 +1,75 @@ +package org.dromara.other.domain.vo.ys7deviceimg; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.other.domain.OthYs7DeviceImg; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 萤石摄像头图片视图对象 oth_ys7_device_img + * + * @author lilemy + * @date 2025-06-18 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = OthYs7DeviceImg.class) +public class OthYs7DeviceImgVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 设备序列号 + */ + @ExcelProperty(value = "设备序列号") + private String deviceSerial; + + /** + * 设备名称 + */ + @ExcelProperty(value = "设备名称") + private String deviceName; + + /** + * 图片地址 + */ + @ExcelProperty(value = "图片地址") + private String url; + + /** + * 识别算法模型 + */ + private List recTypeList; + + /** + * 是否监测到目标(1是 0否) + */ + private Integer isRecognize; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthDevicePresetMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthDevicePresetMapper.java new file mode 100644 index 0000000..c2b0b72 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthDevicePresetMapper.java @@ -0,0 +1,15 @@ +package org.dromara.other.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.other.domain.OthDevicePreset; +import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo; + +/** + * 摄像头预置位Mapper接口 + * + * @author lilemy + * @date 2025-06-13 + */ +public interface OthDevicePresetMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthYs7DeviceImgMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthYs7DeviceImgMapper.java new file mode 100644 index 0000000..aa779c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthYs7DeviceImgMapper.java @@ -0,0 +1,15 @@ +package org.dromara.other.mapper; + +import org.dromara.other.domain.OthYs7DeviceImg; +import org.dromara.other.domain.vo.ys7deviceimg.OthYs7DeviceImgVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 萤石摄像头图片Mapper接口 + * + * @author lilemy + * @date 2025-06-18 + */ +public interface OthYs7DeviceImgMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthYs7DeviceMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthYs7DeviceMapper.java new file mode 100644 index 0000000..9c4a15f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/mapper/OthYs7DeviceMapper.java @@ -0,0 +1,15 @@ +package org.dromara.other.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.other.domain.OthYs7Device; +import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo; + +/** + * 萤石摄像头Mapper接口 + * + * @author lilemy + * @date 2025-06-13 + */ +public interface OthYs7DeviceMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthDevicePresetService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthDevicePresetService.java new file mode 100644 index 0000000..9033746 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthDevicePresetService.java @@ -0,0 +1,104 @@ +package org.dromara.other.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.other.domain.OthDevicePreset; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetCreateReq; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetQueryReq; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetUpdateReq; +import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo; + +import java.util.List; + +/** + * 摄像头预置位Service接口 + * + * @author lilemy + * @date 2025-06-13 + */ +public interface IOthDevicePresetService extends IService { + + /** + * 查询摄像头预置位 + * + * @param id 主键 + * @return 摄像头预置位 + */ + OthDevicePresetVo queryById(Long id); + + /** + * 分页查询摄像头预置位列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 摄像头预置位分页列表 + */ + TableDataInfo queryPageList(OthDevicePresetQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的摄像头预置位列表 + * + * @param req 查询条件 + * @return 摄像头预置位列表 + */ + List queryList(OthDevicePresetQueryReq req); + + /** + * 新增摄像头预置位 + * + * @param req 摄像头预置位 + * @return 新增摄像头预置位主键id + */ + Long insertByBo(OthDevicePresetCreateReq req); + + /** + * 修改摄像头预置位 + * + * @param req 摄像头预置位 + * @return 是否修改成功 + */ + Boolean updateByBo(OthDevicePresetUpdateReq req); + + /** + * 调用摄像头预置位 + * + * @param id 摄像头预置位id + * @return 是否调用成功 + */ + Boolean moveById(Long id); + + /** + * 校验并批量删除摄像头预置位信息 + * + * @param id 待删除的主键 + * @return 是否删除成功 + */ + Boolean deleteById(Long id); + + /** + * 获取摄像头预置位视图 + * + * @param devicePreset 摄像头预置位 + * @return 摄像头预置位视图 + */ + OthDevicePresetVo getVo(OthDevicePreset devicePreset); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(OthDevicePresetQueryReq req); + + /** + * 获取摄像头预置位分页对象视图 + * + * @param devicePresetPage 摄像头预置位分页对象 + * @return 摄像头预置位分页对象视图 + */ + Page getVoPage(Page devicePresetPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthYs7DeviceImgService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthYs7DeviceImgService.java new file mode 100644 index 0000000..2b0e401 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthYs7DeviceImgService.java @@ -0,0 +1,96 @@ +package org.dromara.other.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.other.domain.OthYs7DeviceImg; +import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture; +import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq; +import org.dromara.other.domain.vo.ys7deviceimg.OthYs7DeviceImgVo; + +import java.util.Collection; +import java.util.Date; +import java.util.List; + +/** + * 萤石摄像头图片Service接口 + * + * @author lilemy + * @date 2025-06-18 + */ +public interface IOthYs7DeviceImgService extends IService { + + /** + * 查询萤石摄像头图片 + * + * @param id 主键 + * @return 萤石摄像头图片 + */ + OthYs7DeviceImgVo queryById(Long id); + + /** + * 分页查询萤石摄像头图片列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 萤石摄像头图片分页列表 + */ + TableDataInfo queryPageList(OthYs7DeviceImgQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的萤石摄像头图片列表 + * + * @param req 查询条件 + * @return 萤石摄像头图片列表 + */ + List queryList(OthYs7DeviceImgQueryReq req); + + /** + * 获取萤石摄像头图片视图 + * + * @param ys7DeviceImg 萤石摄像头图片 + * @return 萤石摄像头图片视图 + */ + OthYs7DeviceImgVo getVo(OthYs7DeviceImg ys7DeviceImg); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(OthYs7DeviceImgQueryReq req); + + /** + * 获取萤石摄像头图片分页对象视图 + * + * @param ys7DeviceImgPage 萤石摄像头图片分页对象 + * @return 萤石摄像头图片分页对象视图 + */ + Page getVoPage(Page ys7DeviceImgPage); + + /** + * 保存抓拍图片 + * + * @param imgList 抓拍图片列表 + */ + void saveCapturePic(List imgList); + + /** + * 根据创建时间删除图片 + * + * @param cutoffDate 截止时间 + * @return 删除数量 + */ + int deleteByCreateTimeBefore(Date cutoffDate); + + /** + * 校验并批量删除萤石摄像头图片信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthYs7DeviceService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthYs7DeviceService.java new file mode 100644 index 0000000..5997d7a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/IOthYs7DeviceService.java @@ -0,0 +1,146 @@ +package org.dromara.other.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; +import org.dromara.other.domain.OthYs7Device; +import org.dromara.other.domain.dto.ys7device.*; +import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo; + +import java.util.Collection; +import java.util.List; + +/** + * 萤石摄像头Service接口 + * + * @author lilemy + * @date 2025-06-13 + */ +public interface IOthYs7DeviceService extends IService { + + /** + * 查询萤石摄像头 + * + * @param id 主键 + * @return 萤石摄像头 + */ + OthYs7DeviceVo queryById(Long id); + + /** + * 分页查询萤石摄像头列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 萤石摄像头分页列表 + */ + TableDataInfo queryPageList(OthYs7DeviceQueryReq req, PageQuery pageQuery); + + /** + * 分页查询萤石摄像头列表 + * + * @param projectId 项目id + * @param pageQuery 分页参数 + * @return 萤石摄像头分页列表 + */ + TableDataInfo queryPageListByProject(Long projectId, PageQuery pageQuery); + + /** + * 查询符合条件的萤石摄像头列表 + * + * @param req 查询条件 + * @return 萤石摄像头列表 + */ + List queryList(OthYs7DeviceQueryReq req); + + /** + * 修改萤石摄像头 + * + * @param req 萤石摄像头 + * @return 是否修改成功 + */ + Boolean updateByBo(OthYs7DeviceUpdateReq req); + + /** + * 设备分配项目 + * + * @param req 萤石摄像头 + * @return 是否分配成功 + */ + Boolean updateWithProject(OthYs7DeviceWithProjectReq req); + + /** + * 修改萤石摄像头视频加密 + * + * @param req 萤石摄像头 + * @return 是否修改成功 + */ + Boolean updateVideoEncrypted(OthYs7DeviceUpdateEncryptedReq req); + + /** + * 校验并批量删除萤石摄像头信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取萤石摄像头视图 + * + * @param ys7Device 萤石摄像头 + * @return 萤石摄像头视图 + */ + OthYs7DeviceVo getVo(OthYs7Device ys7Device); + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(OthYs7DeviceQueryReq req); + + /** + * 获取萤石摄像头分页对象视图 + * + * @param ys7DevicePage 萤石摄像头分页对象 + * @return 萤石摄像头分页对象视图 + */ + Page getVoPage(Page ys7DevicePage); + + /** + * 获取萤石摄像对象 + * + * @param deviceResponseVo 萤石摄像数据 + * @return 萤石摄像对象 + */ + OthYs7Device getEntity(Ys7QueryDeviceResponseVo deviceResponseVo); + + /** + * 获取萤石摄像对象列表 + * + * @param deviceResponseVoList 萤石摄像数据列表 + * @return 萤石摄像对象列表 + */ + List getEntityList(List deviceResponseVoList); + + /** + * 根据云端数据保存或更新萤石摄像对象列表 + * + * @param deviceResponseVoList 云端萤石摄像数据列表 + * @return 是否有值发生更改 + */ + Boolean saveOrUpdateByDeviceList(List deviceResponseVoList); + + /** + * 萤石摄像头webhook + * + * @param receiveMessage 接收消息 + */ + void webhook(WebhookMessage receiveMessage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthDevicePresetServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthDevicePresetServiceImpl.java new file mode 100644 index 0000000..4f93864 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthDevicePresetServiceImpl.java @@ -0,0 +1,282 @@ +package org.dromara.other.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.manager.ys7manager.Ys7Manager; +import org.dromara.other.domain.OthDevicePreset; +import org.dromara.other.domain.OthYs7Device; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetCreateReq; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetQueryReq; +import org.dromara.other.domain.dto.devicepreset.OthDevicePresetUpdateReq; +import org.dromara.other.domain.enums.OthDeviceStatusEnum; +import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo; +import org.dromara.other.mapper.OthDevicePresetMapper; +import org.dromara.other.service.IOthDevicePresetService; +import org.dromara.other.service.IOthYs7DeviceService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 摄像头预置位Service业务层处理 + * + * @author lilemy + * @date 2025-06-13 + */ +@Service +public class OthDevicePresetServiceImpl extends ServiceImpl + implements IOthDevicePresetService { + + @Resource + private IOthYs7DeviceService othYs7DeviceService; + + @Resource + private IBusProjectService projectService; + + @Resource + private Ys7Manager ys7Manager; + + /** + * 查询摄像头预置位 + * + * @param id 主键 + * @return 摄像头预置位 + */ + @Override + public OthDevicePresetVo queryById(Long id) { + OthDevicePreset devicePreset = this.getById(id); + if (devicePreset == null) { + throw new RuntimeException("摄像头预置位信息不存在"); + } + return this.getVo(devicePreset); + } + + /** + * 分页查询摄像头预置位列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 摄像头预置位分页列表 + */ + @Override + public TableDataInfo queryPageList(OthDevicePresetQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的摄像头预置位列表 + * + * @param req 查询条件 + * @return 摄像头预置位列表 + */ + @Override + public List queryList(OthDevicePresetQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增摄像头预置位 + * + * @param req 摄像头预置位 + * @return 新增摄像头预置位主键id + */ + @Override + public Long insertByBo(OthDevicePresetCreateReq req) { + OthDevicePreset devicePreset = new OthDevicePreset(); + BeanUtils.copyProperties(req, devicePreset); + validEntityBeforeSave(devicePreset, true); + OthYs7Device ys7Device = othYs7DeviceService.lambdaQuery() + .eq(OthYs7Device::getDeviceSerial, devicePreset.getDeviceSerial()) + .one(); + if (ys7Device == null) { + throw new ServiceException("摄像头信息不存在", HttpStatus.NOT_FOUND); + } + if (!ys7Device.getStatus().equals(OthDeviceStatusEnum.ONLINE.getValue())) { + throw new ServiceException("摄像头不在线", HttpStatus.ERROR); + } + Integer index = ys7Manager.addDevicePreset(req.getDeviceSerial(), Math.toIntExact(req.getChannelNo())); + devicePreset.setPresetIndex(index); + boolean result = this.save(devicePreset); + if (!result) { + throw new ServiceException("摄像头预置位信息新增失败", HttpStatus.ERROR); + } + return devicePreset.getId(); + } + + /** + * 修改摄像头预置位 + * + * @param req 摄像头预置位 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(OthDevicePresetUpdateReq req) { + String presetName = req.getPresetName(); + if (StringUtils.isBlank(presetName)) { + throw new ServiceException("预置点名称不能为空", HttpStatus.ERROR); + } + OthDevicePreset devicePreset = new OthDevicePreset(); + BeanUtils.copyProperties(req, devicePreset); + validEntityBeforeSave(devicePreset, false); + OthDevicePreset oldDevicePreset = this.getById(req.getId()); + if (oldDevicePreset == null) { + throw new ServiceException("修改摄像头预置位信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + boolean result = this.updateById(devicePreset); + if (!result) { + throw new ServiceException("摄像头预置位信息更新失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 调用摄像头预置位 + * + * @param id 摄像头预置位id + * @return 是否调用成功 + */ + @Override + public Boolean moveById(Long id) { + OthDevicePreset devicePreset = this.getById(id); + if (devicePreset == null) { + throw new ServiceException("摄像头预置位信息不存在", HttpStatus.NOT_FOUND); + } + OthYs7Device ys7Device = othYs7DeviceService.lambdaQuery() + .eq(OthYs7Device::getDeviceSerial, devicePreset.getDeviceSerial()) + .one(); + if (ys7Device == null) { + throw new ServiceException("摄像头信息不存在", HttpStatus.NOT_FOUND); + } + boolean result = ys7Manager.moveDevicePreset( + devicePreset.getDeviceSerial(), + devicePreset.getChannelNo(), + devicePreset.getPresetIndex()); + if (!result) { + throw new ServiceException("调用摄像头预置位失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(OthDevicePreset entity, Boolean create) { + //TODO 做一些数据校验,如唯一约束 + String deviceSerial = entity.getDeviceSerial(); + if (create) { + if (StringUtils.isBlank(deviceSerial)) { + throw new ServiceException("设备序列号不能为空", HttpStatus.BAD_REQUEST); + } + } + if (StringUtils.isNotBlank(deviceSerial)) { + Long count = othYs7DeviceService.lambdaQuery() + .eq(OthYs7Device::getDeviceSerial, deviceSerial) + .count(); + if (count <= 0) { + throw new ServiceException("设备不存在", HttpStatus.BAD_REQUEST); + } + } + } + + /** + * 校验并批量删除摄像头预置位信息 + * + * @param id 待删除的主键 + * @return 是否删除成功 + */ + @Override + public Boolean deleteById(Long id) { + Long userId = LoginHelper.getUserId(); + OthDevicePreset devicePreset = this.getById(id); + String deviceSerial = devicePreset.getDeviceSerial(); + OthYs7Device device = othYs7DeviceService.lambdaQuery() + .eq(OthYs7Device::getDeviceSerial, deviceSerial) + .one(); + if (device == null) { + throw new ServiceException("设备不存在", HttpStatus.BAD_REQUEST); + } + Long projectId = device.getProjectId(); + if (projectId != 0) { + projectService.validAuth(projectId, userId); + } + Boolean result = ys7Manager.deleteDevicePreset( + deviceSerial, + devicePreset.getChannelNo(), + devicePreset.getPresetIndex()); + if (!result) { + throw new ServiceException("删除摄像头预置位信息失败", HttpStatus.ERROR); + } + return this.removeById(id); + } + + /** + * 获取摄像头预置位视图 + * + * @param devicePreset 摄像头预置位 + * @return 摄像头预置位视图 + */ + @Override + public OthDevicePresetVo getVo(OthDevicePreset devicePreset) { + OthDevicePresetVo vo = new OthDevicePresetVo(); + if (devicePreset == null) { + return vo; + } + BeanUtils.copyProperties(devicePreset, vo); + return vo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(OthDevicePresetQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + String deviceSerial = req.getDeviceSerial(); + Integer channelNo = req.getChannelNo(); + Integer index = req.getPresetIndex(); + String name = req.getPresetName(); + lqw.eq(StringUtils.isNotBlank(deviceSerial), OthDevicePreset::getDeviceSerial, deviceSerial); + lqw.eq(ObjectUtils.isNotEmpty(channelNo), OthDevicePreset::getChannelNo, channelNo); + lqw.eq(ObjectUtils.isNotEmpty(index), OthDevicePreset::getPresetIndex, index); + lqw.like(StringUtils.isNotBlank(name), OthDevicePreset::getPresetName, name); + return lqw; + } + + /** + * 获取摄像头预置位分页对象视图 + * + * @param devicePresetPage 摄像头预置位分页对象 + * @return 摄像头预置位分页对象视图 + */ + @Override + public Page getVoPage(Page devicePresetPage) { + List devicePresetList = devicePresetPage.getRecords(); + Page devicePresetVoPage = new Page<>( + devicePresetPage.getCurrent(), + devicePresetPage.getSize(), + devicePresetPage.getTotal()); + if (CollUtil.isEmpty(devicePresetList)) { + return devicePresetVoPage; + } + List devicePresetVoList = devicePresetList.stream().map(this::getVo).toList(); + devicePresetVoPage.setRecords(devicePresetVoList); + return devicePresetVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthYs7DeviceImgServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthYs7DeviceImgServiceImpl.java new file mode 100644 index 0000000..52adf43 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthYs7DeviceImgServiceImpl.java @@ -0,0 +1,333 @@ +package org.dromara.other.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.manager.recognizermanager.RecognizerManager; +import org.dromara.manager.recognizermanager.enums.RecognizerHasTargetEnum; +import org.dromara.manager.recognizermanager.enums.RecognizerTypeEnum; +import org.dromara.manager.recognizermanager.vo.RecognizeImageStreamResult; +import org.dromara.manager.recognizermanager.vo.RecognizeTargetVo; +import org.dromara.manager.recognizermanager.vo.RecognizeVo; +import org.dromara.other.constant.Ys7DeviceImgConstant; +import org.dromara.other.domain.OthYs7DeviceImg; +import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgCreateByCapture; +import org.dromara.other.domain.dto.ys7deviceimg.OthYs7DeviceImgQueryReq; +import org.dromara.other.domain.vo.ys7deviceimg.OthYs7DeviceImgVo; +import org.dromara.other.mapper.OthYs7DeviceImgMapper; +import org.dromara.other.service.IOthYs7DeviceImgService; +import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordCreateDto; +import org.dromara.safety.domain.enums.HseRecordCategoryEnum; +import org.dromara.safety.service.IHseRecognizeRecordService; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.InputStream; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; + +/** + * 萤石摄像头图片Service业务层处理 + * + * @author lilemy + * @date 2025-06-18 + */ +@Slf4j +@Service +public class OthYs7DeviceImgServiceImpl extends ServiceImpl + implements IOthYs7DeviceImgService { + + @Resource + private ISysOssService ossService; + + @Resource + private RecognizerManager recognizerManager; + + @Resource + private IHseRecognizeRecordService recognizeRecordService; + + /** + * 查询萤石摄像头图片 + * + * @param id 主键 + * @return 萤石摄像头图片 + */ + @Override + public OthYs7DeviceImgVo queryById(Long id) { + OthYs7DeviceImg ys7DeviceImg = this.getById(id); + if (ys7DeviceImg == null) { + throw new ServiceException("萤石摄像头图片信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(ys7DeviceImg); + } + + /** + * 分页查询萤石摄像头图片列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 萤石摄像头图片分页列表 + */ + @Override + public TableDataInfo queryPageList(OthYs7DeviceImgQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的萤石摄像头图片列表 + * + * @param req 查询条件 + * @return 萤石摄像头图片列表 + */ + @Override + public List queryList(OthYs7DeviceImgQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 获取萤石摄像头图片视图 + * + * @param ys7DeviceImg 萤石摄像头图片 + * @return 萤石摄像头图片视图 + */ + @Override + public OthYs7DeviceImgVo getVo(OthYs7DeviceImg ys7DeviceImg) { + OthYs7DeviceImgVo vo = new OthYs7DeviceImgVo(); + if (ys7DeviceImg == null) { + return vo; + } + BeanUtils.copyProperties(ys7DeviceImg, vo); + return vo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(OthYs7DeviceImgQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + String deviceSerial = req.getDeviceSerial(); + String deviceName = req.getDeviceName(); + Date createTime = req.getCreateTime(); + lqw.like(StringUtils.isNotBlank(deviceSerial), OthYs7DeviceImg::getDeviceSerial, deviceSerial); + lqw.like(StringUtils.isNotBlank(deviceName), OthYs7DeviceImg::getDeviceName, deviceName); + if (createTime != null) { + // 构造当天的起始和结束时间 + LocalDate localDate = createTime.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + LocalDateTime startOfDay = localDate.atStartOfDay(); + LocalDateTime startOfNextDay = localDate.plusDays(1).atStartOfDay(); + Date start = Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()); + Date end = Date.from(startOfNextDay.atZone(ZoneId.systemDefault()).toInstant()); + lqw.ge(OthYs7DeviceImg::getCreateTime, start) + .lt(OthYs7DeviceImg::getCreateTime, end); + } + lqw.orderByDesc(OthYs7DeviceImg::getCreateTime); + return lqw; + } + + /** + * 获取萤石摄像头图片分页对象视图 + * + * @param ys7DeviceImgPage 萤石摄像头图片分页对象 + * @return 萤石摄像头图片分页对象视图 + */ + @Override + public Page getVoPage(Page ys7DeviceImgPage) { + List ys7DeviceImgList = ys7DeviceImgPage.getRecords(); + Page ys7DeviceImgVoPage = new Page<>( + ys7DeviceImgPage.getCurrent(), + ys7DeviceImgPage.getSize(), + ys7DeviceImgPage.getTotal() + ); + if (CollUtil.isEmpty(ys7DeviceImgList)) { + return ys7DeviceImgVoPage; + } + List ys7DeviceImgVoList = ys7DeviceImgList.stream().map(deviceImg -> { + OthYs7DeviceImgVo vo = new OthYs7DeviceImgVo(); + if (deviceImg == null) { + return vo; + } + BeanUtils.copyProperties(deviceImg, vo); + if (deviceImg.getRecognizeUrl() != null) { + vo.setUrl(deviceImg.getRecognizeUrl()); + } + List recTypeList = JSONUtil.toList(deviceImg.getRecType(), String.class); + List list = recTypeList.stream().map(recType -> Objects.requireNonNull(RecognizerTypeEnum.fromValue(recType)).getText()).toList(); + vo.setRecTypeList(list); + return vo; + }).toList(); + ys7DeviceImgVoPage.setRecords(ys7DeviceImgVoList); + return ys7DeviceImgVoPage; + } + + /** + * 保存抓拍图片 + * + * @param imgList 抓拍图片列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void saveCapturePic(List imgList) { + List saveList = new ArrayList<>(); + List recordList = new ArrayList<>(); + for (OthYs7DeviceImgCreateByCapture img : imgList) { + OthYs7DeviceImg othYs7DeviceImg = new OthYs7DeviceImg(); + String url = img.getUrl(); + String deviceSerial = img.getDeviceSerial(); + String originalFilename = extractFilename(url); + String deviceImgOssPath = Ys7DeviceImgConstant.getDeviceImgOssPath(originalFilename, deviceSerial); + SysOssUploadVo uploadVo = ossService.uploadFileUrlWithNoSave(url, deviceImgOssPath); + String ossUrl = uploadVo.getUrl(); + if (StringUtils.isNotBlank(ossUrl)) { + othYs7DeviceImg.setDeviceSerial(deviceSerial); + othYs7DeviceImg.setCreateTime(img.getCreateTime()); + othYs7DeviceImg.setDeviceName(img.getDeviceName()); + othYs7DeviceImg.setUrl(ossUrl); + // 将抓取的图片进行识别 + List recTypes = List.of(RecognizerTypeEnum.HARDHAT, RecognizerTypeEnum.SMOKING, RecognizerTypeEnum.FIRE); + RecognizeVo recognizeVo = recognizerManager.recognize(ossUrl, recTypes); + if (recognizeVo != null && recognizeVo.getHasTarget().equals(RecognizerHasTargetEnum.YES.getValue())) { + // 记录识别信息 + HseRecognizeRecordCreateDto record = new HseRecognizeRecordCreateDto(); + record.setCreateTime(new Date()); + List targets = recognizeVo.getTargets(); + othYs7DeviceImg.setTargets(JSONUtil.toJsonStr(targets)); + othYs7DeviceImg.setImgSize(JSONUtil.toJsonStr(recognizeVo.getOriginalImgSize())); + othYs7DeviceImg.setIsRecognize(RecognizerHasTargetEnum.YES.getValue()); + List recTypeList = targets.stream().map(RecognizeTargetVo::getType).distinct().toList(); + othYs7DeviceImg.setRecType(JSONUtil.toJsonStr(recTypeList)); + String targetUrl = null; + try { + RecognizeImageStreamResult imageStreamResult = recognizerManager.drawImageToStream(url, targets); + InputStream inputStream = imageStreamResult.getInputStream(); + String contentType = imageStreamResult.getContentType(); + long length = imageStreamResult.getLength(); + String targetImgPath = Ys7DeviceImgConstant.getTargetImgOssPath(originalFilename, deviceSerial); + SysOssUploadVo drawImageUploadVo = ossService.uploadFileUrlWithNoSave(inputStream, targetImgPath, contentType, length); + targetUrl = drawImageUploadVo.getUrl(); + if (StringUtils.isNotBlank(targetUrl)) { + othYs7DeviceImg.setRecognizeUrl(targetUrl); + } + } catch (Exception e) { + log.error("图片绘制失败", e); + } + record.setTargets(targets); + record.setDeviceSerial(deviceSerial); + record.setDeviceName(img.getDeviceName()); + record.setPicture(targetUrl); + record.setRecordCategory(HseRecordCategoryEnum.MONITOR.getValue()); + record.setProjectId(img.getProjectId()); + recordList.add(record); + } + saveList.add(othYs7DeviceImg); + } + } + if (CollUtil.isNotEmpty(saveList)) { + boolean result = saveBatch(saveList); + if (!result) { + throw new ServiceException("批量新增图片失败,数据库异常", HttpStatus.ERROR); + } + } + if (CollUtil.isNotEmpty(recordList)) { + recognizeRecordService.saveByMonitor(recordList); + } + } + + /** + * 根据创建时间删除图片 + * + * @param cutoffDate 截止时间 + * @return 删除数量 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteByCreateTimeBefore(Date cutoffDate) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.lt(OthYs7DeviceImg::getCreateTime, cutoffDate); + // 删除对象存储中的图片 + List list = this.list(lqw); + if (CollUtil.isEmpty(list)) { + return 0; + } + OssClient storage = OssFactory.instance(); + for (OthYs7DeviceImg othYs7DeviceImg : list) { + storage.delete(othYs7DeviceImg.getUrl()); + if (othYs7DeviceImg.getRecognizeUrl() != null) { + storage.delete(othYs7DeviceImg.getRecognizeUrl()); + } + } + boolean result = this.removeBatchByIds(list); + if (!result) { + throw new ServiceException("删除图片失败,数据库异常", HttpStatus.ERROR); + } + return list.size(); + } + + /** + * 校验并批量删除萤石摄像头图片信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids) { + List ys7DeviceImgList = this.listByIds(ids); + if (CollUtil.isEmpty(ys7DeviceImgList)) { + return true; + } + OssClient storage = OssFactory.instance(); + for (OthYs7DeviceImg ys7DeviceImg : ys7DeviceImgList) { + storage.delete(ys7DeviceImg.getUrl()); + if (ys7DeviceImg.getRecognizeUrl() != null) { + storage.delete(ys7DeviceImg.getRecognizeUrl()); + } + } + return this.removeBatchByIds(ids); + } + + /** + * 提取文件名 + * + * @param url 文件路径 + * @return 文件名 + */ + private static String extractFilename(String url) { + int start = url.lastIndexOf("/") + 1; + int end = url.indexOf("?", start); + if (end == -1) { + return url.substring(start); + } + if (start > 0 && end > start) { + return url.substring(start, end); + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthYs7DeviceServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthYs7DeviceServiceImpl.java new file mode 100644 index 0000000..64f9b19 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/other/service/impl/OthYs7DeviceServiceImpl.java @@ -0,0 +1,483 @@ +package org.dromara.other.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.manager.ys7manager.Ys7Constant; +import org.dromara.manager.ys7manager.Ys7Manager; +import org.dromara.manager.ys7manager.enums.DeviceOnOffLineEnum; +import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo; +import org.dromara.other.domain.OthYs7Device; +import org.dromara.other.domain.dto.ys7device.*; +import org.dromara.other.domain.enums.OthDeviceStatusEnum; +import org.dromara.other.domain.enums.OthVideoEncryptedEnum; +import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo; +import org.dromara.other.mapper.OthYs7DeviceMapper; +import org.dromara.other.service.IOthYs7DeviceService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 萤石摄像头Service业务层处理 + * + * @author lilemy + * @date 2025-06-13 + */ +@Slf4j +@Service +public class OthYs7DeviceServiceImpl extends ServiceImpl + implements IOthYs7DeviceService { + + @Resource + private IBusProjectService projectService; + + @Resource + private Ys7Manager ys7Manager; + + /** + * 查询萤石摄像头 + * + * @param id 主键 + * @return 萤石摄像头 + */ + @Override + public OthYs7DeviceVo queryById(Long id) { + OthYs7Device ys7Device = this.getById(id); + if (ys7Device == null) { + throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(ys7Device); + } + + /** + * 分页查询萤石摄像头列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 萤石摄像头分页列表 + */ + @Override + public TableDataInfo queryPageList(OthYs7DeviceQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 分页查询萤石摄像头列表 + * + * @param projectId 项目id + * @param pageQuery 分页参数 + * @return 萤石摄像头分页列表 + */ + @Override + public TableDataInfo queryPageListByProject(Long projectId, PageQuery pageQuery) { + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(OthYs7Device::getProjectId, projectId); + lqw.orderByDesc(OthYs7Device::getStatus); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的萤石摄像头列表 + * + * @param req 查询条件 + * @return 萤石摄像头列表 + */ + @Override + public List queryList(OthYs7DeviceQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 修改萤石摄像头 + * + * @param req 萤石摄像头 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(OthYs7DeviceUpdateReq req) { + // 将实体类和 DTO 进行转换 + OthYs7Device ys7Device = new OthYs7Device(); + BeanUtils.copyProperties(req, ys7Device); + // 数据校验 + OthYs7Device oldYs7Device = this.getById(req.getId()); + if (oldYs7Device == null) { + throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND); + } + // 判断是否更新名称 + String deviceName = req.getDeviceName(); + if (deviceName != null && !deviceName.equals(oldYs7Device.getDeviceName())) { + Long count = this.lambdaQuery() + .eq(OthYs7Device::getDeviceName, req.getDeviceName()) + .count(); + if (count > 0) { + throw new ServiceException("已存在同名萤石摄像头", HttpStatus.CONFLICT); + } + Boolean result = ys7Manager.updateDeviceName(oldYs7Device.getDeviceSerial(), deviceName); + if (!result) { + throw new ServiceException("更新云端萤石摄像头名称异常", HttpStatus.ERROR); + } + } + boolean result = this.updateById(ys7Device); + if (!result) { + throw new ServiceException("更新萤石摄像头信息异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 设备分配项目 + * + * @param req 萤石摄像头 + * @return 是否分配成功 + */ + @Override + public Boolean updateWithProject(OthYs7DeviceWithProjectReq req) { + List ids = req.getId(); + Long projectId = req.getProjectId(); + // 参数校验 + if (CollUtil.isEmpty(ids) || projectId == null) { + throw new ServiceException("参数为空", HttpStatus.BAD_REQUEST); + } + List ys7DeviceList = this.listByIds(ids); + if (CollUtil.isEmpty(ys7DeviceList)) { + throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND); + } + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + // 权限校验 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(projectId, userId); + // 更新 + boolean update = this.lambdaUpdate() + .in(OthYs7Device::getId, ids) + .set(OthYs7Device::getProjectId, projectId) + .update(); + if (!update) { + throw new ServiceException("更新萤石摄像头信息异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 修改萤石摄像头视频加密 + * + * @param req 萤石摄像头 + * @return 是否修改成功 + */ + @Override + public Boolean updateVideoEncrypted(OthYs7DeviceUpdateEncryptedReq req) { + Long id = req.getId(); + Integer videoEncrypted = req.getVideoEncrypted(); + // 参数校验 + if (id == null || videoEncrypted == null) { + throw new ServiceException("参数为空", HttpStatus.BAD_REQUEST); + } + OthYs7Device ys7Device = this.getById(id); + if (ys7Device == null) { + throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND); + } + if (videoEncrypted.equals(ys7Device.getVideoEncrypted())) { + return true; + } + String text = OthVideoEncryptedEnum.getTextByValue(videoEncrypted); + if (text == null) { + throw new ServiceException("参数错误,未知状态", HttpStatus.BAD_REQUEST); + } + boolean update = this.lambdaUpdate() + .eq(OthYs7Device::getId, id) + .set(OthYs7Device::getVideoEncrypted, videoEncrypted) + .update(); + if (!update) { + throw new ServiceException("更新萤石摄像头信息异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 校验并批量删除萤石摄像头信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List deviceList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectIds = deviceList.stream() + .map(OthYs7Device::getProjectId) + .filter(id -> id != 0) + .distinct() + .toList(); + if (CollUtil.isNotEmpty(projectIds)) { + projectService.validAuth(projectIds, userId); + } + } + return this.removeBatchByIds(ids); + } + + /** + * 获取萤石摄像头视图 + * + * @param ys7Device 萤石摄像头 + * @return 萤石摄像头视图 + */ + @Override + public OthYs7DeviceVo getVo(OthYs7Device ys7Device) { + // 对象转封装类 + OthYs7DeviceVo ys7DeviceVo = new OthYs7DeviceVo(); + if (ys7Device == null) { + return ys7DeviceVo; + } + BeanUtils.copyProperties(ys7Device, ys7DeviceVo); + Long projectId = ys7Device.getProjectId(); + if (projectId != null && !projectId.equals(0L)) { + BusProject project = projectService.getById(projectId); + ys7DeviceVo.setProjectName(project.getProjectName()); + } + return ys7DeviceVo; + } + + /** + * 构建查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(OthYs7DeviceQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + String deviceSerial = req.getDeviceSerial(); + Long projectId = req.getProjectId(); + String deviceName = req.getDeviceName(); + String deviceType = req.getDeviceType(); + String deviceVersion = req.getDeviceVersion(); + Long status = req.getStatus(); + lqw.and(ObjectUtils.isNotEmpty(projectId), w -> w + .eq(OthYs7Device::getProjectId, projectId) + .or() + .eq(OthYs7Device::getProjectId, 0L)); + lqw.eq(ObjectUtils.isNotEmpty(status), OthYs7Device::getStatus, status); + lqw.like(StringUtils.isNotBlank(deviceName), OthYs7Device::getDeviceName, deviceName); + lqw.like(StringUtils.isNotBlank(deviceType), OthYs7Device::getDeviceType, deviceType); + lqw.like(StringUtils.isNotBlank(deviceSerial), OthYs7Device::getDeviceSerial, deviceSerial); + lqw.like(StringUtils.isNotBlank(deviceVersion), OthYs7Device::getDeviceVersion, deviceVersion); + lqw.orderByDesc(OthYs7Device::getProjectId); + lqw.orderByDesc(OthYs7Device::getStatus); + return lqw; + } + + /** + * 获取萤石摄像头分页对象视图 + * + * @param ys7DevicePage 萤石摄像头分页对象 + * @return 萤石摄像头分页对象视图 + */ + @Override + public Page getVoPage(Page ys7DevicePage) { + List ys7DeviceList = ys7DevicePage.getRecords(); + Page ys7DeviceVoPage = new Page<>( + ys7DevicePage.getCurrent(), + ys7DevicePage.getSize(), + ys7DevicePage.getTotal()); + if (CollUtil.isEmpty(ys7DeviceList)) { + return ys7DeviceVoPage; + } + // 获取项目列表 + Set projectIdList = ys7DeviceList.stream().map(OthYs7Device::getProjectId).collect(Collectors.toSet()); + List projectList = projectService.lambdaQuery() + .select(BusProject::getId, BusProject::getProjectName) + .in(BusProject::getId, projectIdList) + .list(); + Map projectMap = projectList.stream().collect(Collectors.toMap(BusProject::getId, project -> project)); + // 对象列表 => 封装对象列表 + List ys7DeviceVoList = ys7DeviceList.stream().map(ys7Device -> { + OthYs7DeviceVo ys7DeviceVo = new OthYs7DeviceVo(); + BeanUtils.copyProperties(ys7Device, ys7DeviceVo); + Long projectId = ys7Device.getProjectId(); + if (projectId != null && !projectId.equals(0L)) { + BusProject project = projectMap.get(projectId); + ys7DeviceVo.setProjectName(project.getProjectName()); + } + return ys7DeviceVo; + }).toList(); + ys7DeviceVoPage.setRecords(ys7DeviceVoList); + return ys7DeviceVoPage; + } + + /** + * 获取萤石摄像对象 + * + * @param deviceResponseVo 萤石摄像数据 + * @return 萤石摄像对象 + */ + @Override + public OthYs7Device getEntity(Ys7QueryDeviceResponseVo deviceResponseVo) { + OthYs7Device ys7Device = new OthYs7Device(); + if (deviceResponseVo == null) { + return ys7Device; + } + ys7Device.setDeviceSerial(deviceResponseVo.getDeviceSerial()); + ys7Device.setDeviceName(deviceResponseVo.getDeviceName()); + ys7Device.setDeviceType(deviceResponseVo.getDeviceType()); + ys7Device.setStatus(deviceResponseVo.getStatus()); + ys7Device.setDefence(Long.valueOf(deviceResponseVo.getDefence())); + ys7Device.setDeviceVersion(deviceResponseVo.getDeviceVersion()); + ys7Device.setDeviceCreateTime(new Date(deviceResponseVo.getAddTime())); + ys7Device.setDeviceUpdateTime(new Date(deviceResponseVo.getUpdateTime())); + ys7Device.setRiskLevel(deviceResponseVo.getRiskLevel()); + return ys7Device; + } + + /** + * 获取萤石摄像对象列表 + * + * @param deviceResponseVoList 萤石摄像数据列表 + * @return 萤石摄像对象列表 + */ + @Override + public List getEntityList(List deviceResponseVoList) { + if (CollUtil.isEmpty(deviceResponseVoList)) { + return List.of(); + } + return deviceResponseVoList.stream().map(this::getEntity).toList(); + } + + /** + * 根据云端数据保存或更新萤石摄像对象列表 + * + * @param deviceResponseVoList 云端萤石摄像数据列表 + * @return 是否有值发生更改 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean saveOrUpdateByDeviceList(List deviceResponseVoList) { + if (deviceResponseVoList == null) { + return false; + } + List deviceList = this.getEntityList(deviceResponseVoList); + if (CollUtil.isEmpty(deviceList)) { + return false; + } + // 查询数据库中的数据并构建 Map + Map entityMap = this.list().stream() + .collect(Collectors.toMap( + OthYs7Device::getDeviceSerial, + Function.identity(), + (a, b) -> a)); + // 记录日志 + StringBuffer updateLog = new StringBuffer(); + StringBuffer saveLog = new StringBuffer(); + // 遍历设备列表,设置已存在的 id + List resultList = deviceList.stream() + .filter(device -> { + OthYs7Device existing = entityMap.get(device.getDeviceSerial()); + // 若已有记录且未发生变化,则过滤掉 + return existing == null || !validDeviceUpdate(existing, device); + }) + .peek(device -> { + OthYs7Device existing = entityMap.get(device.getDeviceSerial()); + if (existing != null) { + device.setId(existing.getId()); + updateLog.append("[") + .append(device.getDeviceName()) + .append(",") + .append(device.getDeviceSerial()) + .append("]"); + } else { + saveLog.append("[") + .append(device.getDeviceName()) + .append(",") + .append(device.getDeviceSerial()) + .append("]"); + } + }) + .toList(); + if (CollUtil.isNotEmpty(resultList)) { + log.info("需新增信息设备:{}", saveLog); + log.info("需修改信息设备:{}", updateLog); + // 更新或保存设备列表 + return saveOrUpdateBatch(resultList); + } + return false; + } + + /** + * 萤石摄像头webhook + * + * @param receiveMessage 接收消息 + */ + @Override + public void webhook(WebhookMessage receiveMessage) { + String type = receiveMessage.getHeader().getType(); + // 设备上下线消息 + if (Ys7Constant.ON_OFF_LINE_TOPIC_TYPE.equals(type)) { + JSONObject jsonObject = JSONUtil.parseObj(receiveMessage.getBody()); + String deviceSerial = jsonObject.get("subSerial", String.class); + String msgType = jsonObject.get("msgType", String.class); + OthYs7Device device = this.lambdaQuery() + .eq(OthYs7Device::getDeviceSerial, deviceSerial) + .one(); + if (device == null) { + log.info("更新设备上下线状态失败,设备不存在:{}", deviceSerial); + return; + } + OthYs7Device updateDevice = new OthYs7Device(); + updateDevice.setId(device.getId()); + if (DeviceOnOffLineEnum.ONLINE.getValue().equals(msgType)) { + updateDevice.setStatus(OthDeviceStatusEnum.ONLINE.getValue()); + } else if (DeviceOnOffLineEnum.OFFLINE.getValue().equals(msgType)) { + updateDevice.setStatus(OthDeviceStatusEnum.OFFLINE.getValue()); + } + this.updateById(updateDevice); + } + } + + /** + * 验证萤石摄像对象是否发生更改 + * + * @param cloudDevice 云端萤石摄像对象 + * @param device 萤石摄像对象 + * @return true:云端设备与数据库中设备一致;false:云端设备与数据库中设备存在差异,即至少有一个字段发生了变化。 + */ + private Boolean validDeviceUpdate(OthYs7Device cloudDevice, OthYs7Device device) { + return Objects.equals(cloudDevice.getDeviceName(), device.getDeviceName()) + && Objects.equals(cloudDevice.getDeviceType(), device.getDeviceType()) + && Objects.equals(cloudDevice.getStatus(), device.getStatus()) + && Objects.equals(cloudDevice.getDefence(), device.getDefence()) + && Objects.equals(cloudDevice.getDeviceVersion(), device.getDeviceVersion()) + && Objects.equals(cloudDevice.getRiskLevel(), device.getRiskLevel()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/constant/PgsProgressCategoryConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/constant/PgsProgressCategoryConstant.java new file mode 100644 index 0000000..dd517e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/constant/PgsProgressCategoryConstant.java @@ -0,0 +1,82 @@ +package org.dromara.progress.constant; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/23 11:44 + */ +public interface PgsProgressCategoryConstant { + + /** + * 顶级父级id + */ + Long TOP_PARENT_ID = 0L; + + /** + * 项目公共进度类别ID + */ + Long PUBLIC_PROJECT_ID = 0L; + + /** + * 光伏板钻孔进度类别 + */ + String PHOTOVOLTAIC_PANEL_POINT_WORK_TYPE = "12"; + + /** + * 光伏板桩基进度类别 + */ + String PHOTOVOLTAIC_PANEL_COLUMN_WORK_TYPE = "13"; + + /** + * 光伏板支架进度类别 + */ + String PHOTOVOLTAIC_PANEL_SUPPORT_WORK_TYPE = "14"; + + /** + * 光伏板进度类别名称 + */ + List PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE = List.of( + "12", + "13", + "14", + "15", + "16", + "17" + ); + + /** + * 关联光伏板进度类别名称 + */ + List RELEVANCE_PHOTOVOLTAIC_PANEL_WORK_TYPE = List.of( + "12", + "13", + "14" + ); + + /** + * 逆变器进度类别名称 + */ + List INVERTER_PROGRESS_CATEGORY_WORK_TYPE = List.of( + "2", + "3", + "4", + "18", + "19", + "20", + "21" + ); + + /** + * 箱变进度类别名称 + */ + List BOX_TRANSFORMER_PROGRESS_CATEGORY_WORK_TYPE = List.of( + "23", + "24", + "25", + "26", + "27", + "28" + ); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryController.java new file mode 100644 index 0000000..755775a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryController.java @@ -0,0 +1,146 @@ +package org.dromara.progress.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryReq; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryUpdateReq; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryCoordinateVo; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryLastTimeVo; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryProjectVo; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryVo; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 进度类别 + * + * @author lilemy + * @date 2025-05-26 + */ +@Validated +@RestController +@RequestMapping("/progress/progressCategory") +public class PgsProgressCategoryController extends BaseController { + + @Resource + private IPgsProgressCategoryService pgsProgressCategoryService; + + /** + * 查询进度类别列表 + */ + @SaCheckPermission("progress:progressCategory:list") + @GetMapping("/list") + public R> list(PgsProgressCategoryQueryReq req) { + List list = pgsProgressCategoryService.queryList(req); + return R.ok(list); + } + + /** + * 导出进度类别列表 + */ + @SaCheckPermission("progress:progressCategory:export") + @Log(title = "进度类别", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PgsProgressCategoryQueryReq req, HttpServletResponse response) { + List list = pgsProgressCategoryService.queryList(req); + ExcelUtil.exportExcel(list, "进度类别", PgsProgressCategoryVo.class, response); + } + + /** + * 获取进度类别详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressCategory:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(pgsProgressCategoryService.queryById(id)); + } + + /** + * 获取进度类别坐标信息 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressCategory:query") + @GetMapping("/coordinate/{id}") + public R getCoordinate(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(pgsProgressCategoryService.getCoordinate(id)); + } + + /** + * 获取项目总的进度信息 + * + * @param projectId 项目主键 + */ + @SaCheckPermission("progress:progressCategory:query") + @GetMapping("/project/number/{projectId}") + public R getProjectNumber(@NotNull(message = "项目主键不能为空") + @PathVariable Long projectId) { + return R.ok(pgsProgressCategoryService.getProjectNumber(projectId)); + } + + /** + * 获取进度类别最后一次进度信息 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressCategory:query") + @GetMapping("/lastTime/{id}") + public R getLastTimeInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(pgsProgressCategoryService.queryLastTimeById(id)); + } + + /** + * 新增进度类别 + */ + @SaCheckPermission("progress:progressCategory:add") + @Log(title = "进度类别", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody PgsProgressCategoryCreateReq req) { + return R.ok(pgsProgressCategoryService.insertByBo(req)); + } + + /** + * 修改进度类别 + */ + @SaCheckPermission("progress:progressCategory:edit") + @Log(title = "进度类别", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody PgsProgressCategoryUpdateReq req) { + return toAjax(pgsProgressCategoryService.updateByBo(req)); + } + + /** + * 删除进度类别 + * + * @param ids 主键串 + */ + @SaCheckPermission("progress:progressCategory:remove") + @Log(title = "进度类别", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(pgsProgressCategoryService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryTemplateController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryTemplateController.java new file mode 100644 index 0000000..5aa4ad1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressCategoryTemplateController.java @@ -0,0 +1,118 @@ +package org.dromara.progress.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq; +import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo; +import org.dromara.progress.service.IPgsProgressCategoryTemplateService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 进度类别模版 + * + * @author lilemy + * @date 2025-05-22 + */ +@Validated +@RestController +@RequestMapping("/progress/progressCategoryTemplate") +public class PgsProgressCategoryTemplateController extends BaseController { + + @Resource + private IPgsProgressCategoryTemplateService pgsProgressCategoryTemplateService; + + /** + * 分页查询进度类别模版列表 + */ + @SaCheckPermission("progress:progressCategoryTemplate:page") + @GetMapping("/page") + public TableDataInfo page(PgsProgressCategoryTemplateQueryReq req, PageQuery pageQuery) { + return pgsProgressCategoryTemplateService.queryPageList(req, pageQuery); + } + + /** + * 查询进度类别模版列表 + */ + @SaCheckPermission("progress:progressCategoryTemplate:list") + @GetMapping("/list") + public R> list(PgsProgressCategoryTemplateQueryReq req) { + List list = pgsProgressCategoryTemplateService.queryList(req); + return R.ok(list); + } + + /** + * 导出进度类别模版列表 + */ + @SaCheckPermission("progress:progressCategoryTemplate:export") + @Log(title = "进度类别模版", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PgsProgressCategoryTemplateQueryReq req, HttpServletResponse response) { + List list = pgsProgressCategoryTemplateService.queryList(req); + ExcelUtil.exportExcel(list, "进度类别模版", PgsProgressCategoryTemplateVo.class, response); + } + + /** + * 获取进度类别模版详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressCategoryTemplate:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(pgsProgressCategoryTemplateService.queryById(id)); + } + + /** + * 新增进度类别模版 + */ + @SaCheckPermission("progress:progressCategoryTemplate:add") + @Log(title = "进度类别模版", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody PgsProgressCategoryTemplateCreateReq req) { + return R.ok(pgsProgressCategoryTemplateService.insertByBo(req)); + } + + /** + * 修改进度类别模版 + */ + @SaCheckPermission("progress:progressCategoryTemplate:edit") + @Log(title = "进度类别模版", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody PgsProgressCategoryTemplateUpdateReq req) { + return toAjax(pgsProgressCategoryTemplateService.updateByBo(req)); + } + + /** + * 删除进度类别模版 + * + * @param ids 主键串 + */ + @SaCheckPermission("progress:progressCategoryTemplate:remove") + @Log(title = "进度类别模版", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(pgsProgressCategoryTemplateService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressPlanController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressPlanController.java new file mode 100644 index 0000000..5f2375c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressPlanController.java @@ -0,0 +1,95 @@ +package org.dromara.progress.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanCreateReq; +import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanQueryReq; +import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo; +import org.dromara.progress.service.IPgsProgressPlanService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 进度计划 + * + * @author lilemy + * @date 2025-05-27 + */ +@Validated +@RestController +@RequestMapping("/progress/progressPlan") +public class PgsProgressPlanController extends BaseController { + + @Resource + private IPgsProgressPlanService pgsProgressPlanService; + + /** + * 查询进度计划列表 + */ + @SaCheckPermission("progress:progressPlan:list") + @GetMapping("/list") + public TableDataInfo list(PgsProgressPlanQueryReq req, PageQuery pageQuery) { + return pgsProgressPlanService.queryPageList(req, pageQuery); + } + + /** + * 导出进度计划列表 + */ + @SaCheckPermission("progress:progressPlan:export") + @Log(title = "进度计划", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PgsProgressPlanQueryReq req, HttpServletResponse response) { + List list = pgsProgressPlanService.queryList(req); + ExcelUtil.exportExcel(list, "进度计划", PgsProgressPlanVo.class, response); + } + + /** + * 获取进度计划详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressPlan:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(pgsProgressPlanService.queryById(id)); + } + + /** + * 新增进度计划 + */ + @SaCheckPermission("progress:progressPlan:add") + @Log(title = "进度计划", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody PgsProgressPlanCreateReq req) { + return R.ok(pgsProgressPlanService.insertByBo(req)); + } + + /** + * 删除进度计划 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressPlan:remove") + @Log(title = "进度计划", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(pgsProgressPlanService.deleteById(id)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressPlanDetailController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressPlanDetailController.java new file mode 100644 index 0000000..ec6f719 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/controller/PgsProgressPlanDetailController.java @@ -0,0 +1,90 @@ +package org.dromara.progress.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailPercentageCreateReq; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailUnFinishVo; +import org.dromara.progress.service.IPgsProgressPlanDetailService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 进度计划详情 + * + * @author lilemy + * @date 2025-05-27 + */ +@Validated +@RestController +@RequestMapping("/progress/progressPlanDetail") +public class PgsProgressPlanDetailController extends BaseController { + + @Resource + private IPgsProgressPlanDetailService pgsProgressPlanDetailService; + + /** + * 新增进度计划详情(普通设施) + */ + @SaCheckPermission("progress:progressPlanDetail:insert") + @RepeatSubmit() + @PostMapping("/insert/detail") + public R insertFinishedDetail(@Validated @RequestBody PgsProgressPlanDetailFinishedCreateReq req) { + return toAjax(pgsProgressPlanDetailService.insertFinishedDetail(req)); + } + + /** + * 新增进度计划详情(百分比设施) + */ + @SaCheckPermission("progress:progressPlanDetail:insert") + @RepeatSubmit() + @PostMapping("/insert/percentage") + public R insertPercentageDetail(@Validated @RequestBody PgsProgressPlanDetailPercentageCreateReq req) { + return toAjax(pgsProgressPlanDetailService.insertPercentageDetail(req)); + } + + /** + * 获取进度计划详情已完成设施详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressPlanDetail:query") + @GetMapping("/detail/finished/{id}") + public TableDataInfo getFinishedDetail(@NotNull(message = "主键不能为空") + @PathVariable Long id, + PageQuery pageQuery) { + return pgsProgressPlanDetailService.queryFinishedById(id, pageQuery); + } + + /** + * 获取进度计划详情未完成设施详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("progress:progressPlanDetail:query") + @GetMapping("/detail/unFinish/{id}") + public TableDataInfo getUnFinishDetail(@NotNull(message = "主键不能为空") + @PathVariable Long id, + PageQuery pageQuery) { + return pgsProgressPlanDetailService.queryUnFinishById(id, pageQuery); + } + + /** + * 删除进度计划详情 + */ + @SaCheckPermission("progress:progressPlanDetail:remove") + @RepeatSubmit() + @DeleteMapping("/remove/detail") + public R removeDetail(@Validated PgsProgressPlanDetailRemoveReq req) { + return toAjax(pgsProgressPlanDetailService.removeDetail(req)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressCategory.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressCategory.java new file mode 100644 index 0000000..c885c5a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressCategory.java @@ -0,0 +1,97 @@ +package org.dromara.progress.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 进度类别对象 pgs_progress_category + * + * @author lilemy + * @date 2025-05-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("pgs_progress_category") +public class PgsProgressCategory extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 父类别id + */ + private Long pid; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 方阵名称 + */ + private String matrixName; + + /** + * 类别名称 + */ + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + private String unitType; + + /** + * 总数量/百分比 + */ + private BigDecimal total; + + /** + * 已完成数量/百分比 + */ + private BigDecimal completed; + + /** + * 计划总数量/百分比 + */ + private BigDecimal planTotal; + + /** + * 是否超期(0否 1是) + */ + private String isDelay; + + /** + * 完成状态(0未开始 1进行中 2已完成) + */ + private String status; + + /** + * 工作类型 + */ + private String workType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressCategoryTemplate.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressCategoryTemplate.java new file mode 100644 index 0000000..07c686c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressCategoryTemplate.java @@ -0,0 +1,70 @@ +package org.dromara.progress.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 进度类别模版对象 pgs_progress_category_template + * + * @author lilemy + * @date 2025-05-22 + */ +@Data +@TableName("pgs_progress_category_template") +public class PgsProgressCategoryTemplate implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 父类别id + */ + private Long pid; + + /** + * 类别名称 + */ + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + private String unitType; + + /** + * 工作类型 + */ + private String workType; + + /** + * 项目id(0表示共用) + */ + private Long projectId; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressPlan.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressPlan.java new file mode 100644 index 0000000..501abcf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressPlan.java @@ -0,0 +1,82 @@ +package org.dromara.progress.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 进度计划对象 pgs_progress_plan + * + * @author lilemy + * @date 2025-05-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("pgs_progress_plan") +public class PgsProgressPlan extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 方阵名称 + */ + private String matrixName; + + /** + * 进度类型id + */ + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + private String progressCategoryName; + + /** + * 计划开始时间 + */ + private Date startDate; + + /** + * 计划结束时间 + */ + private Date endDate; + + /** + * 计划数量/百分比 + */ + private Long planNumber; + + /** + * 完成数量/百分比 + */ + private Long finishedNumber; + + /** + * 延期数量/百分比 + */ + private Long delayNumber; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressPlanDetail.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressPlanDetail.java new file mode 100644 index 0000000..23dabaf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/PgsProgressPlanDetail.java @@ -0,0 +1,72 @@ +package org.dromara.progress.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 进度计划详情对象 pgs_progress_plan_detail + * + * @author lilemy + * @date 2025-05-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("pgs_progress_plan_detail") +public class PgsProgressPlanDetail extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 进度计划id + */ + private Long progressPlanId; + + /** + * 进度类型id + */ + private Long progressCategoryId; + + /** + * 计划时间 + */ + private Date date; + + /** + * 计划数量/百分比 + */ + private Long planNumber; + + /** + * 完成数量/百分比 + */ + private Long finishedNumber; + + /** + * 完成详情 + */ + private String finishedDetail; + + /** + * AI填入数量 + */ + private Long aiFill; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryCreateReq.java new file mode 100644 index 0000000..a84f7d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryCreateReq.java @@ -0,0 +1,42 @@ +package org.dromara.progress.domain.dto.progresscategory; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/5/26 9:46 + */ +@Data +public class PgsProgressCategoryCreateReq { + + /** + * 父类别id + */ + private Long pid; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 类别名称 + */ + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + private String unitType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryQueryReq.java new file mode 100644 index 0000000..e8c7ee3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryQueryReq.java @@ -0,0 +1,22 @@ +package org.dromara.progress.domain.dto.progresscategory; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/5/26 9:46 + */ +@Data +public class PgsProgressCategoryQueryReq { + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryUpdateReq.java new file mode 100644 index 0000000..e4b28ef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategory/PgsProgressCategoryUpdateReq.java @@ -0,0 +1,69 @@ +package org.dromara.progress.domain.dto.progresscategory; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author lilemy + * @date 2025/5/26 9:47 + */ +@Data +public class PgsProgressCategoryUpdateReq { + + /** + * 主键id + */ + private Long id; + + /** + * 父类别id + */ + private Long pid; + + /** + * 项目id + */ + private Long projectId; + + /** + * 类别名称 + */ + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + private String unitType; + + /** + * 总数量/百分比 + */ + private BigDecimal total; + + /** + * 已完成数量/百分比 + */ + private BigDecimal completed; + + /** + * 计划总数量/百分比 + */ + private BigDecimal planTotal; + + /** + * 是否超期(0否 1是) + */ + private String isDelay; + + /** + * 完成状态(0未开始 1进行中 2已完成) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateCreateReq.java new file mode 100644 index 0000000..ac08290 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateCreateReq.java @@ -0,0 +1,43 @@ +package org.dromara.progress.domain.dto.progresscategorytemplate; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/22 16:07 + */ +@Data +public class PgsProgressCategoryTemplateCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6264724604334298318L; + + /** + * 父类别id + */ + private Long pid; + + /** + * 类别名称 + */ + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + private String unitType; + + /** + * 项目id(0表示共用) + */ + private Long projectId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateQueryReq.java new file mode 100644 index 0000000..aa2eaaa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateQueryReq.java @@ -0,0 +1,37 @@ +package org.dromara.progress.domain.dto.progresscategorytemplate; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/22 16:07 + */ +@Data +public class PgsProgressCategoryTemplateQueryReq implements Serializable { + @Serial + private static final long serialVersionUID = 2607953543340685175L; + + /** + * 父类别id + */ + private Long pid; + + /** + * 类别名称 + */ + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + private String unitType; + + /** + * 项目id(0表示共用) + */ + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateUpdateReq.java new file mode 100644 index 0000000..fd8a9c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progresscategorytemplate/PgsProgressCategoryTemplateUpdateReq.java @@ -0,0 +1,43 @@ +package org.dromara.progress.domain.dto.progresscategorytemplate; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/22 16:07 + */ +@Data +public class PgsProgressCategoryTemplateUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8324950385975719302L; + + /** + * 主键id + */ + private Long id; + + /** + * 父类别id + */ + private Long pid; + + /** + * 类别名称 + */ + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + private String unitType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplan/PgsProgressPlanCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplan/PgsProgressPlanCreateReq.java new file mode 100644 index 0000000..dfa2dce --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplan/PgsProgressPlanCreateReq.java @@ -0,0 +1,59 @@ +package org.dromara.progress.domain.dto.progressplan; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateDto; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/27 10:21 + */ +@Data +public class PgsProgressPlanCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -1696848895886843506L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 进度类型id + */ + private Long progressCategoryId; + + /** + * 计划开始时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date startDate; + + /** + * 计划结束时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date endDate; + + /** + * 计划数量/百分比 + */ + private Long planNumber; + + /** + * 计划详情列表 + */ + List detailList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplan/PgsProgressPlanQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplan/PgsProgressPlanQueryReq.java new file mode 100644 index 0000000..a66ff54 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplan/PgsProgressPlanQueryReq.java @@ -0,0 +1,47 @@ +package org.dromara.progress.domain.dto.progressplan; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/5/27 10:22 + */ +@Data +public class PgsProgressPlanQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2964218996260328296L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 进度类型id + */ + private Long progressCategoryId; + + /** + * 计划开始时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date startDate; + + /** + * 计划结束时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date endDate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailCreateDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailCreateDto.java new file mode 100644 index 0000000..5a622d3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailCreateDto.java @@ -0,0 +1,30 @@ +package org.dromara.progress.domain.dto.progressplandetail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author lilemy + * @date 2025/5/27 15:06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PgsProgressPlanDetailCreateDto { + + /** + * 计划时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date date; + + /** + * 计划数量/百分比 + */ + private Long planNumber; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailFinishedCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailFinishedCreateReq.java new file mode 100644 index 0000000..ae87cd0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailFinishedCreateReq.java @@ -0,0 +1,29 @@ +package org.dromara.progress.domain.dto.progressplandetail; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/28 9:36 + */ +@Data +public class PgsProgressPlanDetailFinishedCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5685368912659847672L; + + /** + * 主键id + */ + private Long id; + + /** + * 完成详情id列表 + */ + private List finishedDetailIdList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailPercentageCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailPercentageCreateReq.java new file mode 100644 index 0000000..3feeecb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailPercentageCreateReq.java @@ -0,0 +1,28 @@ +package org.dromara.progress.domain.dto.progressplandetail; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/28 16:06 + */ +@Data +public class PgsProgressPlanDetailPercentageCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2987044313320050949L; + + /** + * 主键id + */ + private Long id; + + /** + * 完成数量 + */ + private Long finishedNumber; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailRemoveReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailRemoveReq.java new file mode 100644 index 0000000..0b2f856 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/dto/progressplandetail/PgsProgressPlanDetailRemoveReq.java @@ -0,0 +1,29 @@ +package org.dromara.progress.domain.dto.progressplandetail; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/28 16:34 + */ +@Data +public class PgsProgressPlanDetailRemoveReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2345733680238879534L; + + /** + * 主键id + */ + private Long id; + + /** + * 详情id列表 + */ + private List detailIdList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsCoordinateTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsCoordinateTypeEnum.java new file mode 100644 index 0000000..4ecc6b6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsCoordinateTypeEnum.java @@ -0,0 +1,34 @@ +package org.dromara.progress.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/5/30 14:59 + */ +@Getter +public enum PgsCoordinateTypeEnum { + + POINT("Point", 1), + POLYGON("Polygon", 2); + + private final String text; + + private final int value; + + PgsCoordinateTypeEnum(String text, int value) { + this.text = text; + this.value = value; + } + + // 根据 value 获取对应的 text + public static String getTextByValue(int value) { + for (PgsCoordinateTypeEnum type : values()) { + if (type.getValue() == value) { + return type.getText(); + } + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsDelayStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsDelayStatusEnum.java new file mode 100644 index 0000000..7f409df --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsDelayStatusEnum.java @@ -0,0 +1,24 @@ +package org.dromara.progress.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/5/29 10:46 + */ +@Getter +public enum PgsDelayStatusEnum { + + UNDELAY("未延期", "0"), + DELAY("已延期", "1"); + + private final String text; + + private final String value; + + PgsDelayStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsFinishStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsFinishStatusEnum.java new file mode 100644 index 0000000..e7725dd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsFinishStatusEnum.java @@ -0,0 +1,25 @@ +package org.dromara.progress.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/5/28 18:49 + */ +@Getter +public enum PgsFinishStatusEnum { + + UNFINISH("未开始", "0"), + INPROGRESS("进行中", "1"), + FINISH("已完成", "2"); + + private final String text; + + private final String value; + + PgsFinishStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsProgressUnitTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsProgressUnitTypeEnum.java new file mode 100644 index 0000000..464000b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/enums/PgsProgressUnitTypeEnum.java @@ -0,0 +1,26 @@ +package org.dromara.progress.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/5/26 19:07 + */ +@Getter +public enum PgsProgressUnitTypeEnum { + + + NULL("无", "0"), + NUMBER("数量", "1"), + PERCENTAGE("百分比", "2"); + + private final String text; + + private final String value; + + PgsProgressUnitTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryCoordinateVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryCoordinateVo.java new file mode 100644 index 0000000..d324074 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryCoordinateVo.java @@ -0,0 +1,30 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import lombok.Data; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailDateVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/30 10:53 + */ +@Data +public class PgsProgressCategoryCoordinateVo implements Serializable { + + @Serial + private static final long serialVersionUID = 9161894407675118073L; + + /** + * 设施列表 + */ + private List facilityList; + + /** + * 进度计划列表 + */ + private List detailList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryFacilityVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryFacilityVo.java new file mode 100644 index 0000000..382173e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryFacilityVo.java @@ -0,0 +1,49 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import cn.hutool.json.JSONArray; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; + +/** + * @author lilemy + * @date 2025/5/30 11:26 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PgsProgressCategoryFacilityVo { + + /** + * 主键 + */ + private Long id; + + /** + * 光伏板名称 + */ + private String name; + + /** + * 位置 + */ + private JSONArray positions; + + /** + * 坐标类型 + */ + private String type; + + /** + * 完成状态(0未开始 1进行中 2完成) + */ + private String status; + + /** + * 完成时间 + */ + private LocalDate finishDate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryLastTimeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryLastTimeVo.java new file mode 100644 index 0000000..116de18 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryLastTimeVo.java @@ -0,0 +1,32 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/5/28 11:36 + */ +@Data +public class PgsProgressCategoryLastTimeVo implements Serializable { + + @Serial + private static final long serialVersionUID = -3509755254504905644L; + + /** + * 计划结束时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + private Date endDate; + + /** + * 剩余数量 + */ + private BigDecimal leftNum; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryMatrixVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryMatrixVo.java new file mode 100644 index 0000000..fcfad59 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryMatrixVo.java @@ -0,0 +1,65 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.json.handler.BigDecimalToIntegerSerializer; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author lilemy + * @date 2025/6/5 15:41 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PgsProgressCategoryMatrixVo implements Serializable { + + @Serial + private static final long serialVersionUID = 3061735290740592145L; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 方阵名称 + */ + private String name; + + /** + * 总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal total; + + /** + * 已完成数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal completed; + + /** + * 计划总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal planTotal; + + /** + * 已完成数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal completedPercentage; + + /** + * 计划中数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal planTotalPercentage; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryProjectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryProjectVo.java new file mode 100644 index 0000000..a892e58 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryProjectVo.java @@ -0,0 +1,67 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Data; +import org.dromara.common.json.handler.BigDecimalToIntegerSerializer; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/5 15:36 + */ +@Data +public class PgsProgressCategoryProjectVo implements Serializable { + + @Serial + private static final long serialVersionUID = -8208751933207899365L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 项目名称 + */ + private String name; + + /** + * 总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal total; + + /** + * 已完成数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal completed; + + /** + * 计划总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal planTotal; + + /** + * 已完成数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal completedPercentage; + + /** + * 计划中数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal planTotalPercentage; + + /** + * 子项目列表 + */ + private List children; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategorySubProjectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategorySubProjectVo.java new file mode 100644 index 0000000..3960f1c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategorySubProjectVo.java @@ -0,0 +1,71 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.json.handler.BigDecimalToIntegerSerializer; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/5 15:39 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PgsProgressCategorySubProjectVo implements Serializable { + + @Serial + private static final long serialVersionUID = 7523695525881518366L; + + /** + * 子项目id + */ + private Long subProjectId; + + /** + * 子项目名称 + */ + private String name; + + /** + * 总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal total; + + /** + * 已完成数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal completed; + + /** + * 计划总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal planTotal; + + /** + * 已完成数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal completedPercentage; + + /** + * 计划中数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal planTotalPercentage; + + /** + * 方阵列表 + */ + private List children; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryVo.java new file mode 100644 index 0000000..e7517b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategory/PgsProgressCategoryVo.java @@ -0,0 +1,121 @@ +package org.dromara.progress.domain.vo.progresscategory; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.common.json.handler.BigDecimalToIntegerSerializer; +import org.dromara.progress.domain.PgsProgressCategory; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + + +/** + * 进度类别视图对象 pgs_progress_category + * + * @author lilemy + * @date 2025-05-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = PgsProgressCategory.class) +public class PgsProgressCategoryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 父类别id + */ + @ExcelProperty(value = "父类别id") + private Long pid; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 方阵id + */ + private Long matrixId; + + /** + * 类别名称 + */ + @ExcelProperty(value = "类别名称") + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + @ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比") + private String unitType; + + /** + * 总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + @ExcelProperty(value = "总数量/百分比") + private BigDecimal total; + + /** + * 已完成数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + @ExcelProperty(value = "已完成数量/百分比") + private BigDecimal completed; + + /** + * 计划总数量/百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + @ExcelProperty(value = "计划总数量/百分比") + private BigDecimal planTotal; + + /** + * 已完成数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal completedPercentage; + + /** + * 计划中数量百分比 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal planTotalPercentage; + + /** + * 是否超期(0否 1是) + */ + @ExcelProperty(value = "是否超期", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=否,1=是") + private String isDelay; + + /** + * 完成状态(0未开始 1进行中 2已完成) + */ + @ExcelProperty(value = "完成状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未开始,1=进行中,2=已完成") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategorytemplate/PgsProgressCategoryTemplateVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategorytemplate/PgsProgressCategoryTemplateVo.java new file mode 100644 index 0000000..28b5de5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progresscategorytemplate/PgsProgressCategoryTemplateVo.java @@ -0,0 +1,66 @@ +package org.dromara.progress.domain.vo.progresscategorytemplate; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.progress.domain.PgsProgressCategoryTemplate; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 进度类别模版视图对象 pgs_progress_category_template + * + * @author lilemy + * @date 2025-05-22 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = PgsProgressCategoryTemplate.class) +public class PgsProgressCategoryTemplateVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 父类别id + */ + @ExcelProperty(value = "父类别id") + private Long pid; + + /** + * 类别名称 + */ + @ExcelProperty(value = "类别名称") + private String name; + + /** + * 计量方式(0无 1数量 2百分比) + */ + @ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=数量,2=百分比") + private String unitType; + + /** + * 项目id(0表示共用) + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplan/PgsProgressPlanVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplan/PgsProgressPlanVo.java new file mode 100644 index 0000000..d39179c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplan/PgsProgressPlanVo.java @@ -0,0 +1,91 @@ +package org.dromara.progress.domain.vo.progressplan; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.progress.domain.PgsProgressPlan; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 进度计划视图对象 pgs_progress_plan + * + * @author lilemy + * @date 2025-05-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = PgsProgressPlan.class) +public class PgsProgressPlanVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 进度类型id + */ + @ExcelProperty(value = "进度类型id") + private Long progressCategoryId; + + /** + * 进度类别名称 + */ + @ExcelProperty(value = "进度类别名称") + private String progressCategoryName; + + /** + * 计划开始时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + @ExcelProperty(value = "计划开始时间") + private Date startDate; + + /** + * 计划结束时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + @ExcelProperty(value = "计划结束时间") + private Date endDate; + + /** + * 计划数量/百分比 + */ + @ExcelProperty(value = "计划数量/百分比") + private Long planNumber; + + /** + * 完成数量/百分比 + */ + @ExcelProperty(value = "完成数量/百分比") + private Long finishedNumber; + + /** + * 延期数量/百分比 + */ + @ExcelProperty(value = "延迟数量/百分比") + private Long delayNumber; + + /** + * AI自动填入 + */ + private Long aiFill; + + /** + * 进度计划详情 + */ + private List detailList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailDateVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailDateVo.java new file mode 100644 index 0000000..7f5e00a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailDateVo.java @@ -0,0 +1,45 @@ +package org.dromara.progress.domain.vo.progressplandetail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.json.handler.BigDecimalToIntegerSerializer; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/5/30 11:01 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PgsProgressPlanDetailDateVo { + + /** + * 主键id + */ + private Long id; + + /** + * 计划时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + private Date date; + + /** + * 已完成数量 + */ + @JsonSerialize(using = BigDecimalToIntegerSerializer.class) + private BigDecimal finishedNumber; + + /** + * 完成详情 + */ + private List finishedDetail; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailFinishedVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailFinishedVo.java new file mode 100644 index 0000000..515d74e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailFinishedVo.java @@ -0,0 +1,31 @@ +package org.dromara.progress.domain.vo.progressplandetail; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author lilemy + * @date 2025/5/28 10:20 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PgsProgressPlanDetailFinishedVo { + + /** + * 设施id + */ + private Long id; + + /** + * 设施名称 + */ + private String name; + + /** + * 设施完成类型 + */ + private String finishType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailNumVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailNumVo.java new file mode 100644 index 0000000..fc90cfd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailNumVo.java @@ -0,0 +1,45 @@ +package org.dromara.progress.domain.vo.progressplandetail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author lilemy + * @date 2025/5/27 14:31 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PgsProgressPlanDetailNumVo { + + /** + * 主键id + */ + private Long id; + + /** + * 计划时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + private Date date; + + /** + * 计划数量/百分比 + */ + private Long planNumber; + + /** + * 完成数量/百分比 + */ + private Long finishedNumber; + + /** + * AI填入数量 + */ + private Long aiFill; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailUnFinishVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailUnFinishVo.java new file mode 100644 index 0000000..305fdcf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailUnFinishVo.java @@ -0,0 +1,33 @@ +package org.dromara.progress.domain.vo.progressplandetail; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/28 11:01 + */ +@Data +public class PgsProgressPlanDetailUnFinishVo implements Serializable { + + @Serial + private static final long serialVersionUID = 2970680763220471140L; + + /** + * 设施id + */ + private Long id; + + /** + * 设施名称 + */ + private String name; + + /** + * 设施状态 + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailVo.java new file mode 100644 index 0000000..69a2483 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/domain/vo/progressplandetail/PgsProgressPlanDetailVo.java @@ -0,0 +1,72 @@ +package org.dromara.progress.domain.vo.progressplandetail; + +import java.util.Date; + +import org.dromara.progress.domain.PgsProgressPlanDetail; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 进度计划详情视图对象 pgs_progress_plan_detail + * + * @author lilemy + * @date 2025-05-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = PgsProgressPlanDetail.class) +public class PgsProgressPlanDetailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 进度计划id + */ + @ExcelProperty(value = "进度计划id") + private Long progressPlanId; + + /** + * 计划时间 + */ + @ExcelProperty(value = "计划时间") + private Date date; + + /** + * 计划数量/百分比 + */ + @ExcelProperty(value = "计划数量/百分比") + private Long planNumber; + + /** + * 完成数量/百分比 + */ + @ExcelProperty(value = "完成数量/百分比") + private Long finishedNumber; + + /** + * AI填入数量 + */ + @ExcelProperty(value = "AI填入数量") + private Long aiFill; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressCategoryMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressCategoryMapper.java new file mode 100644 index 0000000..8a01aa8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressCategoryMapper.java @@ -0,0 +1,15 @@ +package org.dromara.progress.mapper; + +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 进度类别Mapper接口 + * + * @author lilemy + * @date 2025-05-26 + */ +public interface PgsProgressCategoryMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressCategoryTemplateMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressCategoryTemplateMapper.java new file mode 100644 index 0000000..903bf13 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressCategoryTemplateMapper.java @@ -0,0 +1,15 @@ +package org.dromara.progress.mapper; + +import org.dromara.progress.domain.PgsProgressCategoryTemplate; +import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 进度类别Mapper接口 + * + * @author lilemy + * @date 2025-05-22 + */ +public interface PgsProgressCategoryTemplateMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressPlanDetailMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressPlanDetailMapper.java new file mode 100644 index 0000000..a47dc53 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressPlanDetailMapper.java @@ -0,0 +1,15 @@ +package org.dromara.progress.mapper; + +import org.dromara.progress.domain.PgsProgressPlanDetail; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 进度计划详情Mapper接口 + * + * @author lilemy + * @date 2025-05-27 + */ +public interface PgsProgressPlanDetailMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressPlanMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressPlanMapper.java new file mode 100644 index 0000000..d935378 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/mapper/PgsProgressPlanMapper.java @@ -0,0 +1,15 @@ +package org.dromara.progress.mapper; + +import org.dromara.progress.domain.PgsProgressPlan; +import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 进度计划Mapper接口 + * + * @author lilemy + * @date 2025-05-27 + */ +public interface PgsProgressPlanMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryService.java new file mode 100644 index 0000000..0954ef6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryService.java @@ -0,0 +1,125 @@ +package org.dromara.progress.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryReq; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryUpdateReq; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryCoordinateVo; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryLastTimeVo; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryProjectVo; +import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryVo; + +import java.util.Collection; +import java.util.List; + +/** + * 进度类别Service接口 + * + * @author lilemy + * @date 2025-05-26 + */ +public interface IPgsProgressCategoryService extends IService { + + /** + * 查询进度类别 + * + * @param id 主键 + * @return 进度类别 + */ + PgsProgressCategoryVo queryById(Long id); + + /** + * 查询符合条件的进度类别列表 + * + * @param req 查询条件 + * @return 进度类别列表 + */ + List queryList(PgsProgressCategoryQueryReq req); + + /** + * 查询设施剩余数量 + * + * @param id 主键 + * @return 设施剩余数量 + */ + PgsProgressCategoryLastTimeVo queryLastTimeById(Long id); + + /** + * 新增进度类别 + * + * @param req 进度类别 + * @return 新增进度类别id + */ + Long insertByBo(PgsProgressCategoryCreateReq req); + + /** + * 修改进度类别 + * + * @param req 进度类别 + * @return 是否修改成功 + */ + Boolean updateByBo(PgsProgressCategoryUpdateReq req); + + /** + * 校验并批量删除进度类别信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取进度类别视图对象 + * + * @param progressCategory 进度类别对象 + * @return 进度类别视图对象 + */ + PgsProgressCategoryVo getVo(PgsProgressCategory progressCategory); + + /** + * 获取进度类别查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(PgsProgressCategoryQueryReq req); + + /** + * 获取进度类别列表对象视图 + * + * @param progressCategoryList 进度类别列表对象 + * @return 进度类别列表对象视图 + */ + List getVoList(List progressCategoryList); + + /** + * 根据模板创建进度类别 + * + * @param projectId 项目id + * @param matrixList 方阵列表 + * @param oldMatrixList 旧方阵列表 + * @return 是否创建成功 + */ + Boolean insertByTemplate(Long projectId, List matrixList, List oldMatrixList); + + /** + * 根据id获取进度类别坐标信息 + * + * @param id 进度类别id + * @return 进度类别坐标信息 + */ + PgsProgressCategoryCoordinateVo getCoordinate(Long id); + + /** + * 根据项目id获取项目进度类别数量信息 + * + * @param projectId 项目id + * @return 项目进度类别数量信息 + */ + PgsProgressCategoryProjectVo getProjectNumber(Long projectId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryTemplateService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryTemplateService.java new file mode 100644 index 0000000..2e5a160 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressCategoryTemplateService.java @@ -0,0 +1,99 @@ +package org.dromara.progress.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.progress.domain.PgsProgressCategoryTemplate; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq; +import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo; + +import java.util.Collection; +import java.util.List; + +/** + * 进度类别模版Service接口 + * + * @author lilemy + * @date 2025-05-22 + */ +public interface IPgsProgressCategoryTemplateService extends IService { + + /** + * 查询进度类别模版 + * + * @param id 主键 + * @return 进度类别模版 + */ + PgsProgressCategoryTemplateVo queryById(Long id); + + /** + * 分页查询进度类别模版 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 进度类别模版分页列表 + */ + TableDataInfo queryPageList(PgsProgressCategoryTemplateQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的进度类别模版列表 + * + * @param req 查询条件 + * @return 进度类别模版列表 + */ + List queryList(PgsProgressCategoryTemplateQueryReq req); + + /** + * 新增进度类别模版 + * + * @param req 进度类别模版 + * @return 新增进度类别模版id + */ + Long insertByBo(PgsProgressCategoryTemplateCreateReq req); + + /** + * 修改进度类别模版 + * + * @param req 进度类别模版 + * @return 是否修改成功 + */ + Boolean updateByBo(PgsProgressCategoryTemplateUpdateReq req); + + /** + * 校验并批量删除进度类别模版信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取进度类别模版视图对象 + * + * @param progressCategoryTemplate 进度类别模版对象 + * @return 进度类别模版视图对象 + */ + PgsProgressCategoryTemplateVo getVo(PgsProgressCategoryTemplate progressCategoryTemplate); + + /** + * 获取进度类别模版查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(PgsProgressCategoryTemplateQueryReq req); + + /** + * 获取进度类别模版分页对象视图 + * + * @param progressCategoryTemplatePage 进度类别模版分页对象 + * @return 进度类别模版分页对象视图 + */ + Page getVoPage(Page progressCategoryTemplatePage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressPlanDetailService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressPlanDetailService.java new file mode 100644 index 0000000..517a4f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressPlanDetailService.java @@ -0,0 +1,74 @@ +package org.dromara.progress.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.progress.domain.PgsProgressPlanDetail; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailPercentageCreateReq; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailUnFinishVo; + +import java.util.List; + +/** + * 进度计划详情Service接口 + * + * @author lilemy + * @date 2025-05-27 + */ +public interface IPgsProgressPlanDetailService extends IService { + + /** + * 插入进度计划详情设施 + * + * @param req 插入进度计划详情设施参数 + * @return 是否插入成功 + */ + Boolean insertFinishedDetail(PgsProgressPlanDetailFinishedCreateReq req); + + /** + * 插入进度计划详情设施 + * + * @param req 插入进度计划详情设施参数 + * @return 是否插入成功 + */ + Boolean insertPercentageDetail(PgsProgressPlanDetailPercentageCreateReq req); + + /** + * 分页查询进度计划详情已完成设施列表 + * + * @param id 主键 + * @param pageQuery 分页参数 + * @return 进度计划详情设施分页列表 + */ + TableDataInfo queryFinishedById(Long id, PageQuery pageQuery); + + /** + * 分页查询进度计划详情未完成设施列表 + * + * @param id 主键 + * @param pageQuery 分页参数 + * @return 进度计划详情设施分页列表 + */ + TableDataInfo queryUnFinishById(Long id, PageQuery pageQuery); + + /** + * 获取进度计划详情视图对象列表 + * + * @param progressPlanDetailList 进度计划详情对象列表 + * @return 进度计划详情视图对象列表 + */ + List getNumVoList(List progressPlanDetailList); + + /** + * 删除进度计划详情 + * + * @param req 删除进度计划详情参数 + * @return 是否删除成功 + */ + Boolean removeDetail(PgsProgressPlanDetailRemoveReq req); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressPlanService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressPlanService.java new file mode 100644 index 0000000..4067ce7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/IPgsProgressPlanService.java @@ -0,0 +1,104 @@ +package org.dromara.progress.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.domain.PgsProgressPlan; +import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanCreateReq; +import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanQueryReq; +import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo; + +import java.util.List; + +/** + * 进度计划Service接口 + * + * @author lilemy + * @date 2025-05-27 + */ +public interface IPgsProgressPlanService extends IService { + + /** + * 查询进度计划 + * + * @param id 主键 + * @return 进度计划 + */ + PgsProgressPlanVo queryById(Long id); + + /** + * 分页查询进度计划列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 进度计划分页列表 + */ + TableDataInfo queryPageList(PgsProgressPlanQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的进度计划列表 + * + * @param req 查询条件 + * @return 进度计划列表 + */ + List queryList(PgsProgressPlanQueryReq req); + + /** + * 新增进度计划 + * + * @param req 进度计划 + * @return 新增进度计划主键 + */ + Long insertByBo(PgsProgressPlanCreateReq req); + + /** + * 删除进度计划信息 + * + * @param id 待删除的主键 + * @return 是否删除成功 + */ + Boolean deleteById(Long id); + + /** + * 获取进度计划视图对象 + * + * @param progressPlan 进度计划对象 + * @return 进度计划视图对象 + */ + PgsProgressPlanVo getVo(PgsProgressPlan progressPlan); + + /** + * 获取进度计划查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(PgsProgressPlanQueryReq req); + + /** + * 获取进度计划分页对象视图 + * + * @param progressPlanPage 进度计划分页对象 + * @return 进度计划分页对象视图 + */ + Page getVoPage(Page progressPlanPage); + + /** + * 校验计划数量是否合法 + * + * @param planNumber 计划数量 + * @param progressCategory 进度类别 + */ + void validPlanNumber(Long planNumber, PgsProgressCategory progressCategory); + + /** + * 校验计划是否延迟 + * + * @return 是否延迟 + */ + Boolean validProgressPlanIsDelay(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressCategoryServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressCategoryServiceImpl.java new file mode 100644 index 0000000..49842e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressCategoryServiceImpl.java @@ -0,0 +1,751 @@ +package org.dromara.progress.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.utils.BigDecimalUtil; +import org.dromara.common.utils.JsonDimensionUtil; +import org.dromara.facility.domain.*; +import org.dromara.facility.service.*; +import org.dromara.progress.constant.PgsProgressCategoryConstant; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.domain.PgsProgressCategoryTemplate; +import org.dromara.progress.domain.PgsProgressPlan; +import org.dromara.progress.domain.PgsProgressPlanDetail; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryReq; +import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryUpdateReq; +import org.dromara.progress.domain.enums.PgsCoordinateTypeEnum; +import org.dromara.progress.domain.enums.PgsFinishStatusEnum; +import org.dromara.progress.domain.enums.PgsProgressUnitTypeEnum; +import org.dromara.progress.domain.vo.progresscategory.*; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailDateVo; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo; +import org.dromara.progress.mapper.PgsProgressCategoryMapper; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.progress.service.IPgsProgressCategoryTemplateService; +import org.dromara.progress.service.IPgsProgressPlanDetailService; +import org.dromara.progress.service.IPgsProgressPlanService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 进度类别Service业务层处理 + * + * @author lilemy + * @date 2025-05-26 + */ +@Service +public class PgsProgressCategoryServiceImpl extends ServiceImpl + implements IPgsProgressCategoryService { + + @Resource + private IPgsProgressCategoryTemplateService pgsProgressCategoryTemplateService; + + @Resource + private IFacPercentageFacilityService percentageFacilityService; + + @Lazy + @Resource + private IPgsProgressPlanService progressPlanService; + + @Lazy + @Resource + private IPgsProgressPlanDetailService progressPlanDetailService; + + @Lazy + @Resource + private IFacPhotovoltaicPanelService photovoltaicPanelService; + + @Lazy + @Resource + private IFacBoxTransformerService boxTransformerService; + + @Lazy + @Resource + private IFacInverterService inverterService; + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private IFacMatrixService matrixService; + + /** + * 查询进度类别 + * + * @param id 主键 + * @return 进度类别 + */ + @Override + public PgsProgressCategoryVo queryById(Long id) { + PgsProgressCategory progressCategory = this.getById(id); + if (progressCategory == null) { + throw new ServiceException("进度类别信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(progressCategory); + } + + /** + * 查询符合条件的进度类别列表 + * + * @param req 查询条件 + * @return 进度类别列表 + */ + @Override + public List queryList(PgsProgressCategoryQueryReq req) { + Long matrixId = req.getMatrixId(); + if (matrixService.getById(matrixId) == null) { + throw new ServiceException("方阵不存在", HttpStatus.BAD_REQUEST); + } + List list = this.lambdaQuery() + .eq(PgsProgressCategory::getMatrixId, matrixId) + .list(); + return this.getVoList(list); + } + + /** + * 查询设施剩余数量 + * + * @param id 主键 + * @return 设施剩余数量 + */ + @Override + public PgsProgressCategoryLastTimeVo queryLastTimeById(Long id) { + PgsProgressCategory progressCategory = this.getById(id); + if (progressCategory == null) { + throw new ServiceException("进度类别信息不存在", HttpStatus.NOT_FOUND); + } + PgsProgressCategoryLastTimeVo lastTimeVo = new PgsProgressCategoryLastTimeVo(); + BigDecimal total = progressCategory.getTotal(); + BigDecimal completed = progressCategory.getCompleted(); + BigDecimal planTotal = total.subtract(completed); + lastTimeVo.setLeftNum(planTotal); + PgsProgressPlan progressPlan = progressPlanService.lambdaQuery() + .eq(PgsProgressPlan::getProgressCategoryId, id) + .orderByDesc(PgsProgressPlan::getEndDate) + .last("limit 1") + .one(); + LocalDate now = LocalDate.now(); + Date date = DateUtils.toDate(now); + if (progressPlan != null && progressPlan.getEndDate().after(date)) { + lastTimeVo.setEndDate(progressPlan.getEndDate()); + } else { + lastTimeVo.setEndDate(date); + } + return lastTimeVo; + } + + /** + * 新增进度类别 + * + * @param req 进度类别 + * @return 新增进度类别id + */ + @Override + public Long insertByBo(PgsProgressCategoryCreateReq req) { + // 将实体类和 DTO 进行转换 + PgsProgressCategory progressCategory = new PgsProgressCategory(); + BeanUtils.copyProperties(req, progressCategory); + // 数据校验 + validEntityBeforeSave(progressCategory); + // 写入数据库 + boolean result = this.save(progressCategory); + if (!result) { + throw new ServiceException("新增进度类别失败,数据库异常", HttpStatus.ERROR); + } + return progressCategory.getId(); + } + + /** + * 修改进度类别 + * + * @param req 进度类别 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(PgsProgressCategoryUpdateReq req) { + // 将实体类和 DTO 进行转换 + PgsProgressCategory progressCategory = new PgsProgressCategory(); + BeanUtils.copyProperties(req, progressCategory); + PgsProgressCategory oldProgressCategory = this.getById(req.getId()); + if (oldProgressCategory == null) { + throw new ServiceException("修改进度类别失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 数据校验 + validEntityBeforeSave(progressCategory); + // 写入数据库 + boolean result = this.updateById(progressCategory); + if (!result) { + throw new ServiceException("更新进度类别失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(PgsProgressCategory entity) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long pid = entity.getPid(); + if (projectId != null && projectId != 0) { + if (this.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + if (pid != null && pid != 0) { + if (this.getById(pid) == null) { + throw new ServiceException("对应进度类别不存在", HttpStatus.NOT_FOUND); + } + } + // 名称唯一性校验 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(PgsProgressCategory::getName, entity.getName()); + if (projectId != null && projectId != 0) { + lqw.eq(PgsProgressCategory::getProjectId, entity.getProjectId()); + } + if (pid != null && pid != 0) { + lqw.eq(PgsProgressCategory::getPid, entity.getPid()); + } + if (entity.getId() != null) { + // 排除自身 + lqw.ne(PgsProgressCategory::getId, entity.getId()); + } + if (this.count(lqw) > 0) { + throw new ServiceException("已有同名进度类别", HttpStatus.CONFLICT); + } + } + + /** + * 校验并批量删除进度类别信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + return this.removeBatchByIds(ids); + } + + /** + * 获取进度类别视图对象 + * + * @param progressCategory 进度类别对象 + * @return 进度类别视图对象 + */ + @Override + public PgsProgressCategoryVo getVo(PgsProgressCategory progressCategory) { + if (progressCategory == null) { + return null; + } + // 对象转封装类 + PgsProgressCategoryVo progressCategoryVo = new PgsProgressCategoryVo(); + BeanUtils.copyProperties(progressCategory, progressCategoryVo); + return progressCategoryVo; + } + + /** + * 获取进度类别查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(PgsProgressCategoryQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), PgsProgressCategory::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), PgsProgressCategory::getMatrixId, matrixId); + return lqw; + } + + /** + * 获取进度类别列表对象视图 + * + * @param progressCategoryList 进度类别列表对象 + * @return 进度类别列表对象视图 + */ + @Override + public List getVoList(List progressCategoryList) { + if (CollUtil.isEmpty(progressCategoryList)) { + return List.of(); + } + // 1. 构建 pid -> 子节点列表的映射 + Map> parentIdToChildrenMap = progressCategoryList.stream() + .filter(item -> item.getPid() != 0) + .collect(Collectors.groupingBy(PgsProgressCategory::getPid)); + // 对象列表 => 封装对象列表 + return progressCategoryList.stream().map(progressCategory -> { + PgsProgressCategoryVo vo = new PgsProgressCategoryVo(); + BeanUtils.copyProperties(progressCategory, vo); + // 如果是父节点,计算其子节点的总和 + if (progressCategory.getPid() == 0) { + List children = parentIdToChildrenMap.getOrDefault(progressCategory.getId(), Collections.emptyList()); + // 获取父节点状态 + String pidStatus = getPidStatus(children); + // 累加子节点数据 + BigDecimal total = children.stream().map(PgsProgressCategory::getTotal).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal completed = children.stream().map(PgsProgressCategory::getCompleted).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal planTotal = children.stream().map(PgsProgressCategory::getPlanTotal).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + // 可以在 VO 中额外设置这些总和值(或替换原有字段) + vo.setTotal(total); + vo.setCompleted(completed); + vo.setPlanTotal(planTotal); + vo.setStatus(pidStatus); + } + // 计算百分比(避免除以 0) + vo.setCompletedPercentage(BigDecimalUtil.toPercentage(vo.getCompleted(), vo.getTotal())); + vo.setPlanTotalPercentage(BigDecimalUtil.toPercentage(vo.getPlanTotal(), vo.getTotal())); + return vo; + }).toList(); + } + + /** + * 根据模板创建进度类别 + * + * @param projectId 项目id + * @param matrixList 方阵列表 + * @param oldMatrixList 旧方阵列表 + * @return 是否创建成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByTemplate(Long projectId, List matrixList, List oldMatrixList) { + // 获取模板进度类别 + List categoryTemplateList = pgsProgressCategoryTemplateService.lambdaQuery() + .in(PgsProgressCategoryTemplate::getProjectId, projectId, PgsProgressCategoryConstant.PUBLIC_PROJECT_ID) + .list(); + // 遍历模板进度类别,复制数据 + if (CollUtil.isEmpty(categoryTemplateList)) { + throw new ServiceException("对应模板进度类别不存在", HttpStatus.NOT_FOUND); + } + // 获取百分比设施数据 + Map> oldPercentageCategoryMap = new HashMap<>(); + Map> oldPlanMap = new HashMap<>(); + Map> oldPlanDetailMap = new HashMap<>(); + List oldMatrixIdList = new ArrayList<>(); + if (CollUtil.isNotEmpty(oldMatrixList)) { + oldMatrixIdList = oldMatrixList.stream().map(FacMatrix::getId).toList(); + List oldPercentageCategoryList = this.lambdaQuery() + .in(PgsProgressCategory::getMatrixId, oldMatrixIdList) + .ne(PgsProgressCategory::getPid, PgsProgressCategoryConstant.TOP_PARENT_ID) + .eq(PgsProgressCategory::getUnitType, PgsProgressUnitTypeEnum.PERCENTAGE.getValue()) + .list(); + oldPercentageCategoryMap = oldPercentageCategoryList.stream() + .collect(Collectors.groupingBy(item -> item.getMatrixName() + "_" + item.getWorkType())); + // 获取百分比设施计划数据 + List oldPercentageCategoryIdList = oldPercentageCategoryList.stream().map(PgsProgressCategory::getId).toList(); + if (CollUtil.isNotEmpty(oldPercentageCategoryIdList)) { + List oldPlanList = progressPlanService.lambdaQuery() + .select(PgsProgressPlan::getId, PgsProgressPlan::getProgressCategoryId) + .in(PgsProgressPlan::getProgressCategoryId, oldPercentageCategoryIdList) + .list(); + oldPlanMap = oldPlanList.stream() + .collect(Collectors.groupingBy(PgsProgressPlan::getProgressCategoryId)); + // 获取百分比设施计划详情数据 + List oldPlanIdList = oldPlanList.stream().map(PgsProgressPlan::getId).toList(); + if (CollUtil.isNotEmpty(oldPlanIdList)) { + List oldPlanDetailList = progressPlanDetailService.lambdaQuery() + .in(PgsProgressPlanDetail::getProgressPlanId, oldPlanIdList) + .list(); + oldPlanDetailMap = oldPlanDetailList.stream() + .collect(Collectors.groupingBy(PgsProgressPlanDetail::getProgressPlanId)); + } + } + } + // 需修改、保存的数据 + List newList = new ArrayList<>(); + List percentageFacilityList = new ArrayList<>(); + List newPlanList = new ArrayList<>(); + List newPlanDetailList = new ArrayList<>(); + // 每个 matrixId 对应一套新的 ID 映射 + for (FacMatrix matrix : matrixList) { + // templateId -> newId + Map localIdMap = new HashMap<>(); + List localList = new ArrayList<>(); + for (PgsProgressCategoryTemplate template : categoryTemplateList) { + Long newId = IdWorker.getId(); + localIdMap.put(template.getId(), newId); + PgsProgressCategory newCategory = new PgsProgressCategory(); + newCategory.setId(newId); + newCategory.setName(template.getName()); + newCategory.setUnitType(template.getUnitType()); + newCategory.setWorkType(template.getWorkType()); + newCategory.setProjectId(projectId); + newCategory.setMatrixId(matrix.getId()); + newCategory.setMatrixName(matrix.getMatrixName()); + newCategory.setRemark(template.getRemark()); + // 先临时设置旧 pid + newCategory.setPid(template.getPid()); + localList.add(newCategory); + // 创建百分比设施 + if (template.getPid() != 0 && template.getUnitType().equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue())) { + String mapKey = matrix.getMatrixName() + "_" + template.getWorkType(); + // 填充数据 + if (CollUtil.isNotEmpty(oldPercentageCategoryMap) && oldPercentageCategoryMap.containsKey(mapKey)) { + PgsProgressCategory oldPercentageCategory = oldPercentageCategoryMap.get(mapKey).getFirst(); + if (CollUtil.isNotEmpty(oldPlanMap) && oldPlanMap.containsKey(oldPercentageCategory.getId())) { + List planList = oldPlanMap.get(oldPercentageCategory.getId()); + // 填充计划数据 + for (PgsProgressPlan plan : planList) { + PgsProgressPlan newPlan = new PgsProgressPlan(); + Long planId = plan.getId(); + newPlan.setId(planId); + newPlan.setProjectId(projectId); + newPlan.setMatrixId(matrix.getId()); + newPlan.setProgressCategoryId(newId); + newPlanList.add(newPlan); + // 填充计划详情数据 + if (CollUtil.isNotEmpty(oldPlanDetailMap) && oldPlanDetailMap.containsKey(planId)) { + List planDetailList = oldPlanDetailMap.get(planId); + for (PgsProgressPlanDetail planDetail : planDetailList) { + PgsProgressPlanDetail newPlanDetail = new PgsProgressPlanDetail(); + newPlanDetail.setId(planDetail.getId()); + newPlanDetail.setProgressCategoryId(newId); + newPlanDetailList.add(newPlanDetail); + } + } + } + } + newCategory.setCompleted(oldPercentageCategory.getCompleted()); + newCategory.setPlanTotal(oldPercentageCategory.getPlanTotal()); + newCategory.setIsDelay(oldPercentageCategory.getIsDelay()); + newCategory.setStatus(oldPercentageCategory.getStatus()); + } + newCategory.setTotal(BigDecimal.valueOf(100)); + FacPercentageFacility percentageFacility = new FacPercentageFacility(); + percentageFacility.setProjectId(projectId); + percentageFacility.setMatrixId(matrix.getId()); + percentageFacility.setProgressCategoryId(newId); + percentageFacility.setProgressCategoryName(template.getName()); + percentageFacilityList.add(percentageFacility); + } + } + // 修正本 matrix 的 pid + for (PgsProgressCategory category : localList) { + Long oldPid = category.getPid(); + if (oldPid != 0) { + category.setPid(localIdMap.getOrDefault(oldPid, 0L)); + } + } + newList.addAll(localList); + } + // 删除旧进度类别 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(PgsProgressCategory::getProjectId, projectId); + long oldCategoryCount = this.count(lqw); + if (oldCategoryCount > 0) { + boolean remove = this.remove(lqw); + if (!remove) { + throw new ServiceException("删除旧进度类别失败", HttpStatus.ERROR); + } + } + // 批量保存新进度类别 + boolean result = this.saveBatch(newList); + if (!result) { + throw new ServiceException("创建进度类别失败", HttpStatus.ERROR); + } + // 删除旧数据 + LambdaQueryWrapper percentageFacilityLqw = new LambdaQueryWrapper<>(); + if (CollUtil.isNotEmpty(oldMatrixIdList)) { + percentageFacilityLqw.eq(FacPercentageFacility::getMatrixId, oldMatrixIdList); + } + long count = percentageFacilityService.count(percentageFacilityLqw); + if (count > 0) { + boolean remove = percentageFacilityService.remove(percentageFacilityLqw); + if (!remove) { + throw new ServiceException("删除旧百分比设施数据失败", HttpStatus.ERROR); + } + } + // 保存百分比设施 + if (CollUtil.isNotEmpty(percentageFacilityList)) { + boolean save = percentageFacilityService.saveBatch(percentageFacilityList); + if (!save) { + throw new ServiceException("创建设施失败", HttpStatus.ERROR); + } + } + // 修改百分比设施计划 + if (CollUtil.isNotEmpty(newPlanList)) { + boolean save = progressPlanService.updateBatchById(newPlanList); + if (!save) { + throw new ServiceException("修改设施计划失败", HttpStatus.ERROR); + } + } + // 修改百分比设施计划详情 + if (CollUtil.isNotEmpty(newPlanDetailList)) { + boolean save = progressPlanDetailService.updateBatchById(newPlanDetailList); + if (!save) { + throw new ServiceException("修改设施计划详情失败", HttpStatus.ERROR); + } + } + return true; + } + + /** + * 根据id获取进度类别坐标信息 + * + * @param id 进度类别id + * @return 进度类别坐标信息 + */ + @Override + public PgsProgressCategoryCoordinateVo getCoordinate(Long id) { + PgsProgressCategory progressCategory = this.getById(id); + if (progressCategory == null) { + throw new ServiceException("进度类别信息不存在", HttpStatus.NOT_FOUND); + } + String workType = progressCategory.getWorkType(); + List facilityList; + PgsProgressCategoryCoordinateVo coordinateVo = new PgsProgressCategoryCoordinateVo(); + if (PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List list = photovoltaicPanelService.lambdaQuery() + .eq(FacPhotovoltaicPanel::getProjectId, progressCategory.getProjectId()) + .eq(FacPhotovoltaicPanel::getMatrixId, progressCategory.getMatrixId()) + .eq(FacPhotovoltaicPanel::getProgressCategoryId, progressCategory.getId()) + .list(); + facilityList = list.stream().map(fac -> { + JSONArray jsonArray = JSONUtil.parseArray(fac.getPositions()); + int depth = JsonDimensionUtil.getJsonArrayDepth(jsonArray); + return new PgsProgressCategoryFacilityVo( + fac.getId(), + fac.getName(), + jsonArray, + PgsCoordinateTypeEnum.getTextByValue(depth), + fac.getStatus(), + fac.getFinishDate() + ); + }).toList(); + } else if (PgsProgressCategoryConstant.INVERTER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List list = inverterService.lambdaQuery() + .eq(FacInverter::getProjectId, progressCategory.getProjectId()) + .eq(FacInverter::getMatrixId, progressCategory.getMatrixId()) + .eq(FacInverter::getProgressCategoryId, progressCategory.getId()) + .list(); + facilityList = list.stream().map(fac -> { + JSONArray jsonArray = JSONUtil.parseArray(fac.getPositions()); + int depth = JsonDimensionUtil.getJsonArrayDepth(jsonArray); + return new PgsProgressCategoryFacilityVo( + fac.getId(), + fac.getName(), + jsonArray, + PgsCoordinateTypeEnum.getTextByValue(depth), + fac.getStatus(), + fac.getFinishDate() + ); + }).toList(); + } else if (PgsProgressCategoryConstant.BOX_TRANSFORMER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List list = boxTransformerService.lambdaQuery() + .eq(FacBoxTransformer::getProjectId, progressCategory.getProjectId()) + .eq(FacBoxTransformer::getMatrixId, progressCategory.getMatrixId()) + .eq(FacBoxTransformer::getProgressCategoryId, progressCategory.getId()) + .list(); + facilityList = list.stream().map(fac -> { + JSONArray jsonArray = JSONUtil.parseArray(fac.getPositions()); + int depth = JsonDimensionUtil.getJsonArrayDepth(jsonArray); + return new PgsProgressCategoryFacilityVo( + fac.getId(), + fac.getName(), + jsonArray, + PgsCoordinateTypeEnum.getTextByValue(depth), + fac.getStatus(), + fac.getFinishDate() + ); + }).toList(); + } else { + return coordinateVo; + } + List detailList = progressPlanDetailService.lambdaQuery() + .select(PgsProgressPlanDetail::getId, + PgsProgressPlanDetail::getDate, + PgsProgressPlanDetail::getFinishedNumber, + PgsProgressPlanDetail::getFinishedDetail) + .eq(PgsProgressPlanDetail::getProgressCategoryId, id) + .orderByAsc(PgsProgressPlanDetail::getDate) + .list() + .stream().map(detail -> { + PgsProgressPlanDetailDateVo detailDateVo = new PgsProgressPlanDetailDateVo(); + detailDateVo.setId(detail.getId()); + detailDateVo.setDate(detail.getDate()); + detailDateVo.setFinishedNumber(new BigDecimal(detail.getFinishedNumber())); + String finishedDetail = detail.getFinishedDetail(); + if (StringUtils.isNotBlank(finishedDetail)) { + List finishedVoList = JSONUtil.toList(finishedDetail, PgsProgressPlanDetailFinishedVo.class); + detailDateVo.setFinishedDetail(finishedVoList); + } + return detailDateVo; + }).toList(); + coordinateVo.setDetailList(detailList); + coordinateVo.setFacilityList(facilityList); + return coordinateVo; + } + + /** + * 根据项目id获取项目进度类别数量信息 + * + * @param projectId 项目id + * @return 项目进度类别数量信息 + */ + @Override + public PgsProgressCategoryProjectVo getProjectNumber(Long projectId) { + // 获取项目信息 + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 获取子项目信息 + List subProjectList = projectService.lambdaQuery() + .select(BusProject::getId) + .eq(BusProject::getPId, projectId) + .list(); + if (CollUtil.isEmpty(subProjectList)) { + return null; + } + List subProjectIdList = subProjectList.stream().map(BusProject::getId).toList(); + // 获取方阵信息 + List matrixList = matrixService.lambdaQuery() + .select(FacMatrix::getId, FacMatrix::getProjectId) + .in(FacMatrix::getProjectId, subProjectIdList) + .list(); + if (CollUtil.isEmpty(matrixList)) { + return null; + } + List matrixIdList = matrixList.stream().map(FacMatrix::getId).toList(); + // 分组:projectId -> matrixList + Map> matrixGroupByProject = matrixList.stream() + .collect(Collectors.groupingBy(FacMatrix::getProjectId)); + // 获取每个方阵下的进度类别信息 + List progressCategoryList = this.lambdaQuery() + .select(PgsProgressCategory::getId, + PgsProgressCategory::getStatus, + PgsProgressCategory::getMatrixId, + PgsProgressCategory::getTotal, + PgsProgressCategory::getPlanTotal, + PgsProgressCategory::getCompleted) + .in(PgsProgressCategory::getMatrixId, matrixIdList) + .list(); + // 分组:matrixId -> categoryList + Map> categoryGroupByMatrix = progressCategoryList. + stream().collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId)); + // 封装结果 + List subProjectVoList = new ArrayList<>(); + BigDecimal totalAll = BigDecimal.ZERO; + BigDecimal completedAll = BigDecimal.ZERO; + BigDecimal planTotalAll = BigDecimal.ZERO; + for (BusProject subProject : subProjectList) { + Long subProjectId = subProject.getId(); + List subMatrices = matrixGroupByProject.get(subProjectId); + if (CollUtil.isEmpty(subMatrices)) { + continue; + } + List matrixVoList = new ArrayList<>(); + BigDecimal total = BigDecimal.ZERO; + BigDecimal completed = BigDecimal.ZERO; + BigDecimal planTotal = BigDecimal.ZERO; + for (FacMatrix matrix : subMatrices) { + Long matrixId = matrix.getId(); + List categories = categoryGroupByMatrix.get(matrixId); + if (CollUtil.isEmpty(categories)) { + continue; + } + BigDecimal matrixTotal = categories.stream().map(PgsProgressCategory::getTotal).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal matrixCompleted = categories.stream().map(PgsProgressCategory::getCompleted).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal matrixPlanTotal = categories.stream().map(PgsProgressCategory::getPlanTotal).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + total = total.add(matrixTotal); + completed = completed.add(matrixCompleted); + planTotal = planTotal.add(matrixPlanTotal); + // 构建 matrixVo + PgsProgressCategoryMatrixVo matrixVo = new PgsProgressCategoryMatrixVo(); + matrixVo.setMatrixId(matrixId); + matrixVo.setTotal(matrixTotal); + matrixVo.setCompleted(matrixCompleted); + matrixVo.setPlanTotal(matrixPlanTotal); + matrixVo.setCompletedPercentage(BigDecimalUtil.toPercentage(matrixCompleted, matrixTotal)); + matrixVo.setPlanTotalPercentage(BigDecimalUtil.toPercentage(matrixPlanTotal, matrixTotal)); + matrixVoList.add(matrixVo); + } + // 构建子项目VO + PgsProgressCategorySubProjectVo subProjectVo = new PgsProgressCategorySubProjectVo(); + subProjectVo.setSubProjectId(subProjectId); + subProjectVo.setName(subProject.getProjectName()); + subProjectVo.setTotal(total); + subProjectVo.setCompleted(completed); + subProjectVo.setPlanTotal(planTotal); + subProjectVo.setCompletedPercentage(BigDecimalUtil.toPercentage(completed, total)); + subProjectVo.setPlanTotalPercentage(BigDecimalUtil.toPercentage(planTotal, total)); + subProjectVo.setChildren(matrixVoList); + // 累加总项目数据 + totalAll = totalAll.add(total); + completedAll = completedAll.add(completed); + planTotalAll = planTotalAll.add(planTotal); + subProjectVoList.add(subProjectVo); + } + // 构建项目VO + PgsProgressCategoryProjectVo projectVo = new PgsProgressCategoryProjectVo(); + projectVo.setProjectId(projectId); + projectVo.setName(project.getProjectName()); + projectVo.setTotal(totalAll); + projectVo.setCompleted(completedAll); + projectVo.setPlanTotal(planTotalAll); + projectVo.setCompletedPercentage(BigDecimalUtil.toPercentage(completedAll, totalAll)); + projectVo.setPlanTotalPercentage(BigDecimalUtil.toPercentage(planTotalAll, totalAll)); + projectVo.setChildren(subProjectVoList); + return projectVo; + } + + /** + * 根据子节点完成状态获取父节点完成状态 + * + * @param children 子节点列表 + * @return 父节点完成状态 + */ + public String getPidStatus(List children) { + if (CollUtil.isEmpty(children)) { + return PgsFinishStatusEnum.UNFINISH.getValue(); // 为空视为未开始 + } + boolean allFinished = true; + boolean hasInProgress = false; + for (PgsProgressCategory category : children) { + String status = category.getStatus(); + if (!PgsFinishStatusEnum.FINISH.getValue().equals(status)) { + allFinished = false; + if (PgsFinishStatusEnum.INPROGRESS.getValue().equals(status)) { + hasInProgress = true; + } + } + } + if (allFinished) { + return PgsFinishStatusEnum.FINISH.getValue(); // 全部完成 + } else if (hasInProgress) { + return PgsFinishStatusEnum.INPROGRESS.getValue(); // 有进行中 + } else { + return PgsFinishStatusEnum.UNFINISH.getValue(); // 全部未开始 + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressCategoryTemplateServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressCategoryTemplateServiceImpl.java new file mode 100644 index 0000000..3680ed4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressCategoryTemplateServiceImpl.java @@ -0,0 +1,247 @@ +package org.dromara.progress.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.progress.constant.PgsProgressCategoryConstant; +import org.dromara.progress.domain.PgsProgressCategoryTemplate; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq; +import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq; +import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo; +import org.dromara.progress.mapper.PgsProgressCategoryTemplateMapper; +import org.dromara.progress.service.IPgsProgressCategoryTemplateService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 进度类别模版Service业务层处理 + * + * @author lilemy + * @date 2025-05-22 + */ +@Service +public class PgsProgressCategoryTemplateServiceImpl extends ServiceImpl + implements IPgsProgressCategoryTemplateService { + + /** + * 查询进度类别模版 + * + * @param id 主键 + * @return 进度类别模版 + */ + @Override + public PgsProgressCategoryTemplateVo queryById(Long id) { + PgsProgressCategoryTemplate progressCategoryTemplate = this.getById(id); + if (progressCategoryTemplate == null) { + throw new ServiceException("进度类别模版信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(progressCategoryTemplate); + } + + /** + * 分页查询进度类别模版 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 进度类别模版分页列表 + */ + @Override + public TableDataInfo queryPageList(PgsProgressCategoryTemplateQueryReq req, PageQuery pageQuery) { + Page progressCategoryTemplatePage = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(progressCategoryTemplatePage)); + } + + /** + * 查询符合条件的进度类别模版列表 + * + * @param req 查询条件 + * @return 进度类别模版列表 + */ + @Override + public List queryList(PgsProgressCategoryTemplateQueryReq req) { + List list = this.list(this.buildQueryWrapper(req)); + return list.stream().map(this::getVo).toList(); + } + + /** + * 新增进度类别模版 + * + * @param req 进度类别模版 + * @return 新增进度类别模版id + */ + @Override + public Long insertByBo(PgsProgressCategoryTemplateCreateReq req) { + // 将实体类和 DTO 进行转换 + PgsProgressCategoryTemplate progressCategoryTemplate = new PgsProgressCategoryTemplate(); + BeanUtils.copyProperties(req, progressCategoryTemplate); + // 数据校验 + validEntityBeforeSave(progressCategoryTemplate); + // 写入数据库 + boolean result = this.save(progressCategoryTemplate); + if (!result) { + throw new ServiceException("新增进度类别模版失败,数据库异常", HttpStatus.ERROR); + } + return progressCategoryTemplate.getId(); + } + + /** + * 修改进度类别模版 + * + * @param req 进度类别模版 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(PgsProgressCategoryTemplateUpdateReq req) { + // 将实体类和 DTO 进行转换 + PgsProgressCategoryTemplate progressCategoryTemplate = new PgsProgressCategoryTemplate(); + BeanUtils.copyProperties(req, progressCategoryTemplate); + PgsProgressCategoryTemplate oldProgressCategoryTemplate = this.getById(req.getId()); + if (oldProgressCategoryTemplate == null) { + throw new ServiceException("修改进度类别模版失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 数据校验 + validEntityBeforeSave(progressCategoryTemplate); + // 写入数据库 + boolean result = this.updateById(progressCategoryTemplate); + if (!result) { + throw new ServiceException("更新进度类别模版失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(PgsProgressCategoryTemplate entity) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long pid = entity.getPid(); + if (projectId != null && projectId != 0) { + if (this.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + if (pid != null && pid != 0) { + if (this.getById(pid) == null) { + throw new ServiceException("对应进度类别模版不存在", HttpStatus.NOT_FOUND); + } + } + // 名称唯一性校验 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(PgsProgressCategoryTemplate::getName, entity.getName()); + if (projectId != null && projectId != 0) { + lqw.eq(PgsProgressCategoryTemplate::getProjectId, entity.getProjectId()); + } + if (pid != null && pid != 0) { + lqw.eq(PgsProgressCategoryTemplate::getPid, entity.getPid()); + } + if (entity.getId() != null) { + // 排除自身 + lqw.ne(PgsProgressCategoryTemplate::getId, entity.getId()); + } + if (this.count(lqw) > 0) { + throw new ServiceException("已有同名进度类别模版", HttpStatus.CONFLICT); + } + } + + /** + * 校验并批量删除进度类别模版信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + List categoryTemplateList = this.listByIds(ids); + if (isValid) { + categoryTemplateList.forEach(template->{ + Long projectId = template.getProjectId(); + if (projectId != null && projectId == 0) { + throw new ServiceException("通用模版,无法删除", HttpStatus.CONFLICT); + } + }); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取进度类别模版视图对象 + * + * @param progressCategoryTemplate 进度类别模版对象 + * @return 进度类别模版视图对象 + */ + @Override + public PgsProgressCategoryTemplateVo getVo(PgsProgressCategoryTemplate progressCategoryTemplate) { + if (progressCategoryTemplate == null) { + return null; + } + // 对象转封装类 + PgsProgressCategoryTemplateVo progressCategoryTemplateVo = new PgsProgressCategoryTemplateVo(); + BeanUtils.copyProperties(progressCategoryTemplate, progressCategoryTemplateVo); + return progressCategoryTemplateVo; + } + + /** + * 获取进度类别模版查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(PgsProgressCategoryTemplateQueryReq req) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + if (req == null) { + return lqw; + } + Long pid = req.getPid(); + String name = req.getName(); + String unitType = req.getUnitType(); + Long projectId = req.getProjectId(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(name), PgsProgressCategoryTemplate::getName, name); + // 精确查询 + lqw.in(ObjectUtils.isNotEmpty(projectId), PgsProgressCategoryTemplate::getProjectId, projectId, PgsProgressCategoryConstant.PUBLIC_PROJECT_ID); + lqw.eq(StringUtils.isNotBlank(unitType), PgsProgressCategoryTemplate::getUnitType, unitType); + lqw.eq(ObjectUtils.isNotEmpty(pid), PgsProgressCategoryTemplate::getPid, pid); + return lqw; + } + + /** + * 获取进度类别模版分页对象视图 + * + * @param progressCategoryTemplatePage 进度类别模版分页对象 + * @return 进度类别模版分页对象视图 + */ + @Override + public Page getVoPage(Page progressCategoryTemplatePage) { + List progressCategoryTemplateList = progressCategoryTemplatePage.getRecords(); + Page progressCategoryTemplateVoPage = new Page<>(progressCategoryTemplatePage.getCurrent(), progressCategoryTemplatePage.getSize(), progressCategoryTemplatePage.getTotal()); + if (CollUtil.isEmpty(progressCategoryTemplateList)) { + return progressCategoryTemplateVoPage; + } + // 对象列表 => 封装对象列表 + List progressCategoryTemplateVoList = progressCategoryTemplateList.stream().map(progressCategoryTemplate -> { + // 对象转封装类 + PgsProgressCategoryTemplateVo progressCategoryTemplateVo = new PgsProgressCategoryTemplateVo(); + BeanUtils.copyProperties(progressCategoryTemplate, progressCategoryTemplateVo); + return progressCategoryTemplateVo; + }).toList(); + progressCategoryTemplateVoPage.setRecords(progressCategoryTemplateVoList); + return progressCategoryTemplateVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanDetailServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanDetailServiceImpl.java new file mode 100644 index 0000000..37a0aeb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanDetailServiceImpl.java @@ -0,0 +1,581 @@ +package org.dromara.progress.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.facility.domain.FacBoxTransformer; +import org.dromara.facility.domain.FacInverter; +import org.dromara.facility.domain.FacPhotovoltaicPanel; +import org.dromara.facility.domain.enums.FacFinishStatusEnum; +import org.dromara.facility.domain.enums.FacFinishTypeEnum; +import org.dromara.facility.service.IFacBoxTransformerService; +import org.dromara.facility.service.IFacInverterService; +import org.dromara.facility.service.IFacPhotovoltaicPanelPartsService; +import org.dromara.facility.service.IFacPhotovoltaicPanelService; +import org.dromara.progress.constant.PgsProgressCategoryConstant; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.domain.PgsProgressPlan; +import org.dromara.progress.domain.PgsProgressPlanDetail; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailPercentageCreateReq; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq; +import org.dromara.progress.domain.enums.PgsFinishStatusEnum; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailUnFinishVo; +import org.dromara.progress.mapper.PgsProgressPlanDetailMapper; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.progress.service.IPgsProgressPlanDetailService; +import org.dromara.progress.service.IPgsProgressPlanService; +import org.dromara.common.utils.PageConvertUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 进度计划详情Service业务层处理 + * + * @author lilemy + * @date 2025-05-27 + */ +@Service +public class PgsProgressPlanDetailServiceImpl extends ServiceImpl + implements IPgsProgressPlanDetailService { + + @Lazy + @Resource + private IPgsProgressPlanService progressPlanService; + + @Resource + private IFacBoxTransformerService boxTransformerService; + + @Resource + private IFacInverterService inverterService; + + @Resource + private IFacPhotovoltaicPanelService photovoltaicPanelService; + + @Resource + private IPgsProgressCategoryService progressCategoryService; + + @Resource + private IFacPhotovoltaicPanelPartsService photovoltaicPanelPartsService; + + /** + * 插入进度计划详情设施 + * + * @param req 插入进度计划详情设施参数 + * @return 是否插入成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertFinishedDetail(PgsProgressPlanDetailFinishedCreateReq req) { + List finishedDetailIdList = req.getFinishedDetailIdList(); + if (CollUtil.isEmpty(finishedDetailIdList)) { + return true; + } + int size = finishedDetailIdList.size(); + Long id = req.getId(); + PgsProgressPlanDetail progressPlanDetail = this.getById(id); + if (progressPlanDetail == null) { + throw new ServiceException("进度计划详情信息不存在", HttpStatus.NOT_FOUND); + } + // todo 判断完成时间是否大于当前时间 + Date planDate = progressPlanDetail.getDate(); +/* if (planDate.after(new Date())) { + throw new ServiceException("完成时间不能大于当前时间", HttpStatus.BAD_REQUEST); + }*/ + Long projectId = progressPlanDetail.getProjectId(); + Long progressCategoryId = progressPlanDetail.getProgressCategoryId(); + PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId); + if (progressCategory == null) { + throw new ServiceException("进度计划类别信息不存在", HttpStatus.NOT_FOUND); + } + String workType = progressCategory.getWorkType(); + List finishedDetailList = JSONUtil.toList(progressPlanDetail.getFinishedDetail(), PgsProgressPlanDetailFinishedVo.class); + Set idSet = new HashSet<>(finishedDetailIdList); + List matchedNames = finishedDetailList.stream() + .filter(detail -> idSet.contains(detail.getId())) + .map(PgsProgressPlanDetailFinishedVo::getName) + .toList(); + if (CollUtil.isNotEmpty(matchedNames)) { + throw new ServiceException("设施:" + String.join(",", matchedNames) + "已完成,请勿重复提交", HttpStatus.BAD_REQUEST); + } + if (PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List finishedVoList = handleFacilityFinish( + projectId, + progressCategoryId, + finishedDetailIdList, + planDate, + photovoltaicPanelService, + FacPhotovoltaicPanel::getId, + FacPhotovoltaicPanel::getName, + FacPhotovoltaicPanel::getFinishType, + FacPhotovoltaicPanel::getFinishDate, + FacPhotovoltaicPanel::getProjectId, + FacPhotovoltaicPanel::getProgressCategoryId, + FacPhotovoltaicPanel::getId, + FacPhotovoltaicPanel::getStatus + ); + finishedDetailList.addAll(finishedVoList); + // 如果是桩点、支柱、立架,则同步更新 + if (PgsProgressCategoryConstant.RELEVANCE_PHOTOVOLTAIC_PANEL_WORK_TYPE.contains(workType)) { + Long matrixId = progressCategory.getMatrixId(); + List nameList = finishedDetailList.stream().map(PgsProgressPlanDetailFinishedVo::getName).toList(); + Boolean result = photovoltaicPanelPartsService.updatePartsFinishStatus( + workType, + planDate, + projectId, + matrixId, + nameList); + if (!result) { + throw new ServiceException("同步更新设施失败", HttpStatus.ERROR); + } + } + } else if (PgsProgressCategoryConstant.INVERTER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List finishedVoList = handleFacilityFinish( + projectId, + progressCategoryId, + finishedDetailIdList, + planDate, + inverterService, + FacInverter::getId, + FacInverter::getName, + FacInverter::getFinishType, + FacInverter::getFinishDate, + FacInverter::getProjectId, + FacInverter::getProgressCategoryId, + FacInverter::getId, + FacInverter::getStatus + ); + finishedDetailList.addAll(finishedVoList); + } else if (PgsProgressCategoryConstant.BOX_TRANSFORMER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List finishedVoList = handleFacilityFinish( + projectId, + progressCategoryId, + finishedDetailIdList, + planDate, + boxTransformerService, + FacBoxTransformer::getId, + FacBoxTransformer::getName, + FacBoxTransformer::getFinishType, + FacBoxTransformer::getFinishDate, + FacBoxTransformer::getProjectId, + FacBoxTransformer::getProgressCategoryId, + FacBoxTransformer::getId, + FacBoxTransformer::getStatus + ); + finishedDetailList.addAll(finishedVoList); + } + PgsProgressPlanDetail detail = new PgsProgressPlanDetail(); + detail.setId(id); + detail.setFinishedDetail(JSONUtil.toJsonStr(finishedDetailList)); + detail.setFinishedNumber(progressPlanDetail.getFinishedNumber() + size); + boolean update = this.updateById(detail); + if (!update) { + throw new ServiceException("更新进度计划详情异常", HttpStatus.ERROR); + } + boolean result = progressPlanService.lambdaUpdate() + .eq(PgsProgressPlan::getId, progressPlanDetail.getProgressPlanId()) + .setSql("finished_number = finished_number + " + size) + .update(); + if (!result) { + throw new ServiceException("更新进度计划异常", HttpStatus.ERROR); + } + BigDecimal completedTotal = progressCategory.getCompleted().add(new BigDecimal(size)); + progressCategory.setCompleted(completedTotal); + if (completedTotal.compareTo(progressCategory.getTotal()) == 0) { + progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue()); + } + boolean updateCategory = progressCategoryService.updateById(progressCategory); + if (!updateCategory) { + throw new ServiceException("更新进度计划类别异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 插入进度计划详情设施 + * + * @param req 插入进度计划详情设施参数 + * @return 是否插入成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertPercentageDetail(PgsProgressPlanDetailPercentageCreateReq req) { + // 校验 + Long finishedNumber = req.getFinishedNumber(); + if (finishedNumber == null) { + throw new ServiceException("完成百分比不能为空", HttpStatus.BAD_REQUEST); + } + if (finishedNumber < 0) { + throw new ServiceException("完成百分比不能小于0", HttpStatus.BAD_REQUEST); + } + if (finishedNumber > 100) { + throw new ServiceException("完成百分比不能大于100", HttpStatus.BAD_REQUEST); + } + Long id = req.getId(); + PgsProgressPlanDetail progressPlanDetail = this.getById(id); + if (progressPlanDetail == null) { + throw new ServiceException("进度计划详情信息不存在", HttpStatus.NOT_FOUND); + } + Long progressPlanId = progressPlanDetail.getProgressPlanId(); + PgsProgressPlan progressPlan = progressPlanService.getById(progressPlanId); + if (progressPlan == null) { + throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND); + } + Long progressCategoryId = progressPlanDetail.getProgressCategoryId(); + PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId); + if (progressCategory == null) { + throw new ServiceException("进度计划类别信息不存在", HttpStatus.NOT_FOUND); + } + Long number = progressPlanDetail.getFinishedNumber(); + Long finishedNumberTotal = progressPlan.getFinishedNumber(); + // todo 是否判断完成百分比是否大于计划进度 +/* if (finishedNumberTotal + finishedNumber > progressPlan.getPlanNumber()) { + throw new ServiceException("完成百分比不能大于计划进度", HttpStatus.BAD_REQUEST); + }*/ + progressPlanDetail.setFinishedNumber(finishedNumber); + // 更新 + boolean update = this.updateById(progressPlanDetail); + if (!update) { + throw new ServiceException("更新进度计划详情异常", HttpStatus.ERROR); + } + progressPlan.setFinishedNumber(finishedNumberTotal - number + finishedNumber); + boolean result = progressPlanService.updateById(progressPlan); + if (!result) { + throw new ServiceException("更新进度计划异常", HttpStatus.ERROR); + } + BigDecimal completed = progressCategory.getCompleted(); + BigDecimal completedTotal = completed.subtract(new BigDecimal(number)).add(new BigDecimal(finishedNumber)); + progressCategory.setCompleted(completedTotal); + if (completedTotal.compareTo(progressCategory.getTotal()) == 0) { + progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue()); + } + boolean updateCategory = progressCategoryService.updateById(progressCategory); + if (!updateCategory) { + throw new ServiceException("更新进度分类异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 分页查询进度计划详情设施列表 + * + * @param id 主键 + * @param pageQuery 分页参数 + * @return 进度计划详情设施分页列表 + */ + @Override + public TableDataInfo queryFinishedById(Long id, PageQuery pageQuery) { + PgsProgressPlanDetail progressPlanDetail = this.getById(id); + if (progressPlanDetail == null) { + throw new ServiceException("进度计划详情信息不存在", HttpStatus.NOT_FOUND); + } + String finishedDetail = progressPlanDetail.getFinishedDetail(); + List list = JSONUtil.toList(finishedDetail, PgsProgressPlanDetailFinishedVo.class); + return TableDataInfo.build(this.paginateList(list, pageQuery)); + } + + /** + * 分页查询进度计划详情未完成设施列表 + * + * @param id 主键 + * @param pageQuery 分页参数 + * @return 进度计划详情设施分页列表 + */ + @Override + public TableDataInfo queryUnFinishById(Long id, PageQuery pageQuery) { + PgsProgressPlanDetail progressPlanDetail = this.getById(id); + if (progressPlanDetail == null) { + throw new ServiceException("进度计划详情信息不存在", HttpStatus.NOT_FOUND); + } + Long progressCategoryId = progressPlanDetail.getProgressCategoryId(); + PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId); + if (progressCategory == null) { + throw new ServiceException("进度计划类别信息不存在", HttpStatus.NOT_FOUND); + } + String workType = progressCategory.getWorkType(); + if (PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.select(FacPhotovoltaicPanel::getId, FacPhotovoltaicPanel::getName, FacPhotovoltaicPanel::getStatus); + lqw.eq(FacPhotovoltaicPanel::getProjectId, progressPlanDetail.getProjectId()); + lqw.eq(FacPhotovoltaicPanel::getProgressCategoryId, progressCategoryId); + lqw.in(FacPhotovoltaicPanel::getStatus, FacFinishStatusEnum.UNFINISH.getValue(), FacFinishStatusEnum.INPROGRESS.getValue()); + Page page = photovoltaicPanelService.page(pageQuery.build(), lqw); + Page voPage = PageConvertUtil.convert(page, entity -> { + PgsProgressPlanDetailUnFinishVo vo = new PgsProgressPlanDetailUnFinishVo(); + vo.setId(entity.getId()); + vo.setName(entity.getName()); + vo.setStatus(entity.getStatus()); + return vo; + }); + return TableDataInfo.build(voPage); + } else if (PgsProgressCategoryConstant.INVERTER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.select(FacInverter::getId, FacInverter::getName, FacInverter::getStatus); + lqw.eq(FacInverter::getProjectId, progressPlanDetail.getProjectId()); + lqw.eq(FacInverter::getProgressCategoryId, progressCategoryId); + lqw.in(FacInverter::getStatus, FacFinishStatusEnum.UNFINISH.getValue(), FacFinishStatusEnum.INPROGRESS.getValue()); + Page page = inverterService.page(pageQuery.build(), lqw); + Page voPage = PageConvertUtil.convert(page, entity -> { + PgsProgressPlanDetailUnFinishVo vo = new PgsProgressPlanDetailUnFinishVo(); + vo.setId(entity.getId()); + vo.setName(entity.getName()); + vo.setStatus(entity.getStatus()); + return vo; + }); + return TableDataInfo.build(voPage); + } else if (PgsProgressCategoryConstant.BOX_TRANSFORMER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.select(FacBoxTransformer::getId, FacBoxTransformer::getName, FacBoxTransformer::getStatus); + lqw.eq(FacBoxTransformer::getProjectId, progressPlanDetail.getProjectId()); + lqw.eq(FacBoxTransformer::getProgressCategoryId, progressCategoryId); + lqw.in(FacBoxTransformer::getStatus, FacFinishStatusEnum.UNFINISH.getValue(), FacFinishStatusEnum.INPROGRESS.getValue()); + Page page = boxTransformerService.page(pageQuery.build(), lqw); + Page voPage = PageConvertUtil.convert(page, entity -> { + PgsProgressPlanDetailUnFinishVo vo = new PgsProgressPlanDetailUnFinishVo(); + vo.setId(entity.getId()); + vo.setName(entity.getName()); + vo.setStatus(entity.getStatus()); + return vo; + }); + return TableDataInfo.build(voPage); + } else { + throw new ServiceException("未定义的进度计划类别", HttpStatus.BAD_REQUEST); + } + } + + /** + * 获取进度计划详情视图对象列表 + * + * @param progressPlanDetailList 进度计划详情对象列表 + * @return 进度计划详情视图对象列表 + */ + @Override + public List getNumVoList(List progressPlanDetailList) { + return progressPlanDetailList.stream().map(progressPlanDetail -> { + PgsProgressPlanDetailNumVo progressPlanDetailNumVo = new PgsProgressPlanDetailNumVo(); + BeanUtils.copyProperties(progressPlanDetail, progressPlanDetailNumVo); + return progressPlanDetailNumVo; + }).toList(); + } + + /** + * 删除进度计划详情 + * + * @param req 删除进度计划详情参数 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean removeDetail(PgsProgressPlanDetailRemoveReq req) { + Long id = req.getId(); + List detailIdList = req.getDetailIdList(); + if (CollUtil.isEmpty(detailIdList)) { + return true; + } + PgsProgressPlanDetail progressPlanDetail = this.getById(id); + if (progressPlanDetail == null) { + throw new ServiceException("进度计划详情数据不存在", HttpStatus.NOT_FOUND); + } + String finishedDetail = progressPlanDetail.getFinishedDetail(); + int removeTotal = detailIdList.size(); + List finishedVoList = JSONUtil.toList(finishedDetail, PgsProgressPlanDetailFinishedVo.class); + PgsProgressCategory progressCategory = progressCategoryService.getById(progressPlanDetail.getProgressCategoryId()); + String workType = progressCategory.getWorkType(); + if (PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List list = photovoltaicPanelService.lambdaQuery() + .in(FacPhotovoltaicPanel::getId, detailIdList) + .list(); + if (CollUtil.isEmpty(list) || list.size() != removeTotal) { + throw new ServiceException("设施数据丢失", HttpStatus.NOT_FOUND); + } + LambdaUpdateWrapper lqw = new LambdaUpdateWrapper<>(); + lqw.in(FacPhotovoltaicPanel::getId, detailIdList); + lqw.set(FacPhotovoltaicPanel::getStatus, FacFinishStatusEnum.UNFINISH.getValue()); + lqw.set(FacPhotovoltaicPanel::getFinishType, null); + lqw.set(FacPhotovoltaicPanel::getFinishDate, null); + boolean update = photovoltaicPanelService.update(lqw); + if (!update) { + throw new ServiceException("修改设施数据失败,数据库异常", HttpStatus.ERROR); + } + } else if (PgsProgressCategoryConstant.INVERTER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List list = inverterService.lambdaQuery() + .in(FacInverter::getId, detailIdList) + .list(); + if (CollUtil.isEmpty(list) || list.size() != removeTotal) { + throw new ServiceException("设施数据丢失", HttpStatus.NOT_FOUND); + } + LambdaUpdateWrapper lqw = new LambdaUpdateWrapper<>(); + lqw.in(FacInverter::getId, detailIdList); + lqw.set(FacInverter::getStatus, FacFinishStatusEnum.UNFINISH.getValue()); + lqw.set(FacInverter::getFinishType, null); + lqw.set(FacInverter::getFinishDate, null); + boolean update = inverterService.update(lqw); + if (!update) { + throw new ServiceException("修改设施数据失败,数据库异常", HttpStatus.ERROR); + } + } else if (PgsProgressCategoryConstant.BOX_TRANSFORMER_PROGRESS_CATEGORY_WORK_TYPE.contains(workType)) { + List list = boxTransformerService.lambdaQuery() + .in(FacBoxTransformer::getId, detailIdList) + .list(); + if (CollUtil.isEmpty(list) || list.size() != removeTotal) { + throw new ServiceException("设施数据丢失", HttpStatus.NOT_FOUND); + } + LambdaUpdateWrapper lqw = new LambdaUpdateWrapper<>(); + lqw.in(FacBoxTransformer::getId, detailIdList); + lqw.set(FacBoxTransformer::getStatus, FacFinishStatusEnum.UNFINISH.getValue()); + lqw.set(FacBoxTransformer::getFinishType, null); + lqw.set(FacBoxTransformer::getFinishDate, null); + boolean update = boxTransformerService.update(lqw); + if (!update) { + throw new ServiceException("修改设施数据失败,数据库异常", HttpStatus.ERROR); + } + } else { + throw new ServiceException("未定义的进度计划类别", HttpStatus.BAD_REQUEST); + } + AtomicInteger finishType2Count = new AtomicInteger(0); + // 过滤出不需要删除的,生成新列表 + List newList = finishedVoList.stream() + .filter(vo -> { + boolean toRemove = detailIdList.contains(vo.getId()); + if (toRemove && FacFinishTypeEnum.AI.getValue().equals(vo.getFinishType())) { + finishType2Count.incrementAndGet(); + } + return !toRemove; + }) + .toList(); + progressPlanDetail.setFinishedDetail(JSONUtil.toJsonStr(newList)); + progressPlanDetail.setFinishedNumber((long) newList.size()); + long aiFill = progressPlanDetail.getAiFill() - (long) finishType2Count.get(); + progressPlanDetail.setAiFill(Math.max(aiFill, 0L)); + boolean updatePlanDetail = this.updateById(progressPlanDetail); + if (!updatePlanDetail) { + throw new ServiceException("修改进度计划详情失败,数据库异常", HttpStatus.ERROR); + } + boolean updatePlan = progressPlanService.lambdaUpdate() + .eq(PgsProgressPlan::getId, progressPlanDetail.getProgressPlanId()) + .setSql("finished_number = finished_number - " + removeTotal) + .update(); + if (!updatePlan) { + throw new ServiceException("修改进度计划失败,数据库异常", HttpStatus.ERROR); + } + if (removeTotal > 0 && progressCategory.getTotal().compareTo(progressCategory.getCompleted()) == 0) { + progressCategory.setStatus(PgsFinishStatusEnum.INPROGRESS.getValue()); + } + progressCategory.setCompleted(progressCategory.getCompleted().subtract(BigDecimal.valueOf(removeTotal))); + boolean updateCategory = progressCategoryService.updateById(progressCategory); + if (!updateCategory) { + throw new ServiceException("修改进度类别失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 分页 + * + * @param fullList 列表 + * @param pageQuery 分页参数 + * @return 分页列表 + */ + public Page paginateList(List fullList, PageQuery pageQuery) { + int pageNum = ObjectUtil.defaultIfNull(pageQuery.getPageNum(), PageQuery.DEFAULT_PAGE_NUM); + int pageSize = ObjectUtil.defaultIfNull(pageQuery.getPageSize(), PageQuery.DEFAULT_PAGE_SIZE); + // 保底 + if (pageNum < 1) { + pageNum = 1; + } + if (pageSize < 1) { + pageSize = PageQuery.DEFAULT_PAGE_SIZE; + } + int fromIndex = (pageNum - 1) * pageSize; + int toIndex = Math.min(fromIndex + pageSize, fullList.size()); + // 防止越界 + if (fromIndex > fullList.size()) { + return new Page(pageNum, pageSize, fullList.size()).setRecords(Collections.emptyList()); + } + List pageList = fullList.subList(fromIndex, toIndex); + return new Page(pageNum, pageSize, fullList.size()).setRecords(pageList); + } + + /** + * 获取设施封装 + * + * @param projectId 项目ID + * @param progressCategoryId 进度类别ID + * @param finishedDetailIdList 设施完成ID列表 + * @param finishDate 设施完成时间 + * @param service 服务 + * @param getIdFunc 获取ID方法 + * @param getNameFunc 获取名称方法 + * @param getFinishTypeFunc 获取完成类型方法 + * @param getFinishDateFunc 获取完成时间方法 + * @param getProjectIdFunc 获取项目ID方法 + * @param getProgressCategoryIdFunc 获取进度类别ID方法 + * @param getIdColumnFunc 获取ID列方法 + * @param getStatusFunc 获取状态方法 + * @param 设施类型 + */ + public List handleFacilityFinish( + Long projectId, + Long progressCategoryId, + List finishedDetailIdList, + Date finishDate, + IService service, + SFunction getIdFunc, + SFunction getNameFunc, + SFunction getFinishTypeFunc, + SFunction getFinishDateFunc, + SFunction getProjectIdFunc, + SFunction getProgressCategoryIdFunc, + SFunction getIdColumnFunc, + SFunction getStatusFunc + ) { + List entityList = service.lambdaQuery() + .eq(getProjectIdFunc, projectId) + .eq(getProgressCategoryIdFunc, progressCategoryId) + .in(getIdColumnFunc, finishedDetailIdList) + .list(); + if (entityList.size() != finishedDetailIdList.size()) { + throw new ServiceException("上传设施信息异常", HttpStatus.BAD_REQUEST); + } + boolean update = service.lambdaUpdate() + .eq(getProjectIdFunc, projectId) + .eq(getProgressCategoryIdFunc, progressCategoryId) + .in(getIdColumnFunc, finishedDetailIdList) + .set(getStatusFunc, FacFinishStatusEnum.FINISH.getValue()) + .set(getFinishTypeFunc, FacFinishTypeEnum.HAND.getValue()) + .set(getFinishDateFunc, finishDate) + .update(); + if (!update) { + throw new ServiceException("更新设施信息异常", HttpStatus.ERROR); + } + return entityList.stream().map(entity -> { + PgsProgressPlanDetailFinishedVo vo = new PgsProgressPlanDetailFinishedVo(); + vo.setId(getIdFunc.apply(entity)); + vo.setName(getNameFunc.apply(entity)); + vo.setFinishType(FacFinishTypeEnum.HAND.getValue()); + return vo; + }).toList(); + } + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanServiceImpl.java new file mode 100644 index 0000000..a329be8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/progress/service/impl/PgsProgressPlanServiceImpl.java @@ -0,0 +1,390 @@ +package org.dromara.progress.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.progress.domain.PgsProgressCategory; +import org.dromara.progress.domain.PgsProgressPlan; +import org.dromara.progress.domain.PgsProgressPlanDetail; +import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanCreateReq; +import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanQueryReq; +import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateDto; +import org.dromara.progress.domain.enums.PgsDelayStatusEnum; +import org.dromara.progress.domain.enums.PgsFinishStatusEnum; +import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo; +import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo; +import org.dromara.progress.mapper.PgsProgressPlanMapper; +import org.dromara.progress.service.IPgsProgressCategoryService; +import org.dromara.progress.service.IPgsProgressPlanDetailService; +import org.dromara.progress.service.IPgsProgressPlanService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 进度计划Service业务层处理 + * + * @author lilemy + * @date 2025-05-27 + */ +@Slf4j +@Service +public class PgsProgressPlanServiceImpl extends ServiceImpl + implements IPgsProgressPlanService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IPgsProgressPlanDetailService progressPlanDetailService; + + @Resource + private IPgsProgressCategoryService progressCategoryService; + + @Resource + private IFacMatrixService matrixService; + + /** + * 查询进度计划 + * + * @param id 主键 + * @return 进度计划 + */ + @Override + public PgsProgressPlanVo queryById(Long id) { + PgsProgressPlan progressPlan = this.getById(id); + if (progressPlan == null) { + throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(progressPlan); + } + + /** + * 分页查询进度计划列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 进度计划分页列表 + */ + @Override + public TableDataInfo queryPageList(PgsProgressPlanQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的进度计划列表 + * + * @param req 查询条件 + * @return 进度计划列表 + */ + @Override + public List queryList(PgsProgressPlanQueryReq req) { + List list = this.list(this.buildQueryWrapper(req)); + return list.stream().map(this::getVo).toList(); + } + + /** + * 新增进度计划 + * + * @param req 进度计划 + * @return 新增进度计划主键 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(PgsProgressPlanCreateReq req) { + // 将实体类和 DTO 进行转换 + PgsProgressPlan progressPlan = new PgsProgressPlan(); + BeanUtils.copyProperties(req, progressPlan); + // 数据校验 + Date startDate = req.getStartDate(); + Date endDate = req.getEndDate(); + // 结束日期不能早于开始日期 + if (endDate.before(startDate)) { + throw new ServiceException("结束日期不能早于开始日期"); + } + Long projectId = progressPlan.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + Long matrixId = progressPlan.getMatrixId(); + FacMatrix matrix = matrixService.getById(matrixId); + if (matrix == null) { + throw new ServiceException("对应方阵不存在", HttpStatus.NOT_FOUND); + } + Long progressCategoryId = progressPlan.getProgressCategoryId(); + // 校验日期是否合法 + PgsProgressPlan lastProgressPlan = this.lambdaQuery() + .eq(PgsProgressPlan::getProgressCategoryId, progressCategoryId) + .orderByDesc(PgsProgressPlan::getEndDate) + .last("limit 1") + .one(); + if (lastProgressPlan != null && startDate.before(lastProgressPlan.getEndDate())) { + throw new ServiceException("开始日期不能早于上一条进度计划结束日期", HttpStatus.BAD_REQUEST); + } + PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId); + this.validPlanNumber(req.getPlanNumber(), progressCategory); + progressPlan.setProgressCategoryName(progressCategory.getName()); + progressPlan.setMatrixName(matrix.getMatrixName()); + // 操作数据库 + boolean save = this.save(progressPlan); + if (!save) { + throw new ServiceException("新增进度计划失败,数据库异常", HttpStatus.ERROR); + } + // 更新进度计划详情 + Long id = progressPlan.getId(); + List detailList = req.getDetailList(); + if (CollUtil.isNotEmpty(detailList)) { + List newDetailList = detailList.stream().map(detail -> { + PgsProgressPlanDetail progressPlanDetail = new PgsProgressPlanDetail(); + BeanUtils.copyProperties(detail, progressPlanDetail); + progressPlanDetail.setProgressPlanId(id); + progressPlanDetail.setProjectId(progressPlan.getProjectId()); + progressPlanDetail.setProgressCategoryId(progressPlan.getProgressCategoryId()); + return progressPlanDetail; + }).toList(); + boolean result = progressPlanDetailService.saveBatch(newDetailList); + if (!result) { + throw new ServiceException("新增进度计划详情失败,数据库操作失败", HttpStatus.ERROR); + } + } + // 更新进度分类计划总数量 + boolean update = progressCategoryService.lambdaUpdate() + .eq(PgsProgressCategory::getId, progressCategoryId) + .set(PgsProgressCategory::getPlanTotal, progressPlan.getPlanNumber()) + .set(PgsProgressCategory::getStatus, PgsFinishStatusEnum.INPROGRESS.getValue()) + .set(PgsProgressCategory::getIsDelay, PgsDelayStatusEnum.UNDELAY.getValue()) + .update(); + if (!update) { + throw new ServiceException("更新进度分类计划总数量失败,数据库操作失败", HttpStatus.ERROR); + } + return id; + } + + /** + * 删除进度计划信息 + * + * @param id 待删除的主键 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteById(Long id) { + Long userId = LoginHelper.getUserId(); + PgsProgressPlan progressPlan = this.getById(id); + if (progressPlan == null) { + throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND); + } + Long projectId = progressPlan.getProjectId(); + projectService.validAuth(projectId, userId); + if (progressPlan.getPlanNumber() != null && progressPlan.getPlanNumber() != 0) { + throw new ServiceException("已存在完成的设施,无法删除", HttpStatus.CONFLICT); + } + // 删除数据 + boolean result = this.removeById(id); + if (!result) { + throw new ServiceException("删除进度计划失败,数据库异常", HttpStatus.ERROR); + } + // 关联删除分类中记录的计划值 + boolean update = progressCategoryService.lambdaUpdate() + .eq(PgsProgressCategory::getId, progressPlan.getProgressCategoryId()) + .setSql("plan_total = plan_total - " + progressPlan.getPlanNumber()) + .update(); + if (!update) { + throw new ServiceException("更新进度分类计划总数量失败,数据库操作失败", HttpStatus.ERROR); + } + // 关联删除计划详情数据 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(PgsProgressPlanDetail::getProgressPlanId, id); + boolean remove = progressPlanDetailService.remove(lqw); + if (!remove) { + throw new ServiceException("删除进度计划详情失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 获取进度计划视图对象 + * + * @param progressPlan 进度计划对象 + * @return 进度计划视图对象 + */ + @Override + public PgsProgressPlanVo getVo(PgsProgressPlan progressPlan) { + // 对象转封装类 + PgsProgressPlanVo progressPlanVo = new PgsProgressPlanVo(); + if (progressPlan == null) { + return progressPlanVo; + } + BeanUtils.copyProperties(progressPlan, progressPlanVo); + // 获取详情列表 + Long id = progressPlan.getId(); + List detailList = progressPlanDetailService.lambdaQuery() + .eq(PgsProgressPlanDetail::getProgressPlanId, id) + .eq(PgsProgressPlanDetail::getProjectId, progressPlan.getProjectId()) + .list(); + progressPlanVo.setDetailList(progressPlanDetailService.getNumVoList(detailList)); + return progressPlanVo; + } + + /** + * 获取进度计划查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(PgsProgressPlanQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long matrixId = req.getMatrixId(); + Long progressCategoryId = req.getProgressCategoryId(); + Date startDate = req.getStartDate(); + Date endDate = req.getEndDate(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), PgsProgressPlan::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(matrixId), PgsProgressPlan::getMatrixId, matrixId); + lqw.eq(ObjectUtils.isNotEmpty(progressCategoryId), PgsProgressPlan::getProgressCategoryId, progressCategoryId); + // 日期条件:大于startDate,小于endDate + lqw.gt(ObjectUtils.isNotEmpty(startDate), PgsProgressPlan::getStartDate, startDate); + lqw.lt(ObjectUtils.isNotEmpty(endDate), PgsProgressPlan::getEndDate, endDate); + return lqw; + } + + /** + * 获取进度计划分页对象视图 + * + * @param progressPlanPage 进度计划分页对象 + * @return 进度计划分页对象视图 + */ + @Override + public Page getVoPage(Page progressPlanPage) { + List progressPlanList = progressPlanPage.getRecords(); + Page progressPlanVoPage = new Page<>( + progressPlanPage.getCurrent(), + progressPlanPage.getSize(), + progressPlanPage.getTotal()); + if (CollUtil.isEmpty(progressPlanList)) { + return progressPlanVoPage; + } + // 获取详情列表 + List idList = progressPlanList.stream().map(PgsProgressPlan::getId).toList(); + List detailList = progressPlanDetailService.lambdaQuery() + .in(PgsProgressPlanDetail::getProgressPlanId, idList).list(); + Map> detailMap = detailList + .stream().collect(Collectors.groupingBy(PgsProgressPlanDetail::getProgressPlanId)); + // 对象列表 => 封装对象列表 + List progressPlanVoList = progressPlanList.stream().map(progressPlan -> { + // 对象转封装类 + PgsProgressPlanVo progressPlanVo = new PgsProgressPlanVo(); + BeanUtils.copyProperties(progressPlan, progressPlanVo); + // 获取详情列表 + Long id = progressPlan.getId(); + List numDetailList = new ArrayList<>(); + long aiFill = 0L; + if (detailMap.containsKey(id)) { + numDetailList = progressPlanDetailService.getNumVoList(detailMap.get(id)); + for (PgsProgressPlanDetailNumVo vo : numDetailList) { + aiFill += vo.getAiFill() != null ? vo.getAiFill() : 0L; + } + } + progressPlanVo.setDetailList(numDetailList); + progressPlanVo.setAiFill(aiFill); + return progressPlanVo; + }).toList(); + progressPlanVoPage.setRecords(progressPlanVoList); + return progressPlanVoPage; + } + + /** + * 校验计划数量是否合法 + * + * @param planNumber 计划数量 + * @param progressCategory 进度类别 + */ + @Override + public void validPlanNumber(Long planNumber, PgsProgressCategory progressCategory) { + if (progressCategory == null) { + throw new ServiceException("进度类别不存在", HttpStatus.NOT_FOUND); + } + BigDecimal total = progressCategory.getTotal(); + BigDecimal completed = progressCategory.getCompleted(); + BigDecimal planTotal = total.subtract(completed); + if (planNumber.compareTo(planTotal.longValue()) > 0) { + throw new ServiceException("计划数量不能大于剩余数量", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验计划是否延迟 + * + * @return 是否延迟 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean validProgressPlanIsDelay() { + // 查找延期的施工进度 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.lt(PgsProgressPlan::getEndDate, LocalDate.now()); + lqw.apply("finished_number < plan_number "); + lqw.eq(PgsProgressPlan::getDelayNumber, 0); + List delayPlanList = this.list(lqw); + if (CollUtil.isEmpty(delayPlanList)) { + log.info("无新增延期的施工进度"); + return true; + } + Map> delayPlanMap = delayPlanList + .stream().collect(Collectors.groupingBy(PgsProgressPlan::getProgressCategoryId)); + log.warn("延期的施工进度:{}", delayPlanList); + List progressPlanList = new ArrayList<>(); + List categoryIdList = new ArrayList<>(); + for (Map.Entry> entry : delayPlanMap.entrySet()) { + Long key = entry.getKey(); + categoryIdList.add(key); + List value = entry.getValue(); + // 遍历施工进度,更新延期数量 + List delayList = value.stream().map(progressPlan -> { + PgsProgressPlan newProgressPlan = new PgsProgressPlan(); + newProgressPlan.setId(progressPlan.getId()); + newProgressPlan.setDelayNumber(progressPlan.getPlanNumber() - progressPlan.getFinishedNumber()); + return newProgressPlan; + }).toList(); + progressPlanList.addAll(delayList); + } + // 批量更新 + boolean result = this.updateBatchById(progressPlanList); + if (!result) { + throw new ServiceException("更新施工进度失败", HttpStatus.ERROR); + } + boolean update = progressCategoryService.lambdaUpdate() + .in(PgsProgressCategory::getId, categoryIdList) + .set(PgsProgressCategory::getIsDelay, PgsDelayStatusEnum.DELAY.getValue()) + .update(); + if (!update) { + throw new ServiceException("更新进度类别异常", HttpStatus.ERROR); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/constant/BusProjectConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/constant/BusProjectConstant.java new file mode 100644 index 0000000..fc68e28 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/constant/BusProjectConstant.java @@ -0,0 +1,29 @@ +package org.dromara.project.constant; + +/** + * @author lilemy + * @date 2025/5/13 10:33 + */ +public interface BusProjectConstant { + + /** + * 项目天气封装信息缓存的 Redis Key 前缀 + */ + String PROJECT_WEATHER_LIST_VO_REDIS_KEY_PREFIX = "project:weather:list"; + + /** + * 项目安全生产天数缓存的 Redis Key 前缀 + */ + String PROJECT_SAFETY_DAYS_REDIS_KEY_PREFIX = "project:safetyDays"; + + /** + * 项目缓存的 Redis Key 前缀 + */ + String PROJECT_CACHE_REDIS_KEY_PREFIX = "project"; + + /** + * 父级id + */ + Long PARENT_ID = 0L; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java new file mode 100644 index 0000000..d1216df --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusAttendanceController.java @@ -0,0 +1,90 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.attendance.BusAttendanceMonthByUserIdReq; +import org.dromara.project.domain.dto.attendance.BusAttendanceQueryReq; +import org.dromara.project.domain.dto.attendance.BusAttendanceQueryTwoWeekReq; +import org.dromara.project.domain.vo.attendance.BusAttendanceClockDateForTwoWeekVo; +import org.dromara.project.domain.vo.attendance.BusAttendanceMonthByUserIdVo; +import org.dromara.project.domain.vo.attendance.BusAttendanceVo; +import org.dromara.project.service.IBusAttendanceService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 考勤 + * + * @author lilemy + * @date 2025-04-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/attendance") +public class BusAttendanceController extends BaseController { + + private final IBusAttendanceService busAttendanceService; + + /** + * 查询考勤列表 + */ + @SaCheckPermission("project:attendance:list") + @GetMapping("/list") + public TableDataInfo list(BusAttendanceQueryReq req, PageQuery pageQuery) { + return busAttendanceService.queryPageList(req, pageQuery); + } + + /** + * 查询近两周考勤列表 + */ + @SaCheckPermission("project:attendance:list") + @GetMapping("/list/clockDate/twoWeek") + public R> listClockDateForTwoWeek(BusAttendanceQueryTwoWeekReq req) { + return R.ok(busAttendanceService.listClockDateForTwoWeek(req)); + } + + /** + * 查询施工人员月份考勤列表 + */ + @SaCheckPermission("project:attendance:list") + @GetMapping("/list/month/byUserId") + public R> listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req) { + return R.ok(busAttendanceService.listAttendanceMonthListByUserId(req)); + } + + /** + * 导出考勤列表 + */ + @SaCheckPermission("project:attendance:export") + @Log(title = "考勤", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusAttendanceQueryReq req, HttpServletResponse response) { + List list = busAttendanceService.queryList(req); + ExcelUtil.exportExcel(list, "考勤", BusAttendanceVo.class, response); + } + + /** + * 获取考勤详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:attendance:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busAttendanceService.queryById(id)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionBlacklistController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionBlacklistController.java new file mode 100644 index 0000000..2113143 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionBlacklistController.java @@ -0,0 +1,95 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.constructionblacklist.BusConstructionBlacklistCreateReq; +import org.dromara.project.domain.dto.constructionblacklist.BusConstructionBlacklistQueryReq; +import org.dromara.project.domain.vo.constructionblacklist.BusConstructionBlacklistVo; +import org.dromara.project.service.IBusConstructionBlacklistService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 黑名单 + * + * @author lilemy + * @date 2025-03-27 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/constructionBlacklist") +public class BusConstructionBlacklistController extends BaseController { + + private final IBusConstructionBlacklistService busConstructionBlacklistService; + + /** + * 查询黑名单列表 + */ + @SaCheckPermission("project:constructionBlacklist:list") + @GetMapping("/list") + public TableDataInfo list(BusConstructionBlacklistQueryReq req, PageQuery pageQuery) { + return busConstructionBlacklistService.queryPageList(req, pageQuery); + } + + /** + * 导出黑名单列表 + */ + @SaCheckPermission("project:constructionBlacklist:export") + @Log(title = "黑名单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusConstructionBlacklistQueryReq req, HttpServletResponse response) { + List list = busConstructionBlacklistService.queryList(req); + ExcelUtil.exportExcel(list, "黑名单", BusConstructionBlacklistVo.class, response); + } + + /** + * 获取黑名单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:constructionBlacklist:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busConstructionBlacklistService.queryById(id)); + } + + /** + * 新增黑名单 + */ + @SaCheckPermission("project:constructionBlacklist:add") + @Log(title = "黑名单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusConstructionBlacklistCreateReq req) { + return R.ok(busConstructionBlacklistService.insertByBo(req)); + } + + /** + * 删除黑名单 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:constructionBlacklist:remove") + @Log(title = "黑名单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busConstructionBlacklistService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionUserExitController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionUserExitController.java new file mode 100644 index 0000000..bdacbb1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionUserExitController.java @@ -0,0 +1,67 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.constructionuserexit.BusConstructionUserExitQueryReq; +import org.dromara.project.domain.vo.constructionuserexit.BusConstructionUserExitVo; +import org.dromara.project.service.IBusConstructionUserExitService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 施工人员入场退场记录信息 + * + * @author lilemy + * @date 2025-03-31 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/constructionUserExit") +public class BusConstructionUserExitController extends BaseController { + + private final IBusConstructionUserExitService busConstructionUserExitService; + + /** + * 查询施工人员入场退场记录信息列表 + */ + @SaCheckPermission("project:constructionUserExit:list") + @GetMapping("/list") + public TableDataInfo list(BusConstructionUserExitQueryReq req, PageQuery pageQuery) { + return busConstructionUserExitService.queryPageList(req, pageQuery); + } + + /** + * 导出施工人员入场退场记录信息列表 + */ + @SaCheckPermission("project:constructionUserExit:export") + @Log(title = "施工人员入场退场记录信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusConstructionUserExitQueryReq req, HttpServletResponse response) { + List list = busConstructionUserExitService.queryList(req); + ExcelUtil.exportExcel(list, "施工人员入场退场记录信息", BusConstructionUserExitVo.class, response); + } + + /** + * 获取施工人员入场退场记录信息详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:constructionUserExit:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busConstructionUserExitService.queryById(id)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusLeaveController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusLeaveController.java new file mode 100644 index 0000000..2db6f6e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusLeaveController.java @@ -0,0 +1,94 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.leave.BusLeaveManagerReviewReq; +import org.dromara.project.domain.dto.leave.BusLeaveQueryReq; +import org.dromara.project.domain.vo.leave.BusLeaveVo; +import org.dromara.project.service.IBusLeaveService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 施工人员请假申请 + * + * @author lilemy + * @date 2025-04-08 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/leave") +public class BusLeaveController extends BaseController { + + private final IBusLeaveService busLeaveService; + + /** + * 查询施工人员请假申请列表 + */ + @SaCheckPermission("project:leave:list") + @GetMapping("/list") + public TableDataInfo list(BusLeaveQueryReq req, PageQuery pageQuery) { + return busLeaveService.queryPageList(req, pageQuery); + } + + /** + * 导出施工人员请假申请列表 + */ + @SaCheckPermission("project:leave:export") + @Log(title = "施工人员请假申请", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusLeaveQueryReq req, HttpServletResponse response) { + List list = busLeaveService.queryList(req); + ExcelUtil.exportExcel(list, "施工人员请假申请", BusLeaveVo.class, response); + } + + /** + * 获取施工人员请假申请详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:leave:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busLeaveService.queryById(id)); + } + + /** + * 管理员审核施工人员请假申请 + */ + @SaCheckPermission("project:leave:edit") + @Log(title = "施工人员请假申请", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/review/manager") + public R managerReview(@Validated @RequestBody BusLeaveManagerReviewReq req) { + return toAjax(busLeaveService.managerReview(req)); + } + + /** + * 删除施工人员请假申请 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:leave:remove") + @Log(title = "施工人员请假申请", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busLeaveService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectController.java new file mode 100644 index 0000000..bc3879a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectController.java @@ -0,0 +1,185 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.project.BusProjectCreateReq; +import org.dromara.project.domain.dto.project.BusProjectCreateSubReq; +import org.dromara.project.domain.dto.project.BusProjectQueryReq; +import org.dromara.project.domain.dto.project.BusProjectUpdateReq; +import org.dromara.project.domain.vo.project.*; +import org.dromara.project.service.IBusProjectService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 项目 + * + * @author lilemy + * @date 2025-03-04 + */ +@Validated +@RestController +@RequestMapping("/project/project") +public class BusProjectController extends BaseController { + + @Resource + private IBusProjectService projectService; + + /** + * 查询项目列表 + */ + @SaCheckPermission("project:project:list") + @GetMapping("/list") + public TableDataInfo list(BusProjectQueryReq req, PageQuery pageQuery) { + return projectService.queryPageList(req, pageQuery); + } + + /** + * 查询项目列表 + */ + @SaCheckPermission("project:project:listNoDept") + @GetMapping("/listNoDept") + public R> listNoDept() { + return R.ok(projectService.queryListNoDept()); + } + + /** + * 查询项目下的子项目列表 + */ + @SaCheckPermission("project:project:list") + @GetMapping("/list/sub/{id}") + public R> listSubProject(@NotNull(message = "项目id不能为空") + @PathVariable Long id) { + return R.ok(projectService.querySubList(id)); + } + + /** + * 查询项目下的子项目方阵列表 + */ + @SaCheckPermission("project:project:list") + @GetMapping("/list/sub/matrix/{id}") + public R> listSubProjectMatrix(@NotNull(message = "项目id不能为空") + @PathVariable Long id) { + return R.ok(projectService.querySubProjectMatrixList(id)); + } + + /** + * 导出项目列表 + */ + @SaCheckPermission("project:project:export") + @Log(title = "项目", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusProjectQueryReq req, HttpServletResponse response) { + List list = projectService.queryList(req); + ExcelUtil.exportExcel(list, "项目", BusProjectVo.class, response); + } + + /** + * 获取项目详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:project:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(projectService.queryById(id)); + } + + /** + * 查询项目以及项目下的分包公司列表 + */ + @SaCheckPermission("project:project:query") + @GetMapping("/list/project/contractorList") + public R> listProjectContractorList() { + return R.ok(projectService.queryProjectContractorList()); + } + + /** + * 新增项目 + */ + @SaCheckPermission("project:project:add") + @Log(title = "项目", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusProjectCreateReq req) { + if (req == null) { + throw new ServiceException("参数不能为空", HttpStatus.BAD_REQUEST); + } + return R.ok(projectService.insertByBo(req)); + } + + /** + * 新增子项目 + */ + @SaCheckPermission("project:project:add") + @Log(title = "项目", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/sub") + public R addSub(@Validated(AddGroup.class) @RequestBody BusProjectCreateSubReq req) { + if (req == null) { + throw new ServiceException("参数不能为空", HttpStatus.BAD_REQUEST); + } + return R.ok(projectService.insertSubByProject(req)); + } + + /** + * 修改项目 + */ + @SaCheckPermission("project:project:edit") + @Log(title = "项目", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusProjectUpdateReq req) { + return toAjax(projectService.updateByBo(req)); + } + + /** + * 删除项目 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:project:remove") + @Log(title = "项目", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(projectService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 查询项目天气 + */ + @GetMapping("/weather/{id}") + public R> getWeather(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(projectService.getWeather(id)); + } + + /** + * 查询项目安全天数 + */ + @GetMapping("/safetyDay/{id}") + public R getSafetyDay(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(projectService.getSafetyDay(id)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectFileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectFileController.java new file mode 100644 index 0000000..05d297a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectFileController.java @@ -0,0 +1,107 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.json.JSONObject; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.projectfile.BusProjectFileQueryReq; +import org.dromara.project.domain.dto.projectfile.BusProjectFileUpdateReq; +import org.dromara.project.domain.dto.projectfile.BusProjectFileUploadDxfReq; +import org.dromara.project.domain.vo.projectfile.BusProjectFileVo; +import org.dromara.project.service.IBusProjectFileService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 项目文件存储 + * + * @author lilemy + * @date 2025-04-23 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/projectFile") +public class BusProjectFileController extends BaseController { + + private final IBusProjectFileService busProjectFileService; + + /** + * 查询项目文件存储列表 + */ + @SaCheckPermission("project:projectFile:list") + @GetMapping("/list") + public TableDataInfo list(BusProjectFileQueryReq req, PageQuery pageQuery) { + return busProjectFileService.queryPageList(req, pageQuery); + } + + /** + * 获取项目文件存储详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:projectFile:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busProjectFileService.queryById(id)); + } + + /** + * 修改项目文件存储 + */ + @SaCheckPermission("project:projectFile:edit") + @Log(title = "项目文件存储", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusProjectFileUpdateReq req) { + return toAjax(busProjectFileService.updateByBo(req)); + } + + /** + * 删除项目文件存储 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:projectFile:remove") + @Log(title = "项目文件存储", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busProjectFileService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 上传 dxf 文件并解析为 json + */ + @SaCheckPermission("project:projectFile:add") + @Log(title = "项目文件存储", businessType = BusinessType.IMPORT) + @PostMapping("/upload/dxf") + public R uploadDxf2Json(@RequestParam("file") MultipartFile file, BusProjectFileUploadDxfReq req) { + return toAjax(busProjectFileService.uploadDxf2Json(file, req)); + } + + /** + * 获取JSON文件详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:projectFile:query") + @GetMapping("/json/{id}") + public R getJSONFile(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busProjectFileService.getJSONFile(id)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectNewsController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectNewsController.java new file mode 100644 index 0000000..5868485 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectNewsController.java @@ -0,0 +1,118 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsCreateReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsGisReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsQueryReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsUpdateReq; +import org.dromara.project.domain.vo.projectnews.BusProjectNewsGisVo; +import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo; +import org.dromara.project.service.IBusProjectNewsService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 项目新闻 + * + * @author lilemy + * @date 2025-04-28 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/projectNews") +public class BusProjectNewsController extends BaseController { + + private final IBusProjectNewsService busProjectNewsService; + + /** + * 查询项目新闻列表 + */ + @SaCheckPermission("project:projectNews:list") + @GetMapping("/list") + public TableDataInfo list(BusProjectNewsQueryReq req, PageQuery pageQuery) { + return busProjectNewsService.queryPageList(req, pageQuery); + } + + /** + * 导出项目新闻列表 + */ + @SaCheckPermission("project:projectNews:export") + @Log(title = "项目新闻", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusProjectNewsQueryReq req, HttpServletResponse response) { + List list = busProjectNewsService.queryList(req); + ExcelUtil.exportExcel(list, "项目新闻", BusProjectNewsVo.class, response); + } + + /** + * 查询大屏项目新闻列表 + */ + @GetMapping("/list/gis") + public R> listGis(BusProjectNewsGisReq req) { + return R.ok(busProjectNewsService.queryGisList(req)); + } + + /** + * 获取项目新闻详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:projectNews:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busProjectNewsService.queryById(id)); + } + + /** + * 新增项目新闻 + */ + @SaCheckPermission("project:projectNews:add") + @Log(title = "项目新闻", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusProjectNewsCreateReq req) { + return R.ok(busProjectNewsService.insertByBo(req)); + } + + /** + * 修改项目新闻 + */ + @SaCheckPermission("project:projectNews:edit") + @Log(title = "项目新闻", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusProjectNewsUpdateReq req) { + return toAjax(busProjectNewsService.updateByBo(req)); + } + + /** + * 删除项目新闻 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:projectNews:remove") + @Log(title = "项目新闻", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busProjectNewsService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectTeamController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectTeamController.java new file mode 100644 index 0000000..b57129e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectTeamController.java @@ -0,0 +1,119 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamCreateReq; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamUpdateReq; +import org.dromara.project.domain.vo.projectteam.BusProjectTeamForemanVo; +import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo; +import org.dromara.project.service.IBusProjectTeamService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 项目班组 + * + * @author lilemy + * @date 2025-03-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/projectTeam") +public class BusProjectTeamController extends BaseController { + + private final IBusProjectTeamService busProjectTeamService; + + /** + * 查询项目班组列表 + */ + @SaCheckPermission("project:projectTeam:list") + @GetMapping("/list") + public TableDataInfo list(BusProjectTeamQueryReq req, PageQuery pageQuery) { + return busProjectTeamService.queryPageList(req, pageQuery); + } + + /** + * 根据项目id查询项目班组班组长信息列表 + */ + @SaCheckPermission("project:projectTeam:list") + @GetMapping("/listForeman/{projectId}") + public R> listForeman(@NotNull(message = "项目id不能为空") + @PathVariable Long projectId) { + return R.ok(busProjectTeamService.queryForemanList(projectId)); + } + + /** + * 导出项目班组列表 + */ + @SaCheckPermission("project:projectTeam:export") + @Log(title = "项目班组", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusProjectTeamQueryReq req, HttpServletResponse response) { + List list = busProjectTeamService.queryList(req); + ExcelUtil.exportExcel(list, "项目班组", BusProjectTeamVo.class, response); + } + + /** + * 获取项目班组详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:projectTeam:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busProjectTeamService.queryById(id)); + } + + /** + * 新增项目班组 + */ + @SaCheckPermission("project:projectTeam:add") + @Log(title = "项目班组", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusProjectTeamCreateReq req) { + return R.ok(busProjectTeamService.insertByBo(req)); + } + + /** + * 修改项目班组 + */ + @SaCheckPermission("project:projectTeam:edit") + @Log(title = "项目班组", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusProjectTeamUpdateReq req) { + return toAjax(busProjectTeamService.updateByBo(req)); + } + + /** + * 删除项目班组 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:projectTeam:remove") + @Log(title = "项目班组", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busProjectTeamService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectTeamMemberController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectTeamMemberController.java new file mode 100644 index 0000000..0556d76 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectTeamMemberController.java @@ -0,0 +1,105 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberCreateReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberExitReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberQueryReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberUpdateReq; +import org.dromara.project.domain.vo.projectteammember.BusProjectTeamMemberVo; +import org.dromara.project.service.IBusProjectTeamMemberService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 项目班组下的成员 + * + * @author lilemy + * @date 2025-03-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/projectTeamMember") +public class BusProjectTeamMemberController extends BaseController { + + private final IBusProjectTeamMemberService busProjectTeamMemberService; + + /** + * 查询项目班组下的成员列表 + */ + @SaCheckPermission("project:projectTeamMember:list") + @GetMapping("/list") + public TableDataInfo list(BusProjectTeamMemberQueryReq req, PageQuery pageQuery) { + return busProjectTeamMemberService.queryPageList(req, pageQuery); + } + + /** + * 导出项目班组下的成员列表 + */ + @SaCheckPermission("project:projectTeamMember:export") + @Log(title = "项目班组下的成员", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusProjectTeamMemberQueryReq req, HttpServletResponse response) { + List list = busProjectTeamMemberService.queryList(req); + ExcelUtil.exportExcel(list, "项目班组下的成员", BusProjectTeamMemberVo.class, response); + } + + /** + * 获取项目班组下的成员详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:projectTeamMember:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busProjectTeamMemberService.queryById(id)); + } + + /** + * 新增项目班组下的成员 + */ + @SaCheckPermission("project:projectTeamMember:add") + @Log(title = "项目班组下的成员", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusProjectTeamMemberCreateReq req) { + return R.ok(busProjectTeamMemberService.insertByBo(req)); + } + + /** + * 修改项目班组下的成员 + */ + @SaCheckPermission("project:projectTeamMember:edit") + @Log(title = "项目班组下的成员", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusProjectTeamMemberUpdateReq req) { + return toAjax(busProjectTeamMemberService.updateByBo(req)); + } + + /** + * 施工人员退场 + */ + @SaCheckPermission("project:projectTeamMember:remove") + @Log(title = "项目班组下的成员", businessType = BusinessType.DELETE) + @DeleteMapping("/") + public R remove(@RequestBody BusProjectTeamMemberExitReq req) { + return toAjax(busProjectTeamMemberService.deleteById(req)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusReissueCardController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusReissueCardController.java new file mode 100644 index 0000000..19e152a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusReissueCardController.java @@ -0,0 +1,94 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.reissuecard.BusReissueCardManagerReviewReq; +import org.dromara.project.domain.dto.reissuecard.BusReissueCardQueryReq; +import org.dromara.project.domain.vo.reissuecard.BusReissueCardVo; +import org.dromara.project.service.IBusReissueCardService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 施工人员补卡申请 + * + * @author lilemy + * @date 2025-04-08 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/reissueCard") +public class BusReissueCardController extends BaseController { + + private final IBusReissueCardService busReissueCardService; + + /** + * 查询施工人员补卡申请列表 + */ + @SaCheckPermission("project:reissueCard:list") + @GetMapping("/list") + public TableDataInfo list(BusReissueCardQueryReq req, PageQuery pageQuery) { + return busReissueCardService.queryPageList(req, pageQuery); + } + + /** + * 导出施工人员补卡申请列表 + */ + @SaCheckPermission("project:reissueCard:export") + @Log(title = "施工人员补卡申请", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusReissueCardQueryReq req, HttpServletResponse response) { + List list = busReissueCardService.queryList(req); + ExcelUtil.exportExcel(list, "施工人员补卡申请", BusReissueCardVo.class, response); + } + + /** + * 获取施工人员补卡申请详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:reissueCard:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busReissueCardService.queryById(id)); + } + + /** + * 管理员审核施工人员补卡申请 + */ + @SaCheckPermission("project:reissueCard:edit") + @Log(title = "施工人员补卡申请", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/review/manager") + public R managerReview(@RequestBody BusReissueCardManagerReviewReq req) { + return toAjax(busReissueCardService.managerReview(req)); + } + + /** + * 删除施工人员补卡申请 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:reissueCard:remove") + @Log(title = "施工人员补卡申请", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busReissueCardService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusUserProjectRelevancyController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusUserProjectRelevancyController.java new file mode 100644 index 0000000..7ee76f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusUserProjectRelevancyController.java @@ -0,0 +1,168 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.BusUserProjectRelevancy; +import org.dromara.project.domain.dto.project.BusProjectBatchByProjectListReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyCreateReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyQueryReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyUpdateReq; +import org.dromara.project.domain.vo.userprojectrelevancy.BusLoginUserProjectRelevancyVo; +import org.dromara.project.domain.vo.userprojectrelevancy.BusUserProjectRelevancyVo; +import org.dromara.project.service.IBusUserProjectRelevancyService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 系统用户与项目关联 + * + * @author lilemy + * @date 2025-03-04 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/projectRelevancy") +public class BusUserProjectRelevancyController extends BaseController { + + private final IBusUserProjectRelevancyService userProjectRelevancyService; + + /** + * 查询用户与项目关联列表 + */ + @SaCheckPermission("project:projectRelevancy:list") + @GetMapping("/list") + public TableDataInfo list(BusUserProjectRelevancyQueryReq req, PageQuery pageQuery) { + return userProjectRelevancyService.queryPageList(req, pageQuery); + } + + /** + * 查询登录用户与项目关联列表 + */ + @GetMapping("/login/list") + public R> listByLoginUser() { + Long userId = LoginHelper.getUserId(); + return R.ok(userProjectRelevancyService.queryListByUserId(userId)); + } + + /** + * 查询登录用户与项目关联分页 + */ + @SaCheckPermission("project:projectRelevancy:list") + @GetMapping("/login/page") + public TableDataInfo pageByLoginUser(BusUserProjectRelevancyQueryReq req, PageQuery pageQuery) { + Long userId = LoginHelper.getUserId(); + return userProjectRelevancyService.queryPageByUserId(userId, req, pageQuery); + } + + /** + * 导出用户与项目关联列表 + */ + @SaCheckPermission("project:projectRelevancy:export") + @Log(title = "系统用户与项目关联", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusUserProjectRelevancyQueryReq req, HttpServletResponse response) { + List list = userProjectRelevancyService.queryList(req); + ExcelUtil.exportExcel(list, "系统用户与项目关联", BusUserProjectRelevancyVo.class, response); + } + + /** + * 获取用户与项目关联详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:projectRelevancy:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(userProjectRelevancyService.queryById(id)); + } + + /** + * 新增用户与项目关联 + */ + @SaCheckPermission("project:projectRelevancy:add") + @Log(title = "系统用户与项目关联", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusUserProjectRelevancyCreateReq req) { + return R.ok(userProjectRelevancyService.insertByBo(req)); + } + + /** + * 新增用户与项目列表关联 + */ + @SaCheckPermission("project:projectRelevancy:add") + @Log(title = "系统用户与项目关联", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/add/project/list") + public R addBatchByProjectList(@RequestBody BusProjectBatchByProjectListReq req) { + Boolean result = userProjectRelevancyService.insertBatchByProjectList(req); + return R.ok(result); + } + + /** + * 移除用户与项目列表关联 + */ + @SaCheckPermission("project:projectRelevancy:remove") + @Log(title = "系统用户与项目关联", businessType = BusinessType.INSERT) + @RepeatSubmit() + @DeleteMapping("/remove/project/list") + public R removeBatchByProjectList(@RequestBody BusProjectBatchByProjectListReq req) { + Long userId = req.getUserId(); + Long[] projectIdList = req.getProjectIdList(); + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("user_id", userId).in("project_id", (Object[]) projectIdList); + boolean result = userProjectRelevancyService.remove(wrapper); +/* List userProjectRelevancyList = Arrays.stream(projectIdList).map(projectId -> { + UserProjectRelevancy userProjectRelevancy = new UserProjectRelevancy(); + userProjectRelevancy.setUserId(userId); + userProjectRelevancy.setProjectId(projectId); + return userProjectRelevancy; + }).toList(); + boolean result = userProjectRelevancyService.removeBatchByIds(userProjectRelevancyList);*/ + return R.ok(result); + } + + + /** + * 修改用户与项目关联 + */ + @SaCheckPermission("project:projectRelevancy:edit") + @Log(title = "系统用户与项目关联", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusUserProjectRelevancyUpdateReq req) { + return toAjax(userProjectRelevancyService.updateByBo(req)); + } + + /** + * 删除用户与项目关联 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:projectRelevancy:remove") + @Log(title = "系统用户与项目关联", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(userProjectRelevancyService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusWorkWageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusWorkWageController.java new file mode 100644 index 0000000..4bb1058 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusWorkWageController.java @@ -0,0 +1,108 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.workwage.BusWorkWageCreateReq; +import org.dromara.project.domain.dto.workwage.BusWorkWageQueryReq; +import org.dromara.project.domain.dto.workwage.BusWorkWageUpdateReq; +import org.dromara.project.domain.vo.workwage.BusWorkWageVo; +import org.dromara.project.service.IBusWorkWageService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 工种薪水 + * + * @author lilemy + * @date 2025-03-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/workWage") +public class BusWorkWageController extends BaseController { + + private final IBusWorkWageService busWorkWageService; + + /** + * 查询工种薪水列表 + */ + @SaCheckPermission("project:workWage:list") + @GetMapping("/list") + public TableDataInfo list(BusWorkWageQueryReq req, PageQuery pageQuery) { + return busWorkWageService.queryPageList(req, pageQuery); + } + + /** + * 导出工种薪水列表 + */ + @SaCheckPermission("project:workWage:export") + @Log(title = "工种薪水", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusWorkWageQueryReq req, HttpServletResponse response) { + List list = busWorkWageService.queryList(req); + ExcelUtil.exportExcel(list, "工种薪水", BusWorkWageVo.class, response); + } + + /** + * 获取工种薪水详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:workWage:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busWorkWageService.queryById(id)); + } + + /** + * 新增工种薪水 + */ + @SaCheckPermission("project:workWage:add") + @Log(title = "工种薪水", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BusWorkWageCreateReq req) { + return R.ok(busWorkWageService.insertByBo(req)); + } + + /** + * 修改工种薪水 + */ + @SaCheckPermission("project:workWage:edit") + @Log(title = "工种薪水", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody BusWorkWageUpdateReq req) { + return toAjax(busWorkWageService.updateByBo(req)); + } + + /** + * 删除工种薪水 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:workWage:remove") + @Log(title = "工种薪水", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busWorkWageService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusWorkerDailyReportController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusWorkerDailyReportController.java new file mode 100644 index 0000000..7605f91 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusWorkerDailyReportController.java @@ -0,0 +1,82 @@ +package org.dromara.project.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.project.domain.dto.workerdailyreport.BusWorkerDailyReportQueryReq; +import org.dromara.project.domain.vo.workerdailyreport.BusWorkerDailyReportVo; +import org.dromara.project.service.IBusWorkerDailyReportService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 施工人员日报 + * + * @author lilemy + * @date 2025-04-09 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/project/workerDailyReport") +public class BusWorkerDailyReportController extends BaseController { + + private final IBusWorkerDailyReportService busWorkerDailyReportService; + + /** + * 查询施工人员日报列表 + */ + @SaCheckPermission("project:workerDailyReport:list") + @GetMapping("/list") + public TableDataInfo list(BusWorkerDailyReportQueryReq req, PageQuery pageQuery) { + return busWorkerDailyReportService.queryPageList(req, pageQuery); + } + + /** + * 导出施工人员日报列表 + */ + @SaCheckPermission("project:workerDailyReport:export") + @Log(title = "施工人员日报", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BusWorkerDailyReportQueryReq req, HttpServletResponse response) { + List list = busWorkerDailyReportService.queryList(req); + ExcelUtil.exportExcel(list, "施工人员日报", BusWorkerDailyReportVo.class, response); + } + + /** + * 获取施工人员日报详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("project:workerDailyReport:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(busWorkerDailyReportService.queryById(id)); + } + + /** + * 删除施工人员日报 + * + * @param ids 主键串 + */ + @SaCheckPermission("project:workerDailyReport:remove") + @Log(title = "施工人员日报", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(busWorkerDailyReportService.deleteWithValidByIds(List.of(ids), true)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendance.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendance.java new file mode 100644 index 0000000..4a00c5d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusAttendance.java @@ -0,0 +1,112 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 考勤对象 bus_attendance + * + * @author lilemy + * @date 2025-04-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_attendance") +public class BusAttendance extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 人员id + */ + private Long userId; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 人脸照 + */ + private String facePic; + + /** + * 项目id + */ + private Long projectId; + + /** + * 上班打卡时间 + */ + private Date clockTime; + + /** + * 打卡日期 + */ + private Date clockDate; + + /** + * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) + */ + private String clockStatus; + + /** + * 请假id + */ + private Long leaveId; + + /** + * 代打人员id + */ + private Long pinchUserId; + + /** + * 多次打卡时间记录 + */ + private String clockRecord; + + /** + * 上下班(1上班,2下班) + */ + private String commuter; + + /** + * 打卡范围 + */ + private String punchRange; + + /** + * 日薪 + */ + private Long dailyWage; + + /** + * 经度 + */ + private String lng; + + /** + * 纬度 + */ + private String lat; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusConstructionBlacklist.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusConstructionBlacklist.java new file mode 100644 index 0000000..35dfcb2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusConstructionBlacklist.java @@ -0,0 +1,56 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 黑名单对象 bus_construction_blacklist + * + * @author lilemy + * @date 2025-03-27 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("bus_construction_blacklist") +public class BusConstructionBlacklist extends BaseEntity { + + @Serial + private static final long serialVersionUID = 2723907622284296331L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户id + */ + private Long userId; + + /** + * 名字 + */ + private String userName; + + /** + * 身份证号码 + */ + private String sfzNumber; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusConstructionUserExit.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusConstructionUserExit.java new file mode 100644 index 0000000..7669c07 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusConstructionUserExit.java @@ -0,0 +1,71 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 施工人员入场退场记录信息对象 bus_construction_user_exit + * + * @author lilemy + * @date 2025-03-31 + */ +@Data +@TableName("bus_construction_user_exit") +public class BusConstructionUserExit implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 身份证号码 + */ + private String sfzNumber; + + /** + * 用户id + */ + private Long userId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 入场时间 + */ + private Date entryDate; + + /** + * 退场时间 + */ + private Date leaveDate; + + /** + * 退场文件 + */ + private String path; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusDailyPieceItem.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusDailyPieceItem.java new file mode 100644 index 0000000..3bbf422 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusDailyPieceItem.java @@ -0,0 +1,65 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 施工人员日报计件信息对象 bus_daily_piece_item + * + * @author lilemy + * @date 2025-04-09 + */ +@Data +@TableName("bus_daily_piece_item") +public class BusDailyPieceItem implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 日报id + */ + private Long reportId; + + /** + * 计件类型 + */ + private String pieceType; + + /** + * 计件数量 + */ + private Long pieceCount; + + /** + * 计件单位 + */ + private String pieceUnit; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusLeave.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusLeave.java new file mode 100644 index 0000000..fcab96a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusLeave.java @@ -0,0 +1,132 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 施工人员请假申请对象 bus_leave + * + * @author lilemy + * @date 2025-04-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_leave") +public class BusLeave extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + private String userName; + + /** + * 申请请假说明 + */ + private String userExplain; + + /** + * 请假申请时间 + */ + private Date userTime; + + /** + * 请假类型(1事假 2病假) + */ + private String leaveType; + + /** + * 请假开始时间 + */ + private Date startTime; + + /** + * 请假结束时间 + */ + private Date endTime; + + /** + * 班组长 + */ + private Long gangerId; + + /** + * 班组长名字 + */ + private String gangerName; + + /** + * 班组长意见(1未读 2同意 3拒绝) + */ + private String gangerOpinion; + + /** + * 班组长说明 + */ + private String gangerExplain; + + /** + * 班组长操作时间 + */ + private Date gangerTime; + + /** + * 管理员id + */ + private Long managerId; + + /** + * 管理员名字 + */ + private String managerName; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + private String managerOpinion; + + /** + * 管理员说明 + */ + private String managerExplain; + + /** + * 管理员操作时间 + */ + private Date managerTime; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProject.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProject.java new file mode 100644 index 0000000..09c89b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProject.java @@ -0,0 +1,154 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 项目对象 project + * + * @author lilemy + * @date 2025-03-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_project") +public class BusProject extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目简称 + */ + private String shortName; + + /** + * 父项目id + */ + private Long pId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 项目图片 + */ + private String picUrl; + + /** + * 经度 + */ + private String lng; + + /** + * 纬度 + */ + private String lat; + + /** + * 备注 + */ + private String remark; + + /** + * 项目类型 + */ + private String projectType; + + /** + * 项目类别 + */ + private String projectCategory; + + /** + * 删除时间 + */ + private Date deletedAt; + + /** + * 项目地址 + */ + private String projectSite; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 实际容量 + */ + private String actual; + + /** + * 计划容量 + */ + private String plan; + + /** + * 开工时间 + */ + private String onStreamTime; + + /** + * 打卡范围(09:00,18:00) + */ + private String punchRange; + + /** + * 设计总量 + */ + private Long designTotal; + + /** + * 安全协议书 + */ + private String securityAgreement; + + /** + * 排序字段 + */ + private Long sort; + + /** + * 显示隐藏(0显示 1隐藏) + */ + private String showHidden; + + /** + * 是否删除(0正常 1删除) + */ + @TableLogic + private Long isDelete; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectFile.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectFile.java new file mode 100644 index 0000000..db02844 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectFile.java @@ -0,0 +1,65 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 项目文件存储对象 bus_project_file + * + * @author lilemy + * @date 2025-04-23 + */ +@Data +@TableName("bus_project_file") +public class BusProjectFile implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件类型 + */ + private String fileType; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectNews.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectNews.java new file mode 100644 index 0000000..5be72fc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectNews.java @@ -0,0 +1,51 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 项目新闻对象 bus_project_news + * + * @author lilemy + * @date 2025-04-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_project_news") +public class BusProjectNews extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 标题 + */ + private String title; + + /** + * 内容 + */ + private String content; + + /** + * 附件 + */ + private String file; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectTeam.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectTeam.java new file mode 100644 index 0000000..063a62f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectTeam.java @@ -0,0 +1,51 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 项目班组对象 bus_project_team + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_project_team") +public class BusProjectTeam extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 范围内打卡(0范围内打卡 1任何地点打卡)默认为1 + */ + private String isClockIn; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectTeamMember.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectTeamMember.java new file mode 100644 index 0000000..3d970e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusProjectTeamMember.java @@ -0,0 +1,65 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 项目班组下的成员对象 bus_project_team_member + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@TableName("bus_project_team_member") +public class BusProjectTeamMember implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 班组id + */ + private Long teamId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 施工人员id + */ + private Long memberId; + + /** + * 岗位(默认为0普通员工,1组长) + */ + private String postId; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusReissueCard.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusReissueCard.java new file mode 100644 index 0000000..23406e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusReissueCard.java @@ -0,0 +1,127 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 施工人员补卡申请对象 bus_reissue_card + * + * @author lilemy + * @date 2025-04-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_reissue_card") +public class BusReissueCard extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + private String userName; + + /** + * 申请补卡说明 + */ + private String userExplain; + + /** + * 补卡申请时间 + */ + private Date userTime; + + /** + * 班组长 + */ + private Long gangerId; + + /** + * 班组长名字 + */ + private String gangerName; + + /** + * 班组长意见(1未读 2同意 3拒绝) + */ + private String gangerOpinion; + + /** + * 班组长说明 + */ + private String gangerExplain; + + /** + * 班组长操作时间 + */ + private Date gangerTime; + + /** + * 管理员id + */ + private Long managerId; + + /** + * 管理员名字 + */ + private String managerName; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + private String managerOpinion; + + /** + * 管理员说明 + */ + private String managerExplain; + + /** + * 管理员操作时间 + */ + private Date managerTime; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 补卡类型(1上班 2下班) + */ + private String reissueCardType; + + /** + * 考勤表主键id + */ + private Long attendanceId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusUserProjectRelevancy.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusUserProjectRelevancy.java new file mode 100644 index 0000000..8472786 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusUserProjectRelevancy.java @@ -0,0 +1,39 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 系统用户与项目关联对象 user_project_relevancy + * + * @author lilemy + * @date 2025-03-04 + */ +@Data +@TableName("bus_user_project_relevancy") +public class BusUserProjectRelevancy implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 项目ID + */ + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusWorkWage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusWorkWage.java new file mode 100644 index 0000000..3a7c640 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusWorkWage.java @@ -0,0 +1,66 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 工种薪水对象 bus_work_wage + * + * @author lilemy + * @date 2025-03-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_work_wage") +public class BusWorkWage extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 工种 + */ + private String workType; + + /** + * 是否是特种兵(1是 2否) + */ + private String isSpecialType; + + /** + * 工资计算方式(1计时 2计件) + */ + private String wageCalculationType; + + /** + * 工资标准 + */ + private Long wage; + + /** + * 工资计量单位 + */ + private String wageMeasureUnit; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusWorkerDailyReport.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusWorkerDailyReport.java new file mode 100644 index 0000000..c8a4233 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/BusWorkerDailyReport.java @@ -0,0 +1,127 @@ +package org.dromara.project.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 施工人员日报对象 bus_worker_daily_report + * + * @author lilemy + * @date 2025-04-09 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("bus_worker_daily_report") +public class BusWorkerDailyReport extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 申请人id + */ + private Long userId; + + /** + * 日报日期 + */ + private Date reportDate; + + /** + * 申请人名字 + */ + private String userName; + + /** + * 今日完成工作 + */ + private String todayCompletedWork; + + /** + * 未完成工作 + */ + private String unfinishedWork; + + /** + * 明日工作 + */ + private String tomorrowWork; + + /** + * 需协调与帮助 + */ + private String coordinationHelp; + + /** + * 是否为补卡(1不是 2是) + */ + private Long isResubmit; + + /** + * 补交理由 + */ + private String resubmitReason; + + /** + * 附件 + */ + private String file; + + /** + * 是否审核(1审核 2不审核) + */ + private Long isReview; + + /** + * 审核人id + */ + private Long reviewerId; + + /** + * 审核人名字 + */ + private String reviewerName; + + /** + * 审核人意见(1未读 2同意 3拒绝) + */ + private String reviewOpinion; + + /** + * 审核人说明 + */ + private String reviewExplain; + + /** + * 审核人操作时间 + */ + private Date reviewTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceMonthByUserIdReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceMonthByUserIdReq.java new file mode 100644 index 0000000..63970c1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceMonthByUserIdReq.java @@ -0,0 +1,30 @@ +package org.dromara.project.domain.dto.attendance; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/8 17:13 + */ +@Data +public class BusAttendanceMonthByUserIdReq implements Serializable { + + @Serial + private static final long serialVersionUID = -1295339038112604001L; + + /** + * 用户id + */ + @NotNull(message = "用户主键不能为空") + private Long userId; + + /** + * 打卡月份 + */ + private String clockMonth; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceQueryReq.java new file mode 100644 index 0000000..f65e62a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceQueryReq.java @@ -0,0 +1,48 @@ +package org.dromara.project.domain.dto.attendance; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/26 9:47 + */ +@Data +public class BusAttendanceQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7188085233824968862L; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) + */ + private String clockStatus; + + /** + * 打卡日期 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date clockDate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceQueryTwoWeekReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceQueryTwoWeekReq.java new file mode 100644 index 0000000..033af35 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/attendance/BusAttendanceQueryTwoWeekReq.java @@ -0,0 +1,48 @@ +package org.dromara.project.domain.dto.attendance; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/7 9:53 + */ +@Data +public class BusAttendanceQueryTwoWeekReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3193787736889938829L; + + /** + * 人员姓名 + */ + private String userName; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 工种 + */ + private String typeOfWork; + + /** + * 打卡日期 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date clockDate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionblacklist/BusConstructionBlacklistCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionblacklist/BusConstructionBlacklistCreateReq.java new file mode 100644 index 0000000..03d0133 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionblacklist/BusConstructionBlacklistCreateReq.java @@ -0,0 +1,28 @@ +package org.dromara.project.domain.dto.constructionblacklist; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/27 9:30 + */ +@Data +public class BusConstructionBlacklistCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -1095123147028743165L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户id + */ + private Long userId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionblacklist/BusConstructionBlacklistQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionblacklist/BusConstructionBlacklistQueryReq.java new file mode 100644 index 0000000..c4cd3e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionblacklist/BusConstructionBlacklistQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.project.domain.dto.constructionblacklist; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/27 9:30 + */ +@Data +public class BusConstructionBlacklistQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5638694783769399209L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户id + */ + private Long userId; + + /** + * 名字 + */ + private String userName; + + /** + * 身份证号码 + */ + private String sfzNumber; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionuserexit/BusConstructionUserExitQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionuserexit/BusConstructionUserExitQueryReq.java new file mode 100644 index 0000000..43f4be4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/constructionuserexit/BusConstructionUserExitQueryReq.java @@ -0,0 +1,57 @@ +package org.dromara.project.domain.dto.constructionuserexit; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/31 15:13 + */ +@Data +public class BusConstructionUserExitQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1108809723013529990L; + + /** + * 主键id + */ + private Long id; + + /** + * 身份证号码 + */ + private String sfzNumber; + + /** + * 用户id + */ + private Long userId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 入场时间 + */ + private String entryDate; + + /** + * 退场时间 + */ + private String leaveDate; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/leave/BusLeaveManagerReviewReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/leave/BusLeaveManagerReviewReq.java new file mode 100644 index 0000000..fc2ba34 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/leave/BusLeaveManagerReviewReq.java @@ -0,0 +1,41 @@ +package org.dromara.project.domain.dto.leave; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/8 11:43 + */ +@Data +public class BusLeaveManagerReviewReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3902793123554028126L; + + /** + * 主键id + */ + @NotNull(message = "主键不能为空") + private Long id; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + @NotNull(message = "管理员意见不能为空") + private String managerOpinion; + + /** + * 管理员说明 + */ + private String managerExplain; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/leave/BusLeaveQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/leave/BusLeaveQueryReq.java new file mode 100644 index 0000000..70202d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/leave/BusLeaveQueryReq.java @@ -0,0 +1,70 @@ +package org.dromara.project.domain.dto.leave; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/8 11:44 + */ +@Data +public class BusLeaveQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 43795533290515099L; + + /** + * 主键id + */ + private Long id; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + private String userName; + + /** + * 请假类型(1事假 2病假) + */ + private String leaveType; + + /** + * 班组长 + */ + private Long gangerId; + + /** + * 班组长名字 + */ + private String gangerName; + + /** + * 班组长意见(1未读 2同意 3拒绝) + */ + private String gangerOpinion; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + private String managerOpinion; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectBatchByProjectListReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectBatchByProjectListReq.java new file mode 100644 index 0000000..dcd5b97 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectBatchByProjectListReq.java @@ -0,0 +1,28 @@ +package org.dromara.project.domain.dto.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 17:16 + */ +@Data +public class BusProjectBatchByProjectListReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3366498681076059844L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 项目ID列表 + */ + private Long[] projectIdList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectCreateReq.java new file mode 100644 index 0000000..830ed4c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectCreateReq.java @@ -0,0 +1,117 @@ +package org.dromara.project.domain.dto.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class BusProjectCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目简称 + */ + private String shortName; + + /** + * 项目图片 + */ + private String picUrl; + + /** + * 经度 + */ + private String lng; + + /** + * 纬度 + */ + private String lat; + + /** + * 备注 + */ + private String remark; + + /** + * 项目类型 + */ + private String projectType; + + /** + * 项目类别 + */ + private String projectCategory; + + /** + * 项目地址 + */ + private String projectSite; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 实际容量 + */ + private String actual; + + /** + * 计划容量 + */ + private String plan; + + /** + * 开工时间 + */ + private String onStreamTime; + + /** + * 打卡时间开始 + */ + private String playCardStart; + + /** + * 打卡时间结束 + */ + private String playCardEnd; + + /** + * 设计总量 + */ + private Long designTotal; + + /** + * 安全协议书 + */ + private String securityAgreement; + + /** + * 排序字段 + */ + private Long sort; + + /** + * 显示隐藏(0显示 1隐藏) + */ + private String showHidden; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectCreateSubReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectCreateSubReq.java new file mode 100644 index 0000000..a051a75 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectCreateSubReq.java @@ -0,0 +1,28 @@ +package org.dromara.project.domain.dto.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/6 11:57 + */ +@Data +public class BusProjectCreateSubReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6380055877986391291L; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 父项目id + */ + private Long pId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectQueryReq.java new file mode 100644 index 0000000..a2d9644 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectQueryReq.java @@ -0,0 +1,112 @@ +package org.dromara.project.domain.dto.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class BusProjectQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5563677643070664671L; + + /** + * 项目 id + */ + private Long id; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目简称 + */ + private String shortName; + + /** + * 父项目id + */ + private Long pId; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 经度 + */ + private String lng; + + /** + * 纬度 + */ + private String lat; + + /** + * 备注 + */ + private String remark; + + /** + * 项目类型 + */ + private String projectType; + + /** + * 项目类别 + */ + private String projectCategory; + + /** + * 项目地址 + */ + private String projectSite; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 实际容量 + */ + private String actual; + + /** + * 计划容量 + */ + private String plan; + + /** + * 开工时间 + */ + private String onStreamTime; + + /** + * 打卡范围(09:00,18:00) + */ + private String punchRange; + + /** + * 设计总量 + */ + private Long designTotal; + + /** + * 显示隐藏(0显示 1隐藏) + */ + private String showHidden; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectUpdateReq.java new file mode 100644 index 0000000..9ee3d41 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/project/BusProjectUpdateReq.java @@ -0,0 +1,132 @@ +package org.dromara.project.domain.dto.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class BusProjectUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3431952359907567659L; + + /** + * id + */ + private Long id; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目简称 + */ + private String shortName; + + /** + * 父项目id + */ + private Long pId; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 项目图片 + */ + private String picUrl; + + /** + * 经度 + */ + private String lng; + + /** + * 纬度 + */ + private String lat; + + /** + * 备注 + */ + private String remark; + + /** + * 项目类型 + */ + private String projectType; + + /** + * 项目类别 + */ + private String projectCategory; + + /** + * 项目地址 + */ + private String projectSite; + + /** + * 负责人 + */ + private String principal; + + /** + * 负责人电话 + */ + private String principalPhone; + + /** + * 实际容量 + */ + private String actual; + + /** + * 计划容量 + */ + private String plan; + + /** + * 开工时间 + */ + private String onStreamTime; + + /** + * 打卡时间开始 + */ + private String playCardStart; + + /** + * 打卡时间结束 + */ + private String playCardEnd; + + /** + * 设计总量 + */ + private Long designTotal; + + /** + * 安全协议书 + */ + private String securityAgreement; + + /** + * 显示隐藏(0显示 1隐藏) + */ + private String showHidden; + + /** + * 排序字段 + */ + private Long sort; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileQueryReq.java new file mode 100644 index 0000000..fc5b718 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileQueryReq.java @@ -0,0 +1,33 @@ +package org.dromara.project.domain.dto.projectfile; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/23 14:16 + */ +@Data +public class BusProjectFileQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 399401709402729491L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件类型 + */ + private String fileType; + + /** + * 文件名称 + */ + private String fileName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileUpdateReq.java new file mode 100644 index 0000000..540c3d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileUpdateReq.java @@ -0,0 +1,38 @@ +package org.dromara.project.domain.dto.projectfile; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/23 14:18 + */ +@Data +public class BusProjectFileUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5620479296452749930L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileUploadDxfReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileUploadDxfReq.java new file mode 100644 index 0000000..8903c80 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectfile/BusProjectFileUploadDxfReq.java @@ -0,0 +1,23 @@ +package org.dromara.project.domain.dto.projectfile; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/23 11:43 + */ +@Data +public class BusProjectFileUploadDxfReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7096688035548954702L; + + /** + * 项目id + */ + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsCreateReq.java new file mode 100644 index 0000000..e664e13 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsCreateReq.java @@ -0,0 +1,38 @@ +package org.dromara.project.domain.dto.projectnews; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 11:52 + */ +@Data +public class BusProjectNewsCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 7116830397516873096L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 标题 + */ + private String title; + + /** + * 内容 + */ + private String content; + + /** + * 附件 + */ + private String file; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsGisReq.java new file mode 100644 index 0000000..61dea3b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsGisReq.java @@ -0,0 +1,25 @@ +package org.dromara.project.domain.dto.projectnews; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 14:07 + */ +@Data +public class BusProjectNewsGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = -291705026028532102L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsQueryReq.java new file mode 100644 index 0000000..f6c3a6f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsQueryReq.java @@ -0,0 +1,23 @@ +package org.dromara.project.domain.dto.projectnews; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 11:52 + */ +@Data +public class BusProjectNewsQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1453496535743326174L; + + /** + * 项目id + */ + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsUpdateReq.java new file mode 100644 index 0000000..a09d8fc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectnews/BusProjectNewsUpdateReq.java @@ -0,0 +1,38 @@ +package org.dromara.project.domain.dto.projectnews; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 11:53 + */ +@Data +public class BusProjectNewsUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5988430319051945969L; + + /** + * 主键id + */ + private Long id; + + /** + * 标题 + */ + private String title; + + /** + * 内容 + */ + private String content; + + /** + * 附件 + */ + private String file; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamCreateReq.java new file mode 100644 index 0000000..26a3179 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamCreateReq.java @@ -0,0 +1,38 @@ +package org.dromara.project.domain.dto.projectteam; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class BusProjectTeamCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 范围内打卡(0范围内打卡 1任何地点打卡)默认为1 + */ + private String isClockIn; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamQueryReq.java new file mode 100644 index 0000000..6055134 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamQueryReq.java @@ -0,0 +1,43 @@ +package org.dromara.project.domain.dto.projectteam; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class BusProjectTeamQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3252651952758479341L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 范围内打卡(0范围内打卡 1任何地点打卡)默认为1 + */ + private String isClockIn; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamUpdateReq.java new file mode 100644 index 0000000..b7904eb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteam/BusProjectTeamUpdateReq.java @@ -0,0 +1,43 @@ +package org.dromara.project.domain.dto.projectteam; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class BusProjectTeamUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8022860866890925958L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 范围内打卡(0范围内打卡 1任何地点打卡)默认为1 + */ + private String isClockIn; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberCreateReq.java new file mode 100644 index 0000000..39a3844 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberCreateReq.java @@ -0,0 +1,43 @@ +package org.dromara.project.domain.dto.projectteammember; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class BusProjectTeamMemberCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 班组id + */ + private Long teamId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 施工人员id + */ + private Long memberId; + + /** + * 岗位(默认为0普通员工,1组长) + */ + private String postId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberExitReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberExitReq.java new file mode 100644 index 0000000..c7f42da --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberExitReq.java @@ -0,0 +1,32 @@ +package org.dromara.project.domain.dto.projectteammember; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/31 10:54 + */ +@Data +public class BusProjectTeamMemberExitReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6911310088122710744L; + + /** + * 主键id + */ + private Long id; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberQueryReq.java new file mode 100644 index 0000000..c6768c4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberQueryReq.java @@ -0,0 +1,53 @@ +package org.dromara.project.domain.dto.projectteammember; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class BusProjectTeamMemberQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3252651952758479341L; + + /** + * 主键id + */ + private Long id; + + /** + * 班组id + */ + private Long teamId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 施工人员id + */ + private Long memberId; + + /** + * 施工人员名称 + */ + private String memberName; + + /** + * 岗位(默认为0普通员工,1组长) + */ + private String postId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberUpdateReq.java new file mode 100644 index 0000000..7f5d25a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/projectteammember/BusProjectTeamMemberUpdateReq.java @@ -0,0 +1,48 @@ +package org.dromara.project.domain.dto.projectteammember; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class BusProjectTeamMemberUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8022860866890925958L; + + /** + * 主键id + */ + private Long id; + + /** + * 班组id + */ + private Long teamId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 施工人员id + */ + private Long memberId; + + /** + * 岗位(默认为0普通员工,1组长) + */ + private String postId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/reissuecard/BusReissueCardManagerReviewReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/reissuecard/BusReissueCardManagerReviewReq.java new file mode 100644 index 0000000..1b44070 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/reissuecard/BusReissueCardManagerReviewReq.java @@ -0,0 +1,41 @@ +package org.dromara.project.domain.dto.reissuecard; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/8 10:27 + */ +@Data +public class BusReissueCardManagerReviewReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5249263232892725923L; + + /** + * 主键id + */ + @NotNull(message = "主键不能为空") + private Long id; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + @NotNull(message = "管理员意见不能为空") + private String managerOpinion; + + /** + * 管理员说明 + */ + private String managerExplain; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/reissuecard/BusReissueCardQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/reissuecard/BusReissueCardQueryReq.java new file mode 100644 index 0000000..ff52669 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/reissuecard/BusReissueCardQueryReq.java @@ -0,0 +1,75 @@ +package org.dromara.project.domain.dto.reissuecard; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/8 9:58 + */ +@Data +public class BusReissueCardQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3708280254564807491L; + + /** + * 主键id + */ + private Long id; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + private String userName; + + /** + * 班组长 + */ + private Long gangerId; + + /** + * 班组长名字 + */ + private String gangerName; + + /** + * 班组长意见(1未读 2同意 3拒绝) + */ + private String gangerOpinion; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + private String managerOpinion; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 补卡类型(1上班 2下班) + */ + private String reissueCardType; + + /** + * 考勤表主键id + */ + private Long attendanceId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyCreateReq.java new file mode 100644 index 0000000..7692815 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyCreateReq.java @@ -0,0 +1,28 @@ +package org.dromara.project.domain.dto.userprojectrelevancy; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:05 + */ +@Data +public class BusUserProjectRelevancyCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7603153089205421154L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 项目ID + */ + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyQueryReq.java new file mode 100644 index 0000000..76ae87e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyQueryReq.java @@ -0,0 +1,32 @@ +package org.dromara.project.domain.dto.userprojectrelevancy; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 14:31 + */ +@Data +public class BusUserProjectRelevancyQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3252651952758479341L; + + /** + * 主键ID + */ + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 项目ID + */ + private Long projectId; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyUpdateReq.java new file mode 100644 index 0000000..2560e17 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/userprojectrelevancy/BusUserProjectRelevancyUpdateReq.java @@ -0,0 +1,33 @@ +package org.dromara.project.domain.dto.userprojectrelevancy; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:04 + */ +@Data +public class BusUserProjectRelevancyUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8022860866890925958L; + + /** + * 主键ID + */ + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 项目ID + */ + private Long projectId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workerdailyreport/BusWorkerDailyReportQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workerdailyreport/BusWorkerDailyReportQueryReq.java new file mode 100644 index 0000000..72f2411 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workerdailyreport/BusWorkerDailyReportQueryReq.java @@ -0,0 +1,56 @@ +package org.dromara.project.domain.dto.workerdailyreport; + +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/9 15:44 + */ +@Data +public class BusWorkerDailyReportQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8919309843260665154L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + private String userName; + + /** + * 日报日期 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date reportDate; + + /** + * 是否为补卡(1不是 2是) + */ + private Long isResubmit; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageCreateReq.java new file mode 100644 index 0000000..01a2bad --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageCreateReq.java @@ -0,0 +1,52 @@ +package org.dromara.project.domain.dto.workwage; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/26 14:30 + */ +@Data +public class BusWorkWageCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1099295506349661143L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 工种 + */ + @NotNull(message = "工种不能为空") + private String workType; + + /** + * 是否是特种兵(1是 2否) + */ + private String isSpecialType; + + /** + * 工资计算方式(1计时 2计件) + */ + @NotNull(message = "工资计算方式不能为空") + private String wageCalculationType; + + /** + * 工资标准 + */ + @NotNull(message = "工资标准不能为空") + private Long wage; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageQueryReq.java new file mode 100644 index 0000000..9992dc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageQueryReq.java @@ -0,0 +1,57 @@ +package org.dromara.project.domain.dto.workwage; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/26 14:30 + */ +@Data +public class BusWorkWageQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2259122917361079910L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 主键id + */ + private Long id; + + /** + * 工种 + */ + private String workType; + + /** + * 是否是特种兵(1是 2否) + */ + private String isSpecialType; + + /** + * 工资计算方式(1计时 2计件) + */ + private String wageCalculationType; + + /** + * 工资标准 + */ + private Long wage; + + /** + * 工资计量单位 + */ + private String wageMeasureUnit; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageUpdateReq.java new file mode 100644 index 0000000..57ff1ad --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/dto/workwage/BusWorkWageUpdateReq.java @@ -0,0 +1,43 @@ +package org.dromara.project.domain.dto.workwage; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/26 14:30 + */ +@Data +public class BusWorkWageUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2367543567493554848L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 是否是特种兵(1是 2否) + */ + private String isSpecialType; + + /** + * 工资标准 + */ + private Long wage; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceClockStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceClockStatusEnum.java new file mode 100644 index 0000000..efdbf76 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceClockStatusEnum.java @@ -0,0 +1,28 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/7 11:31 + */ +@Getter +public enum BusAttendanceClockStatusEnum { + + NORMAL("正常", "1"), + LATE("迟到", "2"), + LEAVEEARLY("早退", "3"), + UNCLOCK("缺卡", "4"), + REISSUE("补卡", "5"), + LEAVE("请假", "6"); + + private final String text; + + private final String value; + + BusAttendanceClockStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceCommuterEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceCommuterEnum.java new file mode 100644 index 0000000..f4e5140 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceCommuterEnum.java @@ -0,0 +1,25 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/7 12:29 + */ +@Getter +public enum BusAttendanceCommuterEnum { + + CLOCKIN("上班", "1"), + CLOCKOUT("下班", "2"), + ALLDAY("全天", "3"); + + private final String text; + + private final String value; + + BusAttendanceCommuterEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceStatusEnum.java new file mode 100644 index 0000000..5b47bcc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusAttendanceStatusEnum.java @@ -0,0 +1,26 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/7 15:38 + */ +@Getter +public enum BusAttendanceStatusEnum { + + NORMAL("全天考勤正常", "1"), + ERROR("当天存在异常迟到、早退、缺卡", "2"), + REISSUE("当天提交过补卡申请", "3"), + LEAVE("当天请假", "4"); + + private final String text; + + private final String value; + + BusAttendanceStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusConstructionUserAttendanceStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusConstructionUserAttendanceStatusEnum.java new file mode 100644 index 0000000..bc1a065 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusConstructionUserAttendanceStatusEnum.java @@ -0,0 +1,26 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/9 14:10 + */ +@Getter +public enum BusConstructionUserAttendanceStatusEnum { + + NORMAL("全天考勤正常", "1"), + ONECLOCK("当天只打了一次卡", "2"), + UNCLOCK("当天缺卡", "3"), + LEAVE("当天请假", "4"); + + private final String text; + + private final String value; + + BusConstructionUserAttendanceStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusOpinionStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusOpinionStatusEnum.java new file mode 100644 index 0000000..04f33f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusOpinionStatusEnum.java @@ -0,0 +1,25 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/8 10:55 + */ +@Getter +public enum BusOpinionStatusEnum { + + UNREAD("未读", "1"), + PASS("同意", "2"), + REFUSE("拒绝", "3"); + + private final String text; + + private final String value; + + BusOpinionStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusProjectTeamMemberPostEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusProjectTeamMemberPostEnum.java new file mode 100644 index 0000000..f5b75b8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusProjectTeamMemberPostEnum.java @@ -0,0 +1,45 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; +import org.dromara.common.core.utils.ObjectUtils; + +/** + * 项目成员岗位枚举 + * + * @author lilemy + * @date 2025/3/21 13:36 + */ +@Getter +public enum BusProjectTeamMemberPostEnum { + + MEMBER("普通成员", "0"), + FOREMAN("班组长", "1"); + + private final String text; + + private final String value; + + BusProjectTeamMemberPostEnum(String text, String value) { + this.text = text; + this.value = value; + } + + /** + * 根据 value 获取枚举 + * + * @param value 项目成员岗位枚举值 + * @return 项目成员岗位枚举 + */ + public static BusProjectTeamMemberPostEnum getEnumByValue(String value) { + if (ObjectUtils.isEmpty(value)) { + return null; + } + for (BusProjectTeamMemberPostEnum anEnum : BusProjectTeamMemberPostEnum.values()) { + if (anEnum.value.equals(value)) { + return anEnum; + } + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusReviewStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusReviewStatusEnum.java new file mode 100644 index 0000000..07f27fa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusReviewStatusEnum.java @@ -0,0 +1,57 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/8 16:13 + */ +@Getter +public enum BusReviewStatusEnum { + + UNREVIEW("待审核", "1"), + INREVIEW("审核中", "2"), + AGREED("已同意", "3"), + DECLINED("已拒绝", "4"); + + private final String text; + + private final String value; + + BusReviewStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + + /** + * 根据班组长和管理员审核状态获取枚举 + * + * @param gangerStatus 班组长审核状态 + * @param managerStatus 管理员审核状态 + * @return 施工人员补卡/请假审核状态 + */ + public static String getEnumByOpinionStatus(String gangerStatus, String managerStatus) { + // 如果其中一个拒绝,返回 DECLINED("已拒绝", "4") + if (BusOpinionStatusEnum.REFUSE.getValue().equals(gangerStatus) + || BusOpinionStatusEnum.REFUSE.getValue().equals(managerStatus)) { + return DECLINED.getValue(); + } + // 当两个状态都未读,返回 UNREVIEW("待审核", "1") + if (BusOpinionStatusEnum.UNREAD.getValue().equals(gangerStatus) + && BusOpinionStatusEnum.UNREAD.getValue().equals(managerStatus)) { + return UNREVIEW.getValue(); + } + // 当两个状态都同意,返回 AGREED("已同意", "3") + if (BusOpinionStatusEnum.PASS.getValue().equals(gangerStatus) + && BusOpinionStatusEnum.PASS.getValue().equals(managerStatus)) { + return AGREED.getValue(); + } + // 当班组长状态不为未读 且管理员状态为未读,返回 INREVIEW("审核中", "2") + if (!BusOpinionStatusEnum.UNREAD.getValue().equals(gangerStatus) + && BusOpinionStatusEnum.UNREAD.getValue().equals(managerStatus)) { + return INREVIEW.getValue(); + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusWageMeasureUnitEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusWageMeasureUnitEnum.java new file mode 100644 index 0000000..da40455 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/BusWageMeasureUnitEnum.java @@ -0,0 +1,24 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/10 11:16 + */ +@Getter +public enum BusWageMeasureUnitEnum { + + TIME("计时:元/每天", "1"), + PIECE("计件:元/每个", "2"); + + private final String text; + + private final String value; + + BusWageMeasureUnitEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceClockDateForTwoWeekVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceClockDateForTwoWeekVo.java new file mode 100644 index 0000000..e9a41a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceClockDateForTwoWeekVo.java @@ -0,0 +1,48 @@ +package org.dromara.project.domain.vo.attendance; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/7 9:55 + */ +@Data +public class BusAttendanceClockDateForTwoWeekVo implements Serializable { + + @Serial + private static final long serialVersionUID = -2762312533060742243L; + + /** + * 打卡日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd", + timezone = "GMT+8") + private Date clockDate; + + /** + * 出勤人数 + */ + private Integer attendance; + + /** + * 半勤人数 + */ + private Integer halfAttendance; + + /** + * 缺勤人数 + */ + private Integer absenteeism; + + /** + * 请假人数 + */ + private Integer leave; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceListByDay.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceListByDay.java new file mode 100644 index 0000000..f89c321 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceListByDay.java @@ -0,0 +1,45 @@ +package org.dromara.project.domain.vo.attendance; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.project.domain.BusAttendance; + +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/7 15:27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BusAttendanceListByDay { + + /** + * 上下班(1上班,2下班) + */ + private String commuter; + + /** + * 打卡时间 + */ + private Date clockTime; + + /** + * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) + */ + private String clockStatus; + + public static BusAttendanceListByDay build(BusAttendance attendance) { + if (attendance == null) { + return null; + } + BusAttendanceListByDay attendanceListByDay = new BusAttendanceListByDay(); + attendanceListByDay.setCommuter(attendance.getCommuter()); + attendanceListByDay.setClockTime(attendance.getClockTime()); + attendanceListByDay.setClockStatus(attendance.getClockStatus()); + return attendanceListByDay; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceMonthByUserIdVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceMonthByUserIdVo.java new file mode 100644 index 0000000..6ea3e70 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceMonthByUserIdVo.java @@ -0,0 +1,44 @@ +package org.dromara.project.domain.vo.attendance; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/8 16:58 + */ +@Data +public class BusAttendanceMonthByUserIdVo implements Serializable { + + @Serial + private static final long serialVersionUID = -6172238396618801431L; + + /** + * 主键id + */ + private Long id; + + /** + * 打卡日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd", + timezone = "GMT+8") + private Date clockDate; + + /** + * 当天打卡状态 + */ + private String Status; + + /** + * 当天打卡记录 + */ + private List attendanceList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceVo.java new file mode 100644 index 0000000..5e57cee --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/attendance/BusAttendanceVo.java @@ -0,0 +1,140 @@ +package org.dromara.project.domain.vo.attendance; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.project.domain.BusAttendance; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 考勤视图对象 bus_attendance + * + * @author lilemy + * @date 2025-04-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusAttendance.class) +public class BusAttendanceVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 人员id + */ + private Long userId; + + /** + * 人员姓名 + */ + @ExcelProperty(value = "人员姓名") + private String userName; + + /** + * 班组id + */ + private Long teamId; + + /** + * 工种 + */ + @ExcelProperty(value = "工种", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "type_of_work") + private String typeOfWork; + + /** + * 人脸照 + */ + private String facePic; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 打卡时间 + */ + @ExcelProperty(value = "打卡时间") + private Date clockTime; + + /** + * 打卡日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd", + timezone = "GMT+8") + @ExcelProperty(value = "打卡日期") + private Date clockDate; + + /** + * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) + */ + @ExcelProperty(value = "打卡状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "clock_status_type") + private String clockStatus; + + /** + * 代打人员id + */ + private Long pinchUserId; + + /** + * 多次打卡时间记录 + */ + @ExcelProperty(value = "多次打卡时间记录") + private String clockRecord; + + /** + * 上下班(1上班,2下班) + */ + @ExcelProperty(value = "上下班", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "commuter_type") + private String commuter; + + /** + * 打卡范围 + */ + @ExcelProperty(value = "打卡范围") + private String punchRange; + + /** + * 日薪 + */ + @ExcelProperty(value = "日薪") + private Long dailyWage; + + /** + * 经度 + */ + @ExcelProperty(value = "经度") + private String lng; + + /** + * 纬度 + */ + @ExcelProperty(value = "纬度") + private String lat; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/constructionblacklist/BusConstructionBlacklistVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/constructionblacklist/BusConstructionBlacklistVo.java new file mode 100644 index 0000000..4fadf89 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/constructionblacklist/BusConstructionBlacklistVo.java @@ -0,0 +1,76 @@ +package org.dromara.project.domain.vo.constructionblacklist; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.project.domain.BusConstructionBlacklist; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 黑名单视图对象 bus_construction_blacklist + * + * @author lilemy + * @date 2025-03-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusConstructionBlacklist.class) +public class BusConstructionBlacklistVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 名字 + */ + @ExcelProperty(value = "名字") + private String userName; + + /** + * 身份证号码 + */ + @ExcelProperty(value = "身份证号码") + private String sfzNumber; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建者 + */ + @ExcelProperty(value = "创建者") + private Long createBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/constructionuserexit/BusConstructionUserExitVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/constructionuserexit/BusConstructionUserExitVo.java new file mode 100644 index 0000000..b194eae --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/constructionuserexit/BusConstructionUserExitVo.java @@ -0,0 +1,89 @@ +package org.dromara.project.domain.vo.constructionuserexit; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.project.domain.BusConstructionUserExit; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 施工人员入场退场记录信息视图对象 bus_construction_user_exit + * + * @author lilemy + * @date 2025-03-31 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusConstructionUserExit.class) +public class BusConstructionUserExitVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 身份证号码 + */ + @ExcelProperty(value = "身份证号码") + private String sfzNumber; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 班组id + */ + @ExcelProperty(value = "班组id") + private Long teamId; + + /** + * 入场时间 + */ + @ExcelProperty(value = "入场时间") + private Date entryDate; + + /** + * 退场时间 + */ + @ExcelProperty(value = "退场时间") + private Date leaveDate; + + /** + * 退场文件 + */ + @ExcelProperty(value = "退场文件") + private String path; + + /** + * 退场文件url + */ + private List pathUrl; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/dailypieceitem/BusDailyPieceItemVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/dailypieceitem/BusDailyPieceItemVo.java new file mode 100644 index 0000000..e6eca75 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/dailypieceitem/BusDailyPieceItemVo.java @@ -0,0 +1,51 @@ +package org.dromara.project.domain.vo.dailypieceitem; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.project.domain.BusDailyPieceItem; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 施工人员日报计件信息视图对象 bus_daily_piece_item + * + * @author lilemy + * @date 2025-04-09 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusDailyPieceItem.class) +public class BusDailyPieceItemVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 计件类型 + */ + private String pieceType; + + /** + * 计件数量 + */ + private Long pieceCount; + + /** + * 计件单位 + */ + private String pieceUnit; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/leave/BusLeaveVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/leave/BusLeaveVo.java new file mode 100644 index 0000000..f0cfb95 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/leave/BusLeaveVo.java @@ -0,0 +1,162 @@ +package org.dromara.project.domain.vo.leave; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.project.domain.BusLeave; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 施工人员请假申请视图对象 bus_leave + * + * @author lilemy + * @date 2025-04-08 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusLeave.class) +public class BusLeaveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + @ExcelProperty(value = "申请人名字") + private String userName; + + /** + * 申请请假说明 + */ + @ExcelProperty(value = "申请请假说明") + private String userExplain; + + /** + * 请假申请时间 + */ + @ExcelProperty(value = "请假申请时间") + private Date userTime; + + /** + * 请假类型(1事假 2病假) + */ + @ExcelProperty(value = "请假类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_leave_type") + private String leaveType; + + /** + * 请假开始时间 + */ + @ExcelProperty(value = "请假开始时间") + private Date startTime; + + /** + * 请假结束时间 + */ + @ExcelProperty(value = "请假结束时间") + private Date endTime; + + /** + * 项目id + */ + private Long teamId; + + /** + * 项目名字 + */ + private String teamName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组长id + */ + private Long gangerId; + + /** + * 班组长名字 + */ + @ExcelProperty(value = "班组长名字") + private String gangerName; + + /** + * 班组长意见(1未读 2同意 3拒绝) + */ + @ExcelProperty(value = "班组长意见", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_opinion_type") + private String gangerOpinion; + + /** + * 班组长说明 + */ + @ExcelProperty(value = "班组长说明") + private String gangerExplain; + + /** + * 班组长操作时间 + */ + @ExcelProperty(value = "班组长操作时间") + private Date gangerTime; + + /** + * 管理员id + */ + private Long managerId; + + /** + * 管理员名字 + */ + private String managerName; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + @ExcelProperty(value = "管理员意见", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_opinion_type") + private String managerOpinion; + + /** + * 管理员说明 + */ + @ExcelProperty(value = "管理员说明") + private String managerExplain; + + /** + * 管理员操作时间 + */ + @ExcelProperty(value = "管理员操作时间") + private Date managerTime; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 审核状态 + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectContractorListVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectContractorListVo.java new file mode 100644 index 0000000..924db02 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectContractorListVo.java @@ -0,0 +1,35 @@ +package org.dromara.project.domain.vo.project; + +import lombok.Data; +import org.dromara.common.core.domain.vo.IdAndNameVO; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/31 16:16 + */ +@Data +public class BusProjectContractorListVo implements Serializable { + + @Serial + private static final long serialVersionUID = 3089953733712392942L; + + /** + * id + */ + private Long id; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目下的分包公司列表 + */ + private List contractorList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectSafetyDayVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectSafetyDayVo.java new file mode 100644 index 0000000..db44329 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectSafetyDayVo.java @@ -0,0 +1,23 @@ +package org.dromara.project.domain.vo.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/14 9:34 + */ +@Data +public class BusProjectSafetyDayVo implements Serializable { + + @Serial + private static final long serialVersionUID = -1479490255029878315L; + + /** + * 安全生产天数 + */ + private Integer safetyDay; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectVo.java new file mode 100644 index 0000000..4720854 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectVo.java @@ -0,0 +1,187 @@ +package org.dromara.project.domain.vo.project; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.project.domain.BusProject; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 项目视图对象 project + * + * @author lilemy + * @date 2025-03-04 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusProject.class) +public class BusProjectVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 项目名称 + */ + @ExcelProperty(value = "项目名称") + private String projectName; + + /** + * 项目简称 + */ + @ExcelProperty(value = "项目简称") + private String shortName; + + /** + * 父项目id + */ + @ExcelProperty(value = "父项目id") + private Long pId; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 项目图片 + */ + @ExcelProperty(value = "项目图片") + private String picUrl; + + /** + * 经度 + */ + @ExcelProperty(value = "经度") + private String lng; + + /** + * 纬度 + */ + @ExcelProperty(value = "纬度") + private String lat; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 项目类型 + */ + @ExcelProperty(value = "项目类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "project_type") + private String projectType; + + /** + * 项目类别 + */ + @ExcelProperty(value = "项目类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "project_category_type") + private String projectCategory; + + /** + * 项目地址 + */ + @ExcelProperty(value = "项目地址") + private String projectSite; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String principal; + + /** + * 负责人电话 + */ + @ExcelProperty(value = "负责人电话") + private String principalPhone; + + /** + * 实际容量 + */ + @ExcelProperty(value = "实际容量") + private String actual; + + /** + * 计划容量 + */ + @ExcelProperty(value = "计划容量") + private String plan; + + /** + * 开工时间 + */ + @ExcelProperty(value = "开工时间") + private String onStreamTime; + + /** + * 打卡范围(09:00,18:00) + */ + @ExcelProperty(value = "打卡范围") + private String punchRange; + + /** + * 打卡时间开始 + */ + private String playCardStart; + + /** + * 打卡时间结束 + */ + private String playCardEnd; + + /** + * 设计总量 + */ + @ExcelProperty(value = "设计总量") + private Long designTotal; + + /** + * 安全协议书 + */ + @ExcelProperty(value = "安全协议书") + private String securityAgreement; + + /** + * 显示隐藏(0显示 1隐藏) + */ + @ExcelProperty(value = "显示隐藏", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=显示,2=隐藏") + private String showHidden; + + /** + * 排序字段 + */ + private Long sort; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 子项目 + */ + private List children; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectWeatherVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectWeatherVo.java new file mode 100644 index 0000000..366d01d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusProjectWeatherVo.java @@ -0,0 +1,68 @@ +package org.dromara.project.domain.vo.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/5/13 9:29 + */ +@Data +public class BusProjectWeatherVo implements Serializable { + + @Serial + private static final long serialVersionUID = 4173514725591666698L; + + /** + * 日期 + */ + private String date; + + /** + * 星期 + */ + private String week; + + /** + * 最高温度 + */ + private String tempMax; + + /** + * 最低温度 + */ + private String tempMin; + + /** + * 日出时间 + */ + private String sunRise; + + /** + * 日落时间 + */ + private String sunSet; + + /** + * 白天天气状态 + */ + private String dayStatus; + + /** + * 白天天气图标 + */ + private String dayIcon; + + /** + * 晚上天气状态 + */ + private String nightStatus; + + /** + * 晚上天气图标 + */ + private String nightIcon; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusSubProjectMatrixVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusSubProjectMatrixVo.java new file mode 100644 index 0000000..7bd0dbc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusSubProjectMatrixVo.java @@ -0,0 +1,35 @@ +package org.dromara.project.domain.vo.project; + +import lombok.Data; +import org.dromara.facility.domain.vo.matrix.FacMatrixBySubProjectVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/10 15:06 + */ +@Data +public class BusSubProjectMatrixVo implements Serializable { + + @Serial + private static final long serialVersionUID = 5817777295498328412L; + + /** + * id + */ + private Long projectId; + + /** + * 项目名称 + */ + private String name; + + /** + * 方阵列表 + */ + private List children; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusSubProjectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusSubProjectVo.java new file mode 100644 index 0000000..0d94715 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/project/BusSubProjectVo.java @@ -0,0 +1,39 @@ +package org.dromara.project.domain.vo.project; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/4 9:53 + */ +@Data +public class BusSubProjectVo implements Serializable { + + @Serial + private static final long serialVersionUID = -5283786195929619472L; + + /** + * id + */ + private Long id; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 设计文件id + */ + private Long designId; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectfile/BusProjectFileVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectfile/BusProjectFileVo.java new file mode 100644 index 0000000..4263d5a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectfile/BusProjectFileVo.java @@ -0,0 +1,40 @@ +package org.dromara.project.domain.vo.projectfile; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.project.domain.BusProjectFile; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 项目文件存储视图对象 bus_project_file + * + * @author lilemy + * @date 2025-04-23 + */ +@Data +@AutoMapper(target = BusProjectFile.class) +public class BusProjectFileVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 文件类型 + */ + private String fileType; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectnews/BusProjectNewsGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectnews/BusProjectNewsGisVo.java new file mode 100644 index 0000000..3ad0f56 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectnews/BusProjectNewsGisVo.java @@ -0,0 +1,33 @@ +package org.dromara.project.domain.vo.projectnews; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 14:11 + */ +@Data +public class BusProjectNewsGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -751096185387401970L; + + /** + * 主键 + */ + private Long id; + + /** + * 标题 + */ + private String title; + + /** + * 显示 + */ + private Boolean show; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectnews/BusProjectNewsVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectnews/BusProjectNewsVo.java new file mode 100644 index 0000000..735f583 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectnews/BusProjectNewsVo.java @@ -0,0 +1,50 @@ +package org.dromara.project.domain.vo.projectnews; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.project.domain.BusProjectNews; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 项目新闻视图对象 bus_project_news + * + * @author lilemy + * @date 2025-04-28 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusProjectNews.class) +public class BusProjectNewsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 标题 + */ + @ExcelProperty(value = "标题") + private String title; + + /** + * 内容 + */ + @ExcelProperty(value = "内容") + private String content; + + /** + * 附件 + */ + @ExcelProperty(value = "附件") + private String file; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusForemanVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusForemanVo.java new file mode 100644 index 0000000..9bf05a8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusForemanVo.java @@ -0,0 +1,26 @@ +package org.dromara.project.domain.vo.projectteam; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author lilemy + * @date 2025/4/11 16:37 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BusForemanVo { + + /** + * 班组长id + */ + private Long foremanId; + + /** + * 班组长名字 + */ + private String foremanName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusProjectTeamForemanVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusProjectTeamForemanVo.java new file mode 100644 index 0000000..865ee17 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusProjectTeamForemanVo.java @@ -0,0 +1,39 @@ +package org.dromara.project.domain.vo.projectteam; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/21 13:49 + */ +@Data +public class BusProjectTeamForemanVo implements Serializable { + + @Serial + private static final long serialVersionUID = -5655849857614630436L; + + /** + * 主键id + */ + private Long id; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组长列表 + */ + private List foremanList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusProjectTeamVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusProjectTeamVo.java new file mode 100644 index 0000000..98ec9f0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteam/BusProjectTeamVo.java @@ -0,0 +1,72 @@ +package org.dromara.project.domain.vo.projectteam; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.project.domain.BusProjectTeam; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 项目班组视图对象 bus_project_team + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusProjectTeam.class) +public class BusProjectTeamVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 班组名称 + */ + @ExcelProperty(value = "班组名称") + private String teamName; + + /** + * 范围内打卡(0范围内打卡 1任何地点打卡)默认为1 + */ + @ExcelProperty(value = "范围内打卡", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=范围内打卡,1=任何地点打卡") + private String isClockIn; + + /** + * 班组人数 + */ + private Long peopleNumber; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteammember/BusProjectTeamMemberVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteammember/BusProjectTeamMemberVo.java new file mode 100644 index 0000000..0ad92bc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/projectteammember/BusProjectTeamMemberVo.java @@ -0,0 +1,79 @@ +package org.dromara.project.domain.vo.projectteammember; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.project.domain.BusProjectTeamMember; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 项目班组下的成员视图对象 bus_project_team_member + * + * @author lilemy + * @date 2025-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusProjectTeamMember.class) +public class BusProjectTeamMemberVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 班组id + */ + @ExcelProperty(value = "班组id") + private Long teamId; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 施工人员id + */ + @ExcelProperty(value = "施工人员id") + private Long memberId; + + /** + * 施工人员名称 + */ + @ExcelProperty(value = "施工人员名称") + private String memberName; + + /** + * 岗位(默认为0普通员工,1组长) + */ + @ExcelProperty(value = "岗位", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "默认为0普通员工,1组长") + private String postId; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/reissuecard/BusReissueCardVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/reissuecard/BusReissueCardVo.java new file mode 100644 index 0000000..4f7b6eb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/reissuecard/BusReissueCardVo.java @@ -0,0 +1,143 @@ +package org.dromara.project.domain.vo.reissuecard; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.project.domain.BusReissueCard; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 施工人员补卡申请视图对象 bus_reissue_card + * + * @author lilemy + * @date 2025-04-08 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusReissueCard.class) +public class BusReissueCardVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + @ExcelProperty(value = "申请人名字") + private String userName; + + /** + * 申请补卡说明 + */ + @ExcelProperty(value = "申请补卡说明") + private String userExplain; + + /** + * 补卡申请时间 + */ + @ExcelProperty(value = "补卡申请时间") + private Date userTime; + + /** + * 项目id + */ + private Long teamId; + + /** + * 项目名字 + */ + private String teamName; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组长id + */ + private Long gangerId; + + /** + * 班组长名字 + */ + @ExcelProperty(value = "班组长名字") + private String gangerName; + + /** + * 班组长意见(1未读 2同意 3拒绝) + */ + @ExcelProperty(value = "班组长意见", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_opinion_type") + private String gangerOpinion; + + /** + * 班组长说明 + */ + @ExcelProperty(value = "班组长说明") + private String gangerExplain; + + /** + * 班组长操作时间 + */ + @ExcelProperty(value = "班组长操作时间") + private Date gangerTime; + + /** + * 管理员id + */ + private Long managerId; + + /** + * 管理员名字 + */ + private String managerName; + + /** + * 管理员意见(1未读 2同意 3拒绝) + */ + @ExcelProperty(value = "管理员意见", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_opinion_type") + private String managerOpinion; + + /** + * 管理员说明 + */ + @ExcelProperty(value = "管理员说明") + private String managerExplain; + + /** + * 管理员操作时间 + */ + @ExcelProperty(value = "管理员操作时间") + private Date managerTime; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 状态 + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/userprojectrelevancy/BusLoginUserProjectRelevancyVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/userprojectrelevancy/BusLoginUserProjectRelevancyVo.java new file mode 100644 index 0000000..30ba935 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/userprojectrelevancy/BusLoginUserProjectRelevancyVo.java @@ -0,0 +1,42 @@ +package org.dromara.project.domain.vo.userprojectrelevancy; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/5 15:30 + */ +@Data +public class BusLoginUserProjectRelevancyVo implements Serializable { + + @Serial + private static final long serialVersionUID = -2056438621566236671L; + + /** + * 主键ID + */ + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目简称 + */ + private String shortName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/userprojectrelevancy/BusUserProjectRelevancyVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/userprojectrelevancy/BusUserProjectRelevancyVo.java new file mode 100644 index 0000000..dd7dafe --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/userprojectrelevancy/BusUserProjectRelevancyVo.java @@ -0,0 +1,59 @@ +package org.dromara.project.domain.vo.userprojectrelevancy; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.project.domain.BusUserProjectRelevancy; +import org.dromara.project.domain.vo.project.BusProjectVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 系统用户与项目关联视图对象 user_project_relevancy + * + * @author lilemy + * @date 2025-03-04 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusUserProjectRelevancy.class) +public class BusUserProjectRelevancyVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户ID") + private Long userId; + + /** + * 项目ID + */ + @ExcelProperty(value = "项目ID") + private Long projectId; + + /** + * 项目详情 + */ + @ExcelProperty(value = "项目详情") + private BusProjectVo project; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/workerdailyreport/BusWorkerDailyReportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/workerdailyreport/BusWorkerDailyReportVo.java new file mode 100644 index 0000000..c738fe6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/workerdailyreport/BusWorkerDailyReportVo.java @@ -0,0 +1,116 @@ +package org.dromara.project.domain.vo.workerdailyreport; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.project.domain.BusWorkerDailyReport; +import org.dromara.project.domain.vo.dailypieceitem.BusDailyPieceItemVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 施工人员日报视图对象 bus_worker_daily_report + * + * @author lilemy + * @date 2025-04-09 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusWorkerDailyReport.class) +public class BusWorkerDailyReportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 班组id + */ + private Long teamId; + + /** + * 班组名字 + */ + private String teamName; + + /** + * 申请人id + */ + private Long userId; + + /** + * 申请人名字 + */ + @ExcelProperty(value = "申请人名字") + private String userName; + + /** + * 今日完成工作 + */ + @ExcelProperty(value = "今日完成工作") + private String todayCompletedWork; + + /** + * 未完成工作 + */ + @ExcelProperty(value = "未完成工作") + private String unfinishedWork; + + /** + * 明日工作 + */ + @ExcelProperty(value = "明日工作") + private String tomorrowWork; + + /** + * 需协调与帮助 + */ + @ExcelProperty(value = "需协调与帮助") + private String coordinationHelp; + + /** + * 是否为补卡(1不是 2是) + */ + private Long isResubmit; + + /** + * 补交理由 + */ + @ExcelProperty(value = "补交理由") + private String resubmitReason; + + /** + * 日报日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd", + timezone = "GMT+8") + @ExcelProperty(value = "打卡日期") + private Date reportDate; + + /** + * 附件 + */ + private List fileList; + + /** + * 附件id + */ + private String file; + + /** + * 日报明细 + */ + private List dailyPieceItemVoList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/workwage/BusWorkWageVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/workwage/BusWorkWageVo.java new file mode 100644 index 0000000..54f2c20 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/workwage/BusWorkWageVo.java @@ -0,0 +1,88 @@ +package org.dromara.project.domain.vo.workwage; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.project.domain.BusWorkWage; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 工种薪水视图对象 bus_work_wage + * + * @author lilemy + * @date 2025-03-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BusWorkWage.class) +public class BusWorkWageVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 工种 + */ + @ExcelProperty(value = "工种", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "type_of_work") + private String workType; + + /** + * 是否是特种兵(1是 2否) + */ + @ExcelProperty(value = "是否是特种兵", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=是,2=否") + private String isSpecialType; + + /** + * 工资计算方式(1计时 2计件) + */ + @ExcelProperty(value = "工资计算方式", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=计时,2=计件") + private String wageCalculationType; + + /** + * 工资标准 + */ + @ExcelProperty(value = "工资标准") + private Long wage; + + /** + * 工资计量单位 + */ + @ExcelProperty(value = "工资计量单位", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "wage_measure_unit_type") + private String wageMeasureUnit; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java new file mode 100644 index 0000000..b15b1e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusAttendanceMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.vo.attendance.BusAttendanceVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 考勤Mapper接口 + * + * @author lilemy + * @date 2025-04-07 + */ +public interface BusAttendanceMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusConstructionBlacklistMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusConstructionBlacklistMapper.java new file mode 100644 index 0000000..5efeefb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusConstructionBlacklistMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusConstructionBlacklist; +import org.dromara.project.domain.vo.constructionblacklist.BusConstructionBlacklistVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 黑名单Mapper接口 + * + * @author lilemy + * @date 2025-03-27 + */ +public interface BusConstructionBlacklistMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusConstructionUserExitMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusConstructionUserExitMapper.java new file mode 100644 index 0000000..5812fd8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusConstructionUserExitMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusConstructionUserExit; +import org.dromara.project.domain.vo.constructionuserexit.BusConstructionUserExitVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 施工人员入场退场记录信息Mapper接口 + * + * @author lilemy + * @date 2025-03-31 + */ +public interface BusConstructionUserExitMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusDailyPieceItemMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusDailyPieceItemMapper.java new file mode 100644 index 0000000..8542928 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusDailyPieceItemMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusDailyPieceItem; +import org.dromara.project.domain.vo.dailypieceitem.BusDailyPieceItemVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 施工人员日报计件信息Mapper接口 + * + * @author lilemy + * @date 2025-04-09 + */ +public interface BusDailyPieceItemMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusLeaveMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusLeaveMapper.java new file mode 100644 index 0000000..0a28aea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusLeaveMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusLeave; +import org.dromara.project.domain.vo.leave.BusLeaveVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 施工人员请假申请Mapper接口 + * + * @author lilemy + * @date 2025-04-08 + */ +public interface BusLeaveMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectFileMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectFileMapper.java new file mode 100644 index 0000000..bb531a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectFileMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusProjectFile; +import org.dromara.project.domain.vo.projectfile.BusProjectFileVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目文件存储Mapper接口 + * + * @author lilemy + * @date 2025-04-23 + */ +public interface BusProjectFileMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectMapper.java new file mode 100644 index 0000000..d8b7bfc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.vo.project.BusProjectVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目Mapper接口 + * + * @author lilemy + * @date 2025-03-04 + */ +public interface BusProjectMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectNewsMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectNewsMapper.java new file mode 100644 index 0000000..4137fda --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectNewsMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusProjectNews; +import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目新闻Mapper接口 + * + * @author lilemy + * @date 2025-04-28 + */ +public interface BusProjectNewsMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectTeamMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectTeamMapper.java new file mode 100644 index 0000000..ee74553 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectTeamMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目班组Mapper接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface BusProjectTeamMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectTeamMemberMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectTeamMemberMapper.java new file mode 100644 index 0000000..48730e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusProjectTeamMemberMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.project.domain.vo.projectteammember.BusProjectTeamMemberVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目班组下的成员Mapper接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface BusProjectTeamMemberMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusReissueCardMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusReissueCardMapper.java new file mode 100644 index 0000000..558b042 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusReissueCardMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusReissueCard; +import org.dromara.project.domain.vo.reissuecard.BusReissueCardVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 施工人员补卡申请Mapper接口 + * + * @author lilemy + * @date 2025-04-08 + */ +public interface BusReissueCardMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusUserProjectRelevancyMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusUserProjectRelevancyMapper.java new file mode 100644 index 0000000..ddf7304 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusUserProjectRelevancyMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusUserProjectRelevancy; +import org.dromara.project.domain.vo.userprojectrelevancy.BusUserProjectRelevancyVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 系统用户与项目关联Mapper接口 + * + * @author lilemy + * @date 2025-03-04 + */ +public interface BusUserProjectRelevancyMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusWorkWageMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusWorkWageMapper.java new file mode 100644 index 0000000..e148d87 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusWorkWageMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusWorkWage; +import org.dromara.project.domain.vo.workwage.BusWorkWageVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 工种薪水Mapper接口 + * + * @author lilemy + * @date 2025-03-26 + */ +public interface BusWorkWageMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusWorkerDailyReportMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusWorkerDailyReportMapper.java new file mode 100644 index 0000000..8d73cc1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/mapper/BusWorkerDailyReportMapper.java @@ -0,0 +1,15 @@ +package org.dromara.project.mapper; + +import org.dromara.project.domain.BusWorkerDailyReport; +import org.dromara.project.domain.vo.workerdailyreport.BusWorkerDailyReportVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 施工人员日报Mapper接口 + * + * @author lilemy + * @date 2025-04-09 + */ +public interface BusWorkerDailyReportMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java new file mode 100644 index 0000000..c0a35a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusAttendanceService.java @@ -0,0 +1,99 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.dto.attendance.BusAttendanceMonthByUserIdReq; +import org.dromara.project.domain.dto.attendance.BusAttendanceQueryReq; +import org.dromara.project.domain.dto.attendance.BusAttendanceQueryTwoWeekReq; +import org.dromara.project.domain.vo.attendance.BusAttendanceClockDateForTwoWeekVo; +import org.dromara.project.domain.vo.attendance.BusAttendanceMonthByUserIdVo; +import org.dromara.project.domain.vo.attendance.BusAttendanceVo; + +import java.util.List; + +/** + * 考勤Service接口 + * + * @author lilemy + * @date 2025-04-07 + */ +public interface IBusAttendanceService extends IService { + + /** + * 查询考勤 + * + * @param id 主键 + * @return 考勤 + */ + BusAttendanceVo queryById(Long id); + + /** + * 分页查询考勤列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 考勤分页列表 + */ + TableDataInfo queryPageList(BusAttendanceQueryReq req, PageQuery pageQuery); + + /** + * 查询两周内的考勤列表 + * + * @param req 查询条件 + * @return 考勤列表 + */ + List listClockDateForTwoWeek(BusAttendanceQueryTwoWeekReq req); + + /** + * 查询用户每月考勤列表 + * + * @param req 查询条件 + * @return 考勤列表 + */ + List listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req); + + /** + * 查询符合条件的考勤列表 + * + * @param req 查询条件 + * @return 考勤列表 + */ + List queryList(BusAttendanceQueryReq req); + + /** + * 根据项目id查询出勤人列表 + * + * @param projectId 项目id + * @return 出勤人列表 + */ + List listAttendancePeopleByProjectId(Long projectId); + + /** + * 获取考勤视图对象 + * + * @param attendance 考勤对象 + * @return 考勤视图对象 + */ + BusAttendanceVo getVo(BusAttendance attendance); + + /** + * 获取考勤查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusAttendanceQueryReq req); + + /** + * 获取考勤分页对象视图 + * + * @param attendancePage 考勤分页对象 + * @return 考勤分页对象视图 + */ + Page getVoPage(Page attendancePage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionBlacklistService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionBlacklistService.java new file mode 100644 index 0000000..5ef8631 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionBlacklistService.java @@ -0,0 +1,88 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusConstructionBlacklist; +import org.dromara.project.domain.dto.constructionblacklist.BusConstructionBlacklistCreateReq; +import org.dromara.project.domain.dto.constructionblacklist.BusConstructionBlacklistQueryReq; +import org.dromara.project.domain.vo.constructionblacklist.BusConstructionBlacklistVo; + +import java.util.Collection; +import java.util.List; + +/** + * 黑名单Service接口 + * + * @author lilemy + * @date 2025-03-27 + */ +public interface IBusConstructionBlacklistService extends IService { + + /** + * 查询黑名单 + * + * @param id 主键 + * @return 黑名单 + */ + BusConstructionBlacklistVo queryById(Long id); + + /** + * 分页查询黑名单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 黑名单分页列表 + */ + TableDataInfo queryPageList(BusConstructionBlacklistQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的黑名单列表 + * + * @param req 查询条件 + * @return 黑名单列表 + */ + List queryList(BusConstructionBlacklistQueryReq req); + + /** + * 根据项目id查询黑名单用户id列表 + * + * @param projectId 项目id + * @return 黑名单用户id列表 + */ + List queryIdListByProjectId(Long projectId); + + /** + * 新增黑名单 + * + * @param req 黑名单 + * @return 是否新增成功 + */ + Long insertByBo(BusConstructionBlacklistCreateReq req); + + /** + * 校验并批量删除黑名单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 校验用户是否在黑名单中 + * + * @param userId 用户id + * @param projectId 项目id + */ + void validUserInBlacklist(Long userId, Long projectId); + + /** + * 获取黑名单查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusConstructionBlacklistQueryReq req); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserExitService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserExitService.java new file mode 100644 index 0000000..22aded9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserExitService.java @@ -0,0 +1,71 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusConstructionUserExit; +import org.dromara.project.domain.dto.constructionuserexit.BusConstructionUserExitQueryReq; +import org.dromara.project.domain.vo.constructionuserexit.BusConstructionUserExitVo; + +import java.util.List; + +/** + * 施工人员入场退场记录信息Service接口 + * + * @author lilemy + * @date 2025-03-31 + */ +public interface IBusConstructionUserExitService extends IService { + + /** + * 查询施工人员入场退场记录信息 + * + * @param id 主键 + * @return 施工人员入场退场记录信息 + */ + BusConstructionUserExitVo queryById(Long id); + + /** + * 分页查询施工人员入场退场记录信息列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员入场退场记录信息分页列表 + */ + TableDataInfo queryPageList(BusConstructionUserExitQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的施工人员入场退场记录信息列表 + * + * @param req 查询条件 + * @return 施工人员入场退场记录信息列表 + */ + List queryList(BusConstructionUserExitQueryReq req); + + /** + * 获取施工人员入场退场记录视图对象 + * + * @param constructionUserExit 施工人员入场退场记录对象 + * @return 施工人员入场退场记录视图对象 + */ + BusConstructionUserExitVo getVo(BusConstructionUserExit constructionUserExit); + + /** + * 获取施工人员入场退场记录信息查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusConstructionUserExitQueryReq req); + + /** + * 获取施工人员入场退场记录分页对象视图 + * + * @param constructionUserExitPage 施工人员入场退场记录分页对象 + * @return 施工人员入场退场记录分页对象视图 + */ + Page getVoPage(Page constructionUserExitPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusDailyPieceItemService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusDailyPieceItemService.java new file mode 100644 index 0000000..e0ee023 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusDailyPieceItemService.java @@ -0,0 +1,33 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.project.domain.BusDailyPieceItem; +import org.dromara.project.domain.vo.dailypieceitem.BusDailyPieceItemVo; + +import java.util.List; + +/** + * 施工人员日报计件信息Service接口 + * + * @author lilemy + * @date 2025-04-09 + */ +public interface IBusDailyPieceItemService extends IService { + + /** + * 施工人员日报计件信息封装 + * + * @param dailyPieceItem 施工人员日报计件信息 + * @return 施工人员日报计件信息封装 + */ + BusDailyPieceItemVo getVo(BusDailyPieceItem dailyPieceItem); + + /** + * 施工人员日报计件信息列表封装 + * + * @param dailyPieceItemList 施工人员日报计件信息列表 + * @return 施工人员日报计件信息列表封装 + */ + List getListVo(List dailyPieceItemList); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusLeaveService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusLeaveService.java new file mode 100644 index 0000000..c6d4d00 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusLeaveService.java @@ -0,0 +1,90 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusLeave; +import org.dromara.project.domain.dto.leave.BusLeaveManagerReviewReq; +import org.dromara.project.domain.dto.leave.BusLeaveQueryReq; +import org.dromara.project.domain.vo.leave.BusLeaveVo; + +import java.util.Collection; +import java.util.List; + +/** + * 施工人员请假申请Service接口 + * + * @author lilemy + * @date 2025-04-08 + */ +public interface IBusLeaveService extends IService { + + /** + * 查询施工人员请假申请 + * + * @param id 主键 + * @return 施工人员请假申请 + */ + BusLeaveVo queryById(Long id); + + /** + * 分页查询施工人员请假申请列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员请假申请分页列表 + */ + TableDataInfo queryPageList(BusLeaveQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的施工人员请假申请列表 + * + * @param req 查询条件 + * @return 施工人员请假申请列表 + */ + List queryList(BusLeaveQueryReq req); + + /** + * 管理员审核施工人员请假申请 + * + * @param req 管理员审核施工人员请假申请 + * @return 是否审核成功 + */ + Boolean managerReview(BusLeaveManagerReviewReq req); + + /** + * 校验并批量删除施工人员请假申请信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取施工人员请假申请视图对象 + * + * @param leave 施工人员请假申请对象 + * @return 施工人员请假申请视图对象 + */ + BusLeaveVo getVo(BusLeave leave); + + /** + * 获取施工人员请假申请查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusLeaveQueryReq req); + + /** + * 获取施工人员请假申请分页对象视图 + * + * @param leavePage 施工人员请假申请分页对象 + * @return 施工人员请假申请分页对象视图 + */ + Page getVoPage(Page leavePage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectFileService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectFileService.java new file mode 100644 index 0000000..18d181b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectFileService.java @@ -0,0 +1,110 @@ +package org.dromara.project.service; + +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusProjectFile; +import org.dromara.project.domain.dto.projectfile.BusProjectFileQueryReq; +import org.dromara.project.domain.dto.projectfile.BusProjectFileUpdateReq; +import org.dromara.project.domain.dto.projectfile.BusProjectFileUploadDxfReq; +import org.dromara.project.domain.vo.projectfile.BusProjectFileVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; + +/** + * 项目文件存储Service接口 + * + * @author lilemy + * @date 2025-04-23 + */ +public interface IBusProjectFileService extends IService { + + /** + * 查询项目文件存储 + * + * @param id 主键 + * @return 项目文件存储 + */ + BusProjectFileVo queryById(Long id); + + /** + * 分页查询项目文件存储列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目文件存储分页列表 + */ + TableDataInfo queryPageList(BusProjectFileQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的项目文件存储列表 + * + * @param req 查询条件 + * @return 项目文件存储列表 + */ + List queryList(BusProjectFileQueryReq req); + + /** + * 修改项目文件存储 + * + * @param req 项目文件存储 + * @return 是否修改成功 + */ + Boolean updateByBo(BusProjectFileUpdateReq req); + + /** + * 校验并批量删除项目文件存储信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据id获取JSON文件 + * + * @param id 主键 + * @return JSON文件 + */ + JSONObject getJSONFile(Long id); + + /** + * 上传dxf文件并转换为json + * + * @param file 文件 + * @param req 请求 + * @return 是否上传文件成功 + */ + Boolean uploadDxf2Json(MultipartFile file, BusProjectFileUploadDxfReq req); + + /** + * 获取项目文件存储视图对象 + * + * @param projectFile 项目文件存储对象 + * @return 项目文件存储视图对象 + */ + BusProjectFileVo getVo(BusProjectFile projectFile); + + /** + * 获取项目文件存储查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusProjectFileQueryReq req); + + /** + * 获取项目文件存储分页对象视图 + * + * @param projectFilePage 项目文件存储分页对象 + * @return 项目文件存储分页对象视图 + */ + Page getVoPage(Page projectFilePage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectNewsService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectNewsService.java new file mode 100644 index 0000000..97bfa3b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectNewsService.java @@ -0,0 +1,109 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusProjectNews; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsCreateReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsGisReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsQueryReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsUpdateReq; +import org.dromara.project.domain.vo.projectnews.BusProjectNewsGisVo; +import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo; + +import java.util.Collection; +import java.util.List; + +/** + * 项目新闻Service接口 + * + * @author lilemy + * @date 2025-04-28 + */ +public interface IBusProjectNewsService extends IService { + + /** + * 查询项目新闻 + * + * @param id 主键 + * @return 项目新闻 + */ + BusProjectNewsVo queryById(Long id); + + /** + * 分页查询项目新闻列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目新闻分页列表 + */ + TableDataInfo queryPageList(BusProjectNewsQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的项目新闻列表 + * + * @param req 查询条件 + * @return 项目新闻列表 + */ + List queryList(BusProjectNewsQueryReq req); + + /** + * 查询大屏项目新闻列表 + * + * @param req 列表查询条件 + * @return 大屏项目新闻列表 + */ + List queryGisList(BusProjectNewsGisReq req); + + /** + * 新增项目新闻 + * + * @param req 项目新闻 + * @return 新增项目新闻id + */ + Long insertByBo(BusProjectNewsCreateReq req); + + /** + * 修改项目新闻 + * + * @param req 项目新闻 + * @return 是否修改成功 + */ + Boolean updateByBo(BusProjectNewsUpdateReq req); + + /** + * 校验并批量删除项目新闻信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取项目新闻存储视图对象 + * + * @param projectNews 项目新闻存储对象 + * @return 项目新闻存储视图对象 + */ + BusProjectNewsVo getVo(BusProjectNews projectNews); + + /** + * 获取项目新闻存储查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusProjectNewsQueryReq req); + + /** + * 获取项目新闻存储分页对象视图 + * + * @param projectNewsPage 项目新闻存储分页对象 + * @return 项目新闻存储分页对象视图 + */ + Page getVoPage(Page projectNewsPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectService.java new file mode 100644 index 0000000..9cb41bd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectService.java @@ -0,0 +1,179 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.dto.project.BusProjectCreateReq; +import org.dromara.project.domain.dto.project.BusProjectCreateSubReq; +import org.dromara.project.domain.dto.project.BusProjectQueryReq; +import org.dromara.project.domain.dto.project.BusProjectUpdateReq; +import org.dromara.project.domain.vo.project.*; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * 项目Service接口 + * + * @author lilemy + * @date 2025-03-04 + */ +public interface IBusProjectService extends IService { + + /** + * 查询项目 + * + * @param id 主键 + * @return 项目 + */ + BusProjectVo queryById(Long id); + + /** + * 分页查询项目列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目分页列表 + */ + TableDataInfo queryPageList(BusProjectQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的项目列表 + * + * @param req 查询条件 + * @return 项目列表 + */ + List queryList(BusProjectQueryReq req); + + /** + * 查询未绑定部门的项目列表(不查询子项目) + * + * @return 项目列表 + */ + List queryListNoDept(); + + /** + * 查询项目下的子项目列表 + * + * @param id 父项目id + * @return 项目下的子项目列表 + */ + List querySubList(Long id); + + /** + * 获取项目子项目方阵信息 + * + * @param id 项目id + * @return 子项目方阵信息列表 + */ + List querySubProjectMatrixList(Long id); + + /** + * 查询当前登录用户项目列表以及项目列表下的分包公司列表 + * + * @return 项目列表以及项目列表下的分包公司列表 + */ + List queryProjectContractorList(); + + /** + * 新增项目 + * + * @param dto 项目 + * @return 新项目 id + */ + Long insertByBo(BusProjectCreateReq dto); + + /** + * 新增子项目 + * + * @param dto 子项目 + * @return 子项目 id + */ + Long insertSubByProject(BusProjectCreateSubReq dto); + + /** + * 创建项目需同步的事务 + * + * @param id 项目id + * @return 是否同步成功 + */ + CompletableFuture insertProjectSyncThing(Long id); + + /** + * 修改项目 + * + * @param req 项目 + * @return 是否修改成功 + */ + Boolean updateByBo(BusProjectUpdateReq req); + + /** + * 校验并批量删除项目信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取项目视图对象 + * + * @param project 项目对象 + * @return 项目视图对象 + */ + BusProjectVo getVo(BusProject project); + + /** + * 获取项目查询条件封装(不查询子项目) + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusProjectQueryReq req); + + /** + * 获取项目分页对象视图 + * + * @param projectPage 项目分页对象 + * @return 项目分页对象视图 + */ + Page getVoPage(Page projectPage); + + /** + * 校验用户是否拥有操作项目的权限 + * + * @param projectId 项目id + * @param userId 需要鉴权的用户id + */ + void validAuth(Long projectId, Long userId); + + /** + * 校验用户是否拥有操作项目的权限 + * + * @param projectIdList 项目id列表 + * @param userId 需要鉴权的用户id + */ + void validAuth(Collection projectIdList, Long userId); + + /** + * 获取天气信息 + * + * @param id 项目id + * @return 天气信息列表 + */ + List getWeather(Long id); + + /** + * 获取项目安全天数 + * + * @param id 项目id + * @return 安全天数 + */ + BusProjectSafetyDayVo getSafetyDay(Long id); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectTeamMemberService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectTeamMemberService.java new file mode 100644 index 0000000..1f55e8e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectTeamMemberService.java @@ -0,0 +1,97 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberCreateReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberExitReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberQueryReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberUpdateReq; +import org.dromara.project.domain.vo.projectteammember.BusProjectTeamMemberVo; + +import java.util.List; + +/** + * 项目班组下的成员Service接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface IBusProjectTeamMemberService extends IService { + + /** + * 查询项目班组下的成员 + * + * @param id 主键 + * @return 项目班组下的成员 + */ + BusProjectTeamMemberVo queryById(Long id); + + /** + * 分页查询项目班组下的成员列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目班组下的成员分页列表 + */ + TableDataInfo queryPageList(BusProjectTeamMemberQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的项目班组下的成员列表 + * + * @param req 查询条件 + * @return 项目班组下的成员列表 + */ + List queryList(BusProjectTeamMemberQueryReq req); + + /** + * 新增项目班组下的成员 + * + * @param req 项目班组下的成员 + * @return 是否新增成功 + */ + Long insertByBo(BusProjectTeamMemberCreateReq req); + + /** + * 修改项目班组下的成员 + * + * @param req 项目班组下的成员 + * @return 是否修改成功 + */ + Boolean updateByBo(BusProjectTeamMemberUpdateReq req); + + /** + * 根据主键删除项目班组与人员关联(人员退场) + * + * @param req 班组人员退场对象 + * @return 是否删除成功 + */ + Boolean deleteById(BusProjectTeamMemberExitReq req); + + /** + * 获取项目班组成员视图对象 + * + * @param projectTeamMember 项目班组成员对象 + * @return 项目班组成员视图对象 + */ + BusProjectTeamMemberVo getVo(BusProjectTeamMember projectTeamMember); + + /** + * 获取项目班组成员查询条件封装 + * + * @param req 项目班组成员查询条件 + * @return 项目班组成员查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusProjectTeamMemberQueryReq req); + + /** + * 获取项目班组成员分页对象视图 + * + * @param projectTeamMemberPage 项目班组成员分页对象 + * @return 项目班组成员分页对象视图 + */ + Page getVoPage(Page projectTeamMemberPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectTeamService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectTeamService.java new file mode 100644 index 0000000..ad69c29 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectTeamService.java @@ -0,0 +1,107 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamCreateReq; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamUpdateReq; +import org.dromara.project.domain.vo.projectteam.BusProjectTeamForemanVo; +import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo; + +import java.util.Collection; +import java.util.List; + +/** + * 项目班组Service接口 + * + * @author lilemy + * @date 2025-03-07 + */ +public interface IBusProjectTeamService extends IService { + + /** + * 查询项目班组 + * + * @param id 主键 + * @return 项目班组 + */ + BusProjectTeamVo queryById(Long id); + + /** + * 分页查询项目班组列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目班组分页列表 + */ + TableDataInfo queryPageList(BusProjectTeamQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的项目班组列表 + * + * @param req 查询条件 + * @return 项目班组列表 + */ + List queryList(BusProjectTeamQueryReq req); + + /** + * 新增项目班组 + * + * @param req 项目班组 + * @return 是否新增成功 + */ + Long insertByBo(BusProjectTeamCreateReq req); + + /** + * 修改项目班组 + * + * @param req 项目班组 + * @return 是否修改成功 + */ + Boolean updateByBo(BusProjectTeamUpdateReq req); + + /** + * 校验并批量删除项目班组信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 查询项目班组和班组长分页列表 + * + * @param projectId 项目id + * @return 项目班组和班组长分页列表 + */ + List queryForemanList(Long projectId); + + /** + * 获取项目班组视图对象 + * + * @param projectTeam 项目班组对象 + * @return 项目班组视图对象 + */ + BusProjectTeamVo getVo(BusProjectTeam projectTeam); + + /** + * 获取项目班组查询条件封装 + * + * @param req 项目班组查询条件 + * @return 项目班组查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusProjectTeamQueryReq req); + + /** + * 获取项目班组分页对象视图 + * + * @param projectTeamPage 项目班组分页对象 + * @return 项目班组分页对象视图 + */ + Page getVoPage(Page projectTeamPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusReissueCardService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusReissueCardService.java new file mode 100644 index 0000000..317cc6e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusReissueCardService.java @@ -0,0 +1,90 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusReissueCard; +import org.dromara.project.domain.dto.reissuecard.BusReissueCardManagerReviewReq; +import org.dromara.project.domain.dto.reissuecard.BusReissueCardQueryReq; +import org.dromara.project.domain.vo.reissuecard.BusReissueCardVo; + +import java.util.Collection; +import java.util.List; + +/** + * 施工人员补卡申请Service接口 + * + * @author lilemy + * @date 2025-04-08 + */ +public interface IBusReissueCardService extends IService { + + /** + * 查询施工人员补卡申请 + * + * @param id 主键 + * @return 施工人员补卡申请 + */ + BusReissueCardVo queryById(Long id); + + /** + * 分页查询施工人员补卡申请列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员补卡申请分页列表 + */ + TableDataInfo queryPageList(BusReissueCardQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的施工人员补卡申请列表 + * + * @param req 查询条件 + * @return 施工人员补卡申请列表 + */ + List queryList(BusReissueCardQueryReq req); + + /** + * 管理员审核施工人员补卡申请 + * + * @param req 管理员审核施工人员补卡申请 + * @return 是否审核成功 + */ + Boolean managerReview(BusReissueCardManagerReviewReq req); + + /** + * 校验并批量删除施工人员补卡申请信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取施工人员补卡申请视图对象 + * + * @param reissueCard 施工人员补卡申请对象 + * @return 施工人员补卡申请视图对象 + */ + BusReissueCardVo getVo(BusReissueCard reissueCard); + + /** + * 获取施工人员补卡申请查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusReissueCardQueryReq req); + + /** + * 获取施工人员补卡申请分页对象视图 + * + * @param reissueCardPage 施工人员补卡申请分页对象 + * @return 施工人员补卡申请分页对象视图 + */ + Page getVoPage(Page reissueCardPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusUserProjectRelevancyService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusUserProjectRelevancyService.java new file mode 100644 index 0000000..e4b49f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusUserProjectRelevancyService.java @@ -0,0 +1,158 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusUserProjectRelevancy; +import org.dromara.project.domain.dto.project.BusProjectBatchByProjectListReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyCreateReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyQueryReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyUpdateReq; +import org.dromara.project.domain.vo.userprojectrelevancy.BusLoginUserProjectRelevancyVo; +import org.dromara.project.domain.vo.userprojectrelevancy.BusUserProjectRelevancyVo; + +import java.util.Collection; +import java.util.List; + +/** + * 系统用户与项目关联Service接口 + * + * @author lilemy + * @date 2025-03-04 + */ +public interface IBusUserProjectRelevancyService extends IService { + + /** + * 查询系统用户与项目关联 + * + * @param id 主键 + * @return 系统用户与项目关联 + */ + BusUserProjectRelevancyVo queryById(Long id); + + /** + * 分页查询系统用户与项目关联列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 系统用户与项目关联分页列表 + */ + TableDataInfo queryPageList(BusUserProjectRelevancyQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的系统用户与项目关联列表 + * + * @param req 查询条件 + * @return 系统用户与项目关联列表 + */ + List queryList(BusUserProjectRelevancyQueryReq req); + + /** + * 新增系统用户与项目关联 + * + * @param req 系统用户与项目关联 + * @return 新增关联id + */ + Long insertByBo(BusUserProjectRelevancyCreateReq req); + + /** + * 批量新增用户和项目关联 + * + * @param projectId 项目ID + * @param userIdList 用户ID列表 + */ + void saveBatchByUserList(Long projectId, List userIdList); + + /** + * 批量新增用户和项目关联 + * + * @param projectIdList 项目ID列表 + * @param userId 用户ID + */ + void saveBatchByProjectList(List projectIdList, Long userId); + + /** + * 修改系统用户与项目关联 + * + * @param req 系统用户与项目关联 + * @return 是否修改成功 + */ + Boolean updateByBo(BusUserProjectRelevancyUpdateReq req); + + /** + * 校验并批量删除系统用户与项目关联信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据用户ID删除系统用户与项目关联 + * + * @param userId 用户ID + */ + void deleteByUserId(Long userId); + + /** + * 根据项目ID和用户ID列表删除系统用户与项目关联 + * + * @param oldProjectId 项目ID + * @param userIds 用户ID列表 + */ + void deleteByProjectAndUserIds(Long oldProjectId, List userIds); + + /** + * 获取当前登录用户项目列表 + * + * @param userId 登录用户ID + * @return 当前登录用户项目列表 + */ + List queryListByUserId(Long userId); + + /** + * 获取当前登录用户项目分页 + * + * @param userId 登录用户ID + * @param req 分页查询条件 + * @param pageQuery 分页参数 + * @return 当前登录用户项目分页 + */ + TableDataInfo queryPageByUserId(Long userId, BusUserProjectRelevancyQueryReq req, PageQuery pageQuery); + + /** + * 批量新增用户和项目关联 + * + * @param req 新增参数 + * @return 是否增加成功 + */ + Boolean insertBatchByProjectList(BusProjectBatchByProjectListReq req); + + /** + * 获取系统用户与项目关联视图 + * + * @param userProjectRelevancy 系统用户与项目关联 + * @return 系统用户与项目关联视图 + */ + BusUserProjectRelevancyVo getVo(BusUserProjectRelevancy userProjectRelevancy); + + /** + * 获取用户和项目关联对象查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusUserProjectRelevancyQueryReq req); + + /** + * 获取系统用户与项目关联分页视图 + * + * @param userProjectRelevancyPage 系统用户与项目关联分页 + * @return 系统用户与项目关联分页视图 + */ + Page getVoPage(Page userProjectRelevancyPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusWorkWageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusWorkWageService.java new file mode 100644 index 0000000..e3ac966 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusWorkWageService.java @@ -0,0 +1,98 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusWorkWage; +import org.dromara.project.domain.dto.workwage.BusWorkWageCreateReq; +import org.dromara.project.domain.dto.workwage.BusWorkWageQueryReq; +import org.dromara.project.domain.dto.workwage.BusWorkWageUpdateReq; +import org.dromara.project.domain.vo.workwage.BusWorkWageVo; + +import java.util.Collection; +import java.util.List; + +/** + * 工种薪水Service接口 + * + * @author lilemy + * @date 2025-03-26 + */ +public interface IBusWorkWageService extends IService { + + /** + * 查询工种薪水 + * + * @param id 主键 + * @return 工种薪水 + */ + BusWorkWageVo queryById(Long id); + + /** + * 分页查询工种薪水列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 工种薪水分页列表 + */ + TableDataInfo queryPageList(BusWorkWageQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的工种薪水列表 + * + * @param req 查询条件 + * @return 工种薪水列表 + */ + List queryList(BusWorkWageQueryReq req); + + /** + * 新增工种薪水 + * + * @param req 工种薪水 + * @return 新增工种薪水id + */ + Long insertByBo(BusWorkWageCreateReq req); + + /** + * 修改工种薪水 + * + * @param req 工种薪水 + * @return 是否修改成功 + */ + Boolean updateByBo(BusWorkWageUpdateReq req); + + /** + * 校验并批量删除工种薪水信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取工种薪水视图对象 + * + * @param workWage 工种薪水对象 + * @return 工种薪水视图对象 + */ + BusWorkWageVo getVo(BusWorkWage workWage); + + /** + * 获取工种薪水查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusWorkWageQueryReq req); + + /** + * 获取工种薪水分页对象视图 + * + * @param workWagePage 工种薪水分页对象 + * @return 工种薪水分页对象视图 + */ + Page getVoPage(Page workWagePage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusWorkerDailyReportService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusWorkerDailyReportService.java new file mode 100644 index 0000000..e45b9f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusWorkerDailyReportService.java @@ -0,0 +1,81 @@ +package org.dromara.project.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusWorkerDailyReport; +import org.dromara.project.domain.dto.workerdailyreport.BusWorkerDailyReportQueryReq; +import org.dromara.project.domain.vo.workerdailyreport.BusWorkerDailyReportVo; + +import java.util.Collection; +import java.util.List; + +/** + * 施工人员日报Service接口 + * + * @author lilemy + * @date 2025-04-09 + */ +public interface IBusWorkerDailyReportService extends IService { + + /** + * 查询施工人员日报 + * + * @param id 主键 + * @return 施工人员日报 + */ + BusWorkerDailyReportVo queryById(Long id); + + /** + * 分页查询施工人员日报列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员日报分页列表 + */ + TableDataInfo queryPageList(BusWorkerDailyReportQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的施工人员日报列表 + * + * @param req 查询条件 + * @return 施工人员日报列表 + */ + List queryList(BusWorkerDailyReportQueryReq req); + + /** + * 校验并批量删除施工人员日报信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取施工人员日报列表视图对象 + * + * @param workerDailyReport 施工人员日报列表对象 + * @return 施工人员日报列表视图对象 + */ + BusWorkerDailyReportVo getVo(BusWorkerDailyReport workerDailyReport); + + /** + * 获取施工人员日报列表查询条件封装 + * + * @param req 施工人员日报列表查询条件 + * @return 施工人员日报列表查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(BusWorkerDailyReportQueryReq req); + + /** + * 获取施工人员日报列表分页对象视图 + * + * @param workerDailyReportPage 施工人员日报列表分页对象 + * @return 施工人员日报列表分页对象视图 + */ + Page getVoPage(Page workerDailyReportPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java new file mode 100644 index 0000000..2a792da --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusAttendanceServiceImpl.java @@ -0,0 +1,407 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.DateConstant; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.enums.FormatsType; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum; +import org.dromara.project.domain.enums.BusAttendanceCommuterEnum; +import org.dromara.project.domain.enums.BusAttendanceStatusEnum; +import org.dromara.project.domain.dto.attendance.BusAttendanceMonthByUserIdReq; +import org.dromara.project.domain.dto.attendance.BusAttendanceQueryReq; +import org.dromara.project.domain.dto.attendance.BusAttendanceQueryTwoWeekReq; +import org.dromara.project.domain.vo.attendance.BusAttendanceClockDateForTwoWeekVo; +import org.dromara.project.domain.vo.attendance.BusAttendanceListByDay; +import org.dromara.project.domain.vo.attendance.BusAttendanceMonthByUserIdVo; +import org.dromara.project.domain.vo.attendance.BusAttendanceVo; +import org.dromara.project.mapper.BusAttendanceMapper; +import org.dromara.project.service.*; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.ZoneId; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 考勤Service业务层处理 + * + * @author lilemy + * @date 2025-04-07 + */ +@Service +public class BusAttendanceServiceImpl extends ServiceImpl + implements IBusAttendanceService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IBusProjectTeamMemberService projectTeamMemberService; + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private IBusConstructionBlacklistService constructionBlacklistService; + + // 出勤状态(正常、迟到、早退) + private static final Set ATTENDANCE_STATUS = new HashSet<>(Arrays.asList(BusAttendanceClockStatusEnum.NORMAL.getValue(), + BusAttendanceClockStatusEnum.LATE.getValue(), BusAttendanceClockStatusEnum.LEAVEEARLY.getValue())); + + /** + * 查询考勤 + * + * @param id 主键 + * @return 考勤 + */ + @Override + public BusAttendanceVo queryById(Long id) { + BusAttendance attendance = this.getById(id); + if (attendance == null) { + throw new ServiceException("考勤信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(attendance); + } + + /** + * 分页查询考勤列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 考勤分页列表 + */ + @Override + public TableDataInfo queryPageList(BusAttendanceQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询两周内的考勤列表 + * + * @param req 查询条件 + * @return 考勤列表 + */ + @Override + public List listClockDateForTwoWeek(BusAttendanceQueryTwoWeekReq req) { + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + // 1. 处理日期区间 + Date clockDate = req.getClockDate(); + LocalDate startLocal; + LocalDate endLocal; + if (clockDate != null) { + // 检查 clockDate 不能大于当前日期 + if (DateUtil.compare(clockDate, new Date()) > 0) { + throw new ServiceException("日期不能大于当前日期", HttpStatus.BAD_REQUEST); + } + // 以传入的 clockDate 为结束日期 + endLocal = clockDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + } else { + // 如果未传入,则以当前日期为结束日期 + endLocal = LocalDate.now(); + } + // 计算开始日期为结束日期减两周 + startLocal = endLocal.minusWeeks(2); + // 如果数据库中的 clockDate 只存储日期(时分秒置为 00:00:00),直接转换即可 + Date startDate = Date.from(startLocal.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = Date.from(endLocal.atStartOfDay(ZoneId.systemDefault()).toInstant()); + // 构造查询条件 clockDate 在 [startDate, endDate] 区间内 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(BusAttendance::getProjectId, projectId) + .eq(StringUtils.isNotEmpty(req.getUserName()), BusAttendance::getUserName, req.getUserName()) + .between(BusAttendance::getClockDate, startDate, endDate) + .orderByDesc(BusAttendance::getClockDate); + // 获取黑名单用户列表 + List blackList = constructionBlacklistService.queryIdListByProjectId(projectId); + // 构建查询用户相关信息查询条件 + List userIdList = constructionUserService.lambdaQuery() + .eq(SubConstructionUser::getProjectId, projectId) + .eq(req.getTeamId() != null, SubConstructionUser::getTeamId, req.getTeamId()) + .eq(req.getTypeOfWork() != null, SubConstructionUser::getTypeOfWork, req.getTypeOfWork()) + .notIn(CollUtil.isNotEmpty(blackList), SubConstructionUser::getId, blackList) + .list().stream().map(SubConstructionUser::getId).toList(); + lqw.in(CollUtil.isNotEmpty(userIdList), BusAttendance::getUserId, userIdList); + Map> dateListMap = this.list(lqw) + .stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); + // 遍历每个日期,计算考勤状态 + List respList = new ArrayList<>(); + // 遍历从两周前到今天的所有日期 + for (LocalDate localDate = startLocal; !localDate.isAfter(endLocal); localDate = localDate.plusDays(1)) { + BusAttendanceClockDateForTwoWeekVo resp = new BusAttendanceClockDateForTwoWeekVo(); + // 转换为 Date 类型(时分秒为 00:00:00) + Date currentDate = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + resp.setClockDate(currentDate); + int attendance = 0; + int halfAttendance = 0; + int absenteeism = 0; + int leave = 0; + // 获取当天的考勤记录(可能为 null) + List attendanceList = dateListMap.getOrDefault(currentDate, Collections.emptyList()); + // 按用户分组考勤记录 + Map> userAttendanceMap = attendanceList.stream() + .collect(Collectors.groupingBy(BusAttendance::getUserId)); + if (CollUtil.isNotEmpty(userAttendanceMap)) { + for (List userAttendanceList : userAttendanceMap.values()) { + String clockInStatus = null; + String clockOutStatus = null; + String clockAllDayStatus = null; + // 遍历同一用户的考勤记录,分别获取上下班状态 + for (BusAttendance a : userAttendanceList) { + if (BusAttendanceCommuterEnum.CLOCKIN.getValue().equals(a.getCommuter())) { + clockInStatus = a.getClockStatus(); + } else if (BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(a.getCommuter())) { + clockOutStatus = a.getClockStatus(); + } else if (BusAttendanceCommuterEnum.ALLDAY.getValue().equals(a.getCommuter())) { + clockAllDayStatus = a.getClockStatus(); + } + } + // 统计考勤状态 + if (BusAttendanceClockStatusEnum.LEAVE.getValue().equals(clockAllDayStatus)) { + leave++; + } else if ((BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus) + || BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockInStatus)) + && (BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus) + || BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockOutStatus))) { + attendance++; + } else if (BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus) + && BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { + absenteeism++; + } else if (BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus) + || BusAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { + halfAttendance++; + } + } + } + resp.setAttendance(attendance); + resp.setHalfAttendance(halfAttendance); + resp.setAbsenteeism(absenteeism); + resp.setLeave(leave); + respList.add(resp); + } + // 按打卡日期正序排列 + respList.sort(Comparator.comparing(BusAttendanceClockDateForTwoWeekVo::getClockDate)); + return respList; + } + + /** + * 查询用户每月考勤列表 + * + * @param req 查询条件 + * @return 考勤列表 + */ + @Override + public List listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req) { + Long userId = req.getUserId(); + String clockMonth = req.getClockMonth(); + if (constructionUserService.getById(userId) == null) { + throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); + } + // 解析月份 + YearMonth yearMonth; + if (StringUtils.isNotBlank(clockMonth)) { + // 校验月份格式 + if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { + throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); + } + yearMonth = YearMonth.parse(clockMonth); + } else { + // 如果月份为空,则默认查询当前月份 + yearMonth = YearMonth.now(); + } + // 计算当月第一天 / 最后一天 + Date start = DateUtils.toDate(yearMonth.atDay(1)); + Date end = DateUtils.toDate(yearMonth.atEndOfMonth()); + // 查询当月考勤记录 + Map> dateListMap = this.lambdaQuery() + .eq(BusAttendance::getUserId, userId) + .between(BusAttendance::getClockDate, start, end) + .list() + .stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); + // 遍历每天,计算考勤状态 + List respList = new ArrayList<>(); + dateListMap.forEach((date, attendanceList) -> { + BusAttendanceMonthByUserIdVo resp = new BusAttendanceMonthByUserIdVo(); + resp.setId(userId); + resp.setClockDate(date); + List attendanceListByDayList = new ArrayList<>(); + String clockInStatus = null; + String clockOutStatus = null; + String clockAllDayStatus = null; + String status; + for (BusAttendance attendance : attendanceList) { + // 获取考勤记录 + BusAttendanceListByDay day = BusAttendanceListByDay.build(attendance); + attendanceListByDayList.add(day); + // 获取上下班状态 + if (BusAttendanceCommuterEnum.CLOCKIN.getValue().equals(attendance.getCommuter())) { + clockInStatus = attendance.getClockStatus(); + } else if (BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getCommuter())) { + clockOutStatus = attendance.getClockStatus(); + } else { + clockAllDayStatus = attendance.getClockStatus(); + } + } + // 统计当天考勤状态 + if (BusAttendanceClockStatusEnum.LEAVE.getValue().equals(clockAllDayStatus)) { + return; + } else if (BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus) + && BusAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus)) { + status = BusAttendanceStatusEnum.NORMAL.getValue(); + } else if (BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockInStatus) + || BusAttendanceClockStatusEnum.REISSUE.getValue().equals(clockOutStatus)) { + status = BusAttendanceStatusEnum.REISSUE.getValue(); + } else { + status = BusAttendanceStatusEnum.ERROR.getValue(); + } + resp.setStatus(status); + resp.setAttendanceList(attendanceListByDayList); + respList.add(resp); + }); + // 按打卡日期正序排列 + respList.sort(Comparator.comparing(BusAttendanceMonthByUserIdVo::getClockDate)); + return respList; + } + + /** + * 查询符合条件的考勤列表 + * + * @param req 查询条件 + * @return 考勤列表 + */ + @Override + public List queryList(BusAttendanceQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 根据项目id查询出勤人列表 + * + * @param projectId 项目id + * @return 出勤人列表 + */ + @Override + public List listAttendancePeopleByProjectId(Long projectId) { + // 今天所有用户的打卡记录 + List attendanceList = this.lambdaQuery() + .eq(BusAttendance::getProjectId, projectId) + .eq(BusAttendance::getClockDate, DateUtils.dateTimeNow(FormatsType.YYYY_MM_DD)) + .list(); + if (CollUtil.isEmpty(attendanceList)) { + return List.of(); + } + Map> attendanceMap = attendanceList.stream() + .collect(Collectors.groupingBy(BusAttendance::getUserId)); + List attendedUserIds = new ArrayList<>(); + for (Map.Entry> entry : attendanceMap.entrySet()) { + Long userId = entry.getKey(); + List records = entry.getValue(); + // 要求必须有2条打卡记录 + if (records.size() != 2) { + continue; + } + boolean allValid = records.stream() + .allMatch(record -> ATTENDANCE_STATUS.contains(record.getClockStatus())); + if (allValid) { + attendedUserIds.add(userId); + } + } + return attendedUserIds; + } + + /** + * 获取考勤视图对象 + * + * @param attendance 考勤对象 + * @return 考勤视图对象 + */ + @Override + public BusAttendanceVo getVo(BusAttendance attendance) { + // 对象转封装类 + BusAttendanceVo attendanceVo = new BusAttendanceVo(); + if (attendance == null) { + return attendanceVo; + } + BeanUtils.copyProperties(attendance, attendanceVo); + return attendanceVo; + } + + /** + * 获取考勤查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusAttendanceQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + String userName = req.getUserName(); + Long projectId = req.getProjectId(); + Long teamId = req.getTeamId(); + String clockStatus = req.getClockStatus(); + Date clockDate = req.getClockDate(); + // 联表查询 + if (ObjectUtils.isNotEmpty(teamId)) { + List projectTeamMemberList = projectTeamMemberService.lambdaQuery() + .eq(BusProjectTeamMember::getTeamId, teamId).list(); + List userIdList = projectTeamMemberList.stream().map(BusProjectTeamMember::getMemberId).toList(); + lqw.in(BusAttendance::getUserId, userIdList); + } + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), BusAttendance::getUserName, userName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusAttendance::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(clockStatus), BusAttendance::getClockStatus, clockStatus); + lqw.eq(ObjectUtils.isNotEmpty(clockDate), BusAttendance::getClockDate, clockDate); + // 不包含请假的考勤记录 + lqw.ne(BusAttendance::getClockStatus, BusAttendanceClockStatusEnum.LEAVE.getValue()); + return lqw; + } + + /** + * 获取考勤分页对象视图 + * + * @param attendancePage 考勤分页对象 + * @return 考勤分页对象视图 + */ + @Override + public Page getVoPage(Page attendancePage) { + List attendanceList = attendancePage.getRecords(); + Page attendanceVoPage = new Page<>( + attendancePage.getCurrent(), + attendancePage.getSize(), + attendancePage.getTotal() + ); + if (CollUtil.isEmpty(attendanceList)) { + return attendanceVoPage; + } + List attendanceVoList = attendanceList.stream().map(this::getVo).toList(); + attendanceVoPage.setRecords(attendanceVoList); + return attendanceVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionBlacklistServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionBlacklistServiceImpl.java new file mode 100644 index 0000000..69cfcd9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionBlacklistServiceImpl.java @@ -0,0 +1,252 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.IdcardUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.domain.BusConstructionBlacklist; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.project.domain.dto.constructionblacklist.BusConstructionBlacklistCreateReq; +import org.dromara.project.domain.dto.constructionblacklist.BusConstructionBlacklistQueryReq; +import org.dromara.project.domain.vo.constructionblacklist.BusConstructionBlacklistVo; +import org.dromara.project.mapper.BusConstructionBlacklistMapper; +import org.dromara.project.service.IBusConstructionBlacklistService; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusProjectTeamMemberService; +import org.dromara.common.utils.IdCardEncryptorUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 黑名单Service业务层处理 + * + * @author lilemy + * @date 2025-03-27 + */ +@Service +public class BusConstructionBlacklistServiceImpl extends ServiceImpl + implements IBusConstructionBlacklistService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISubConstructionUserService constructionUserService; + + @Lazy + @Resource + private IBusProjectTeamMemberService projectTeamMemberService; + + @Resource + private IdCardEncryptorUtil idCardEncryptorUtil; + + /** + * 查询黑名单 + * + * @param id 主键 + * @return 黑名单 + */ + @Override + public BusConstructionBlacklistVo queryById(Long id) { + BusConstructionBlacklist constructionBlacklist = this.getById(id); + if (constructionBlacklist == null) { + throw new ServiceException("查询黑名单用户不存在", HttpStatus.NOT_FOUND); + } + BusConstructionBlacklistVo vo = new BusConstructionBlacklistVo(); + BeanUtils.copyProperties(constructionBlacklist, vo); + // 解密身份证号码 + String decrypt = idCardEncryptorUtil.decrypt(constructionBlacklist.getSfzNumber()); + String hide = IdcardUtil.hide(decrypt, 11, 17); + vo.setSfzNumber(hide); + return vo; + } + + /** + * 分页查询黑名单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 黑名单分页列表 + */ + @Override + public TableDataInfo queryPageList(BusConstructionBlacklistQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + List records = result.getRecords(); + Page resultPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal()); + if (CollUtil.isEmpty(records)) { + return TableDataInfo.build(resultPage); + } + List list = records.stream().map(entity -> { + BusConstructionBlacklistVo vo = new BusConstructionBlacklistVo(); + BeanUtils.copyProperties(entity, vo); + String decrypt = idCardEncryptorUtil.decrypt(entity.getSfzNumber()); + String hide = IdcardUtil.hide(decrypt, 11, 17); + vo.setSfzNumber(hide); + return vo; + }).toList(); + resultPage.setRecords(list); + return TableDataInfo.build(resultPage); + } + + /** + * 查询符合条件的黑名单列表 + * + * @param req 查询条件 + * @return 黑名单列表 + */ + @Override + public List queryList(BusConstructionBlacklistQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return baseMapper.selectVoList(lqw); + } + + /** + * 根据项目id查询黑名单用户id列表 + * + * @param projectId 项目id + * @return 黑名单用户id列表 + */ + @Override + public List queryIdListByProjectId(Long projectId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(BusConstructionBlacklist.class) + .select(BusConstructionBlacklist::getUserId) + .eq(projectId != null, BusConstructionBlacklist::getProjectId, projectId); + return this.listObjs(lqw, obj -> (Long) obj); + } + + /** + * 新增黑名单 + * + * @param req 黑名单 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(BusConstructionBlacklistCreateReq req) { + // 将实体类和 DTO 进行转换 + BusConstructionBlacklist constructionBlacklist = new BusConstructionBlacklist(); + BeanUtils.copyProperties(req, constructionBlacklist); + // 数据校验 + validEntityBeforeSave(constructionBlacklist); + // 填充默认值 + Long userId = req.getUserId(); + if (userId == null) { + throw new ServiceException("用户 id 不能为空", HttpStatus.BAD_REQUEST); + } + SubConstructionUser constructionUser = constructionUserService.getById(userId); + if (constructionUser == null) { + throw new ServiceException("对应用户不存在", HttpStatus.NOT_FOUND); + } + constructionBlacklist.setUserName(constructionUser.getUserName()); + constructionBlacklist.setSfzNumber(constructionUser.getSfzNumber()); + // 操作数据库 + boolean result = this.save(constructionBlacklist); + if (!result) { + throw new ServiceException("新增黑名单失败,数据库异常", HttpStatus.ERROR); + } + return constructionBlacklist.getId(); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusConstructionBlacklist entity) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long userId = entity.getUserId(); + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + // 判断用户是否退场 + Long count = projectTeamMemberService.lambdaQuery() + .eq(BusProjectTeamMember::getProjectId, projectId) + .eq(BusProjectTeamMember::getMemberId, userId) + .count(); + if (count > 0) { + throw new ServiceException("请将施工人员退场后,再加入黑名单", HttpStatus.BAD_REQUEST); + } + // 判断是否已经存在该用户 + this.validUserInBlacklist(userId, projectId); + } + + /** + * 校验并批量删除黑名单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List constructionBlacklistList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = constructionBlacklistList.stream().map(BusConstructionBlacklist::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 校验用户是否在黑名单中 + * + * @param userId 用户id + * @param projectId 项目id + */ + @Override + public void validUserInBlacklist(Long userId, Long projectId) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(BusConstructionBlacklist::getUserId, userId) + .eq(BusConstructionBlacklist::getProjectId, projectId); + if (this.count(lqw) > 0) { + throw new ServiceException("用户已存在黑名单中", HttpStatus.BAD_REQUEST); + } + } + + /** + * 获取黑名单查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusConstructionBlacklistQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long id = req.getId(); + Long userId = req.getUserId(); + Long projectId = req.getProjectId(); + String userName = req.getUserName(); + String sfzNumber = req.getSfzNumber(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), BusConstructionBlacklist::getUserName, userName); + lqw.like(StringUtils.isNotBlank(sfzNumber), BusConstructionBlacklist::getSfzNumber, sfzNumber); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusConstructionBlacklist::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(userId), BusConstructionBlacklist::getUserId, userId); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusConstructionBlacklist::getProjectId, projectId); + return lqw; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserExitServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserExitServiceImpl.java new file mode 100644 index 0000000..d4de186 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserExitServiceImpl.java @@ -0,0 +1,153 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusConstructionUserExit; +import org.dromara.project.domain.dto.constructionuserexit.BusConstructionUserExitQueryReq; +import org.dromara.project.domain.vo.constructionuserexit.BusConstructionUserExitVo; +import org.dromara.project.mapper.BusConstructionUserExitMapper; +import org.dromara.project.service.IBusConstructionUserExitService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +/** + * 施工人员入场退场记录信息Service业务层处理 + * + * @author lilemy + * @date 2025-03-31 + */ +@Service +public class BusConstructionUserExitServiceImpl extends ServiceImpl + implements IBusConstructionUserExitService { + + @Resource + private ISysOssService ossService; + + /** + * 查询施工人员入场退场记录信息 + * + * @param id 主键 + * @return 施工人员入场退场记录信息 + */ + @Override + public BusConstructionUserExitVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询施工人员入场退场记录信息列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员入场退场记录信息分页列表 + */ + @Override + public TableDataInfo queryPageList(BusConstructionUserExitQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的施工人员入场退场记录信息列表 + * + * @param req 查询条件 + * @return 施工人员入场退场记录信息列表 + */ + @Override + public List queryList(BusConstructionUserExitQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 获取施工人员入场退场记录视图对象 + * + * @param constructionUserExit 施工人员入场退场记录对象 + * @return 施工人员入场退场记录视图对象 + */ + @Override + public BusConstructionUserExitVo getVo(BusConstructionUserExit constructionUserExit) { + // 对象转封装类 + BusConstructionUserExitVo constructionUserExitVo = new BusConstructionUserExitVo(); + if (constructionUserExit == null) { + return constructionUserExitVo; + } + BeanUtils.copyProperties(constructionUserExit, constructionUserExitVo); + String path = constructionUserExitVo.getPath(); + if (StringUtils.isNotBlank(path)) { + List ossIdList = Arrays.stream(path.split(",")).map(Long::parseLong).toList(); + constructionUserExitVo.setPathUrl(ossService.listByIds(ossIdList).stream().map(SysOssVo::getUrl).toList()); + } + return constructionUserExitVo; + } + + /** + * 获取施工人员入场退场记录信息查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusConstructionUserExitQueryReq req) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + String sfzNumber = req.getSfzNumber(); + Long userId = req.getUserId(); + Long projectId = req.getProjectId(); + Long teamId = req.getTeamId(); + String entryDate = req.getEntryDate(); + String leaveDate = req.getLeaveDate(); + String remark = req.getRemark(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(sfzNumber), BusConstructionUserExit::getSfzNumber, sfzNumber); + lqw.like(StringUtils.isNotBlank(remark), BusConstructionUserExit::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusConstructionUserExit::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(userId), BusConstructionUserExit::getUserId, userId); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusConstructionUserExit::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), BusConstructionUserExit::getTeamId, teamId); + lqw.eq(StringUtils.isNotBlank(entryDate), BusConstructionUserExit::getEntryDate, entryDate); + lqw.eq(StringUtils.isNotBlank(leaveDate), BusConstructionUserExit::getLeaveDate, leaveDate); + // 排序 + lqw.orderByAsc(BusConstructionUserExit::getId); + return lqw; + } + + /** + * 获取施工人员入场退场记录分页对象视图 + * + * @param constructionUserExitPage 施工人员入场退场记录分页对象 + * @return 施工人员入场退场记录分页对象视图 + */ + @Override + public Page getVoPage(Page constructionUserExitPage) { + List constructionUserExitList = constructionUserExitPage.getRecords(); + Page constructionUserExitVoPage = new Page<>( + constructionUserExitPage.getCurrent(), + constructionUserExitPage.getSize(), + constructionUserExitPage.getTotal()); + if (CollUtil.isEmpty(constructionUserExitList)) { + return constructionUserExitVoPage; + } + List constructionUserExitVoList = constructionUserExitList.stream().map(this::getVo).toList(); + constructionUserExitVoPage.setRecords(constructionUserExitVoList); + return constructionUserExitVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusDailyPieceItemServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusDailyPieceItemServiceImpl.java new file mode 100644 index 0000000..7592b97 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusDailyPieceItemServiceImpl.java @@ -0,0 +1,53 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.dromara.project.domain.BusDailyPieceItem; +import org.dromara.project.domain.vo.dailypieceitem.BusDailyPieceItemVo; +import org.dromara.project.mapper.BusDailyPieceItemMapper; +import org.dromara.project.service.IBusDailyPieceItemService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 施工人员日报计件信息Service业务层处理 + * + * @author lilemy + * @date 2025-04-09 + */ +@Service +public class BusDailyPieceItemServiceImpl extends ServiceImpl + implements IBusDailyPieceItemService { + + /** + * 施工人员日报计件信息封装 + * + * @param dailyPieceItem 施工人员日报计件信息 + * @return 施工人员日报计件信息封装 + */ + @Override + public BusDailyPieceItemVo getVo(BusDailyPieceItem dailyPieceItem) { + BusDailyPieceItemVo dailyPieceItemVo = new BusDailyPieceItemVo(); + if (dailyPieceItem == null) { + return dailyPieceItemVo; + } + BeanUtils.copyProperties(dailyPieceItem, dailyPieceItemVo); + return dailyPieceItemVo; + } + + /** + * 施工人员日报计件信息列表封装 + * + * @param dailyPieceItemList 施工人员日报计件信息列表 + * @return 施工人员日报计件信息列表封装 + */ + @Override + public List getListVo(List dailyPieceItemList) { + if (CollUtil.isEmpty(dailyPieceItemList)) { + return List.of(); + } + return dailyPieceItemList.stream().map(this::getVo).toList(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusLeaveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusLeaveServiceImpl.java new file mode 100644 index 0000000..ceaff8c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusLeaveServiceImpl.java @@ -0,0 +1,276 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.BusLeave; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum; +import org.dromara.project.domain.enums.BusAttendanceCommuterEnum; +import org.dromara.project.domain.enums.BusOpinionStatusEnum; +import org.dromara.project.domain.enums.BusReviewStatusEnum; +import org.dromara.project.domain.dto.leave.BusLeaveManagerReviewReq; +import org.dromara.project.domain.dto.leave.BusLeaveQueryReq; +import org.dromara.project.domain.vo.leave.BusLeaveVo; +import org.dromara.project.mapper.BusLeaveMapper; +import org.dromara.project.service.IBusAttendanceService; +import org.dromara.project.service.IBusLeaveService; +import org.dromara.project.service.IBusProjectTeamService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 施工人员请假申请Service业务层处理 + * + * @author lilemy + * @date 2025-04-08 + */ +@Service +public class BusLeaveServiceImpl extends ServiceImpl + implements IBusLeaveService { + + @Resource + private IBusProjectTeamService projectTeamService; + + @Lazy + @Resource + private IBusAttendanceService attendanceService; + + /** + * 查询施工人员请假申请 + * + * @param id 主键 + * @return 施工人员请假申请 + */ + @Override + public BusLeaveVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询施工人员请假申请列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员请假申请分页列表 + */ + @Override + public TableDataInfo queryPageList(BusLeaveQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的施工人员请假申请列表 + * + * @param req 查询条件 + * @return 施工人员请假申请列表 + */ + @Override + public List queryList(BusLeaveQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return baseMapper.selectVoList(lqw); + } + + /** + * 管理员审核施工人员请假申请 + * + * @param req 管理员审核施工人员请假申请 + * @return 是否审核成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean managerReview(BusLeaveManagerReviewReq req) { + Long id = req.getId(); + String managerOpinion = req.getManagerOpinion(); + // 判断该请假记录是否存在 + BusLeave oldLeave = this.getById(id); + if (oldLeave == null) { + throw new ServiceException("施工人员请假申请不存在", HttpStatus.NOT_FOUND); + } + // 如果已经审核过,则返回 + if (!BusOpinionStatusEnum.UNREAD.getValue().equals(oldLeave.getManagerOpinion())) { + throw new ServiceException("该请假已审核,请勿重复操作", HttpStatus.BAD_REQUEST); + } + // 判断班组长是否审核通过 + String gangerOpinion = oldLeave.getGangerOpinion(); + if (!BusOpinionStatusEnum.PASS.getValue().equals(gangerOpinion)) { + throw new ServiceException("请等待班组长审核通过后再进行操作", HttpStatus.BAD_REQUEST); + } + // todo 判断当前用户是否为项目管理员 + // 填充默认值,更新数据 + BusLeave leave = new BusLeave(); + leave.setId(id); + leave.setManagerOpinion(managerOpinion); + leave.setManagerExplain(req.getManagerExplain()); + leave.setManagerTime(new Date()); + leave.setRemark(req.getRemark()); + boolean result = this.updateById(leave); + if (!result) { + throw new ServiceException("更新管理员审核操作失败", HttpStatus.ERROR); + } + // 更新考勤表记录 + Date startTime = oldLeave.getStartTime(); + Date endTime = oldLeave.getEndTime(); + // 计算相差的时间 + long diffInMillis = endTime.getTime() - startTime.getTime(); + long day = TimeUnit.MILLISECONDS.toDays(diffInMillis) + 1; + Long userId = oldLeave.getUserId(); + String userName = oldLeave.getUserName(); + Long projectId = oldLeave.getProjectId(); + // 遍历每一天 + List attendanceList = new ArrayList<>(); + for (long i = 0; i < day; i++) { + BusAttendance attendance = new BusAttendance(); + attendance.setUserId(userId); + attendance.setUserName(userName); + attendance.setProjectId(projectId); + Date date = DateUtils.addDays(startTime, (int) i); + attendance.setLeaveId(id); + attendance.setClockDate(date); + attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVE.getValue()); + attendance.setCommuter(BusAttendanceCommuterEnum.ALLDAY.getValue()); + attendanceList.add(attendance); + } + boolean saveBatch = attendanceService.saveBatch(attendanceList); + if (!saveBatch) { + throw new ServiceException("更新考勤记录失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 校验并批量删除施工人员请假申请信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 获取施工人员请假申请视图对象 + * + * @param leave 施工人员请假申请对象 + * @return 施工人员请假申请视图对象 + */ + @Override + public BusLeaveVo getVo(BusLeave leave) { + // 对象转封装类 + BusLeaveVo leaveVo = new BusLeaveVo(); + if (leave == null) { + return leaveVo; + } + BeanUtils.copyProperties(leave, leaveVo); + // 获取班组信息 + Long teamId = leave.getTeamId(); + if (teamId != null) { + BusProjectTeam team = projectTeamService.lambdaQuery() + .eq(BusProjectTeam::getId, teamId).select(BusProjectTeam::getTeamName).one(); + leaveVo.setTeamName(team.getTeamName()); + } + // 添加审核状态 + String status = BusReviewStatusEnum.getEnumByOpinionStatus(leave.getGangerOpinion(), leave.getManagerOpinion()); + leaveVo.setStatus(status); + return leaveVo; + } + + /** + * 获取施工人员请假申请查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusLeaveQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long userId = req.getUserId(); + String userName = req.getUserName(); + String leaveType = req.getLeaveType(); + Long gangerId = req.getGangerId(); + String gangerName = req.getGangerName(); + String gangerOpinion = req.getGangerOpinion(); + String managerOpinion = req.getManagerOpinion(); + Long projectId = req.getProjectId(); + Long teamId = req.getTeamId(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), BusLeave::getUserName, userName); + lqw.like(StringUtils.isNotBlank(gangerName), BusLeave::getGangerName, gangerName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusLeave::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(userId), BusLeave::getUserId, userId); + lqw.eq(ObjectUtils.isNotEmpty(gangerId), BusLeave::getGangerId, gangerId); + lqw.eq(StringUtils.isNotBlank(gangerOpinion), BusLeave::getGangerOpinion, gangerOpinion); + lqw.eq(StringUtils.isNotBlank(managerOpinion), BusLeave::getManagerOpinion, managerOpinion); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusLeave::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), BusLeave::getTeamId, teamId); + lqw.eq(StringUtils.isNotBlank(leaveType), BusLeave::getLeaveType, leaveType); + return lqw; + } + + /** + * 获取施工人员请假申请分页对象视图 + * + * @param leavePage 施工人员请假申请分页对象 + * @return 施工人员请假申请分页对象视图 + */ + @Override + public Page getVoPage(Page leavePage) { + List leaveList = leavePage.getRecords(); + Page leaveVoPage = new Page<>( + leavePage.getCurrent(), + leavePage.getSize(), + leavePage.getTotal()); + if (CollUtil.isEmpty(leaveList)) { + return leaveVoPage; + } + // 关联查询班组信息 + Set teamIdSet = leaveList.stream().map(BusLeave::getTeamId) + .collect(Collectors.toSet()); + Map> teamIdTeamMap = projectTeamService.listByIds(teamIdSet).stream() + .collect(Collectors.groupingBy(BusProjectTeam::getId)); + List leaveVoList = leaveList.stream().map(leave -> { + BusLeaveVo leaveVo = new BusLeaveVo(); + BeanUtils.copyProperties(leave, leaveVo); + // 关联班组信息 + Long teamId = leave.getTeamId(); + String teamName = null; + if (teamIdTeamMap.containsKey(teamId)) { + teamName = projectTeamService.getVo(teamIdTeamMap.get(teamId).get(0)).getTeamName(); + } + leaveVo.setTeamName(teamName); + // 添加审核状态 + String status = BusReviewStatusEnum.getEnumByOpinionStatus(leave.getGangerOpinion(), leave.getManagerOpinion()); + leaveVo.setStatus(status); + return leaveVo; + }).toList(); + leaveVoPage.setRecords(leaveVoList); + return leaveVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectFileServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectFileServiceImpl.java new file mode 100644 index 0000000..b9bc842 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectFileServiceImpl.java @@ -0,0 +1,385 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.crypto.digest.MD5; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.common.constant.DesignMapFileConstant; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.BusProjectFile; +import org.dromara.project.domain.dto.projectfile.BusProjectFileQueryReq; +import org.dromara.project.domain.dto.projectfile.BusProjectFileUpdateReq; +import org.dromara.project.domain.dto.projectfile.BusProjectFileUploadDxfReq; +import org.dromara.project.domain.vo.projectfile.BusProjectFileVo; +import org.dromara.project.mapper.BusProjectFileMapper; +import org.dromara.project.service.IBusProjectFileService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.common.utils.Dxf2JsonUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; + +/** + * 项目文件存储Service业务层处理 + * + * @author lilemy + * @date 2025-04-23 + */ +@Slf4j +@Service +public class BusProjectFileServiceImpl extends ServiceImpl + implements IBusProjectFileService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ScheduledExecutorService scheduledExecutorService; + + private static final ConcurrentHashMap USER_TASK_RUNNING = new ConcurrentHashMap<>(); + + @Value("${dxf2GeoJson.file-name}") + private String dxf2GeoJsonFileName; + + /** + * 查询项目文件存储 + * + * @param id 主键 + * @return 项目文件存储 + */ + @Override + public BusProjectFileVo queryById(Long id) { + BusProjectFile projectFile = this.getById(id); + if (projectFile == null) { + throw new ServiceException("对应项目文件存储信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(projectFile); + } + + /** + * 分页查询项目文件存储列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目文件存储分页列表 + */ + @Override + public TableDataInfo queryPageList(BusProjectFileQueryReq req, PageQuery pageQuery) { + Page projectFilePage = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(projectFilePage)); + } + + /** + * 查询符合条件的项目文件存储列表 + * + * @param req 查询条件 + * @return 项目文件存储列表 + */ + @Override + public List queryList(BusProjectFileQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 修改项目文件存储 + * + * @param req 项目文件存储 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusProjectFileUpdateReq req) { + // 将实体类和 DTO 进行转换 + BusProjectFile projectFile = new BusProjectFile(); + BeanUtils.copyProperties(req, projectFile); + // 数据校验 + validEntityBeforeSave(projectFile); + // 判断是否存在 + BusProjectFile oldProjectFile = this.getById(projectFile.getId()); + if (oldProjectFile == null) { + throw new ServiceException("修改项目文件存储失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + boolean update = this.updateById(projectFile); + if (!update) { + throw new ServiceException("修改项目文件存储失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusProjectFile entity) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除项目文件存储信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List projectFileList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = projectFileList.stream().map(BusProjectFile::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 根据id获取JSON文件 + * + * @param id 主键 + * @return JSON文件 + */ + @Override + public JSONObject getJSONFile(Long id) { + BusProjectFile projectFile = this.getById(id); + if (projectFile == null) { + throw new ServiceException("对应项目文件存储信息不存在", HttpStatus.NOT_FOUND); + } + Long userId = LoginHelper.getUserId(); + // 获取当前登录用户key值 + String string = String.valueOf(userId + projectFile.getProjectId()); + String md5 = MD5.create().digestHex16(string); + // 判断当前用户是否已经有一个正在处理的任务 + Boolean alreadyRunning = USER_TASK_RUNNING.get(md5); + if (alreadyRunning != null && alreadyRunning) { + throw new ServiceException("正在转换,请稍后重试", HttpStatus.CONFLICT); + } + String filePath = projectFile.getFilePath(); + String suffix = FileUtil.getSuffix(FileUtil.getName(filePath)); + if (!suffix.equals(DesignMapFileConstant.JSONFileSuffix)) { + throw new ServiceException("文件格式不正确,只能解析json文件", HttpStatus.BAD_REQUEST); + } + JSONObject jsonObject; + try { + String property = System.getProperty("user.dir"); + Path path = Paths.get(property, filePath); + String jsonStr = Files.readString(path, StandardCharsets.UTF_8); + jsonObject = JSONUtil.parseObj(jsonStr); + } catch (IOException e) { + throw new ServiceException("文件读取失败", HttpStatus.ERROR); + } + return jsonObject; + } + + /** + * 上传dxf文件并转换为json + * + * @param file 文件 + * @param req 请求 + * @return 是否上传文件成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean uploadDxf2Json(MultipartFile file, BusProjectFileUploadDxfReq req) { + Long userId = LoginHelper.getUserId(); + // 获取当前登录用户key值 + String string = String.valueOf(userId + req.getProjectId()); + String md5 = MD5.create().digestHex16(string); + // 判断当前用户是否已经有一个正在处理的任务 + Boolean alreadyRunning = USER_TASK_RUNNING.putIfAbsent(md5, true); + if (alreadyRunning != null && alreadyRunning) { + throw new ServiceException("当前有一个正在处理的转换任务,请等待完成后再上传", HttpStatus.CONFLICT); + } + // 校验文件是否为空 + if (file == null) { + throw new ServiceException("dxf文件不能为空", HttpStatus.BAD_REQUEST); + } + // 校验是否为 dxf 文件 + String fileName = file.getOriginalFilename(); + String suffix = FileUtil.getSuffix(fileName); + if (!Objects.equals(suffix, DesignMapFileConstant.DXFFileSuffix)) { + throw new ServiceException("文件格式不正确,只能上传.dxf后缀的文件", HttpStatus.BAD_REQUEST); + } + // 校验项目是否存在 + Long projectId = req.getProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + // 获取当前项目根目录 + String projectRoot = System.getProperty("user.dir"); + String bashPath = DesignMapFileConstant.getDxfProjectPath(projectId); + String filePath = projectRoot + File.separator + bashPath; + String uuid = IdUtil.fastSimpleUUID(); + if (!FileUtil.exist(filePath)) { + FileUtil.mkdir(filePath); + } + String inputDXFPath = filePath + File.separator + uuid + "." + suffix; + try { + // 保存文件 + File savedFile = new File(inputDXFPath); + file.transferTo(savedFile); + } catch (IOException e) { + throw new ServiceException("dxf 文件保存失败"); + } + // 构造 JSON 输出路径 + String outputJSONPath = filePath + File.separator + uuid + "." + DesignMapFileConstant.JSONFileSuffix; + // 获取 dxf2json.exe 路径 + String exePath = projectRoot + File.separator + DesignMapFileConstant.DXF_BASE_PATH + File.separator + dxf2GeoJsonFileName; + String sourceEPSG = DesignMapFileConstant.EPSG4524; + String targetEPSG = DesignMapFileConstant.EPSG4326; + BusProjectFile oldProjectFile = this.lambdaQuery() + .eq(BusProjectFile::getProjectId, projectId) + .one(); + Long projectFileId; + String dxfFilePath = bashPath + File.separator + uuid + "." + suffix; + if (oldProjectFile != null) { + // 删除之前的文件 + try { + FileUtil.del(projectRoot + File.separator + oldProjectFile.getFilePath()); + FileUtil.del(projectRoot + File.separator + oldProjectFile.getRemark()); + } catch (Exception e) { + log.error("删除项目文件失败", e); + } + projectFileId = oldProjectFile.getId(); + BusProjectFile projectFile = new BusProjectFile(); + projectFile.setId(projectFileId); + projectFile.setFileName(fileName); + projectFile.setRemark(dxfFilePath); + boolean result = this.updateById(projectFile); + if (!result) { + throw new ServiceException("数据库更新异常"); + } + } else { + projectFileId = null; + } + SseMessageDto messageDto = new SseMessageDto(); + messageDto.setMessage("DXF 文件上传成功,正在转换中......"); + messageDto.setUserIds(List.of(userId)); + SseMessageUtils.publishMessage(messageDto); + scheduledExecutorService.execute(() -> { + try { + // 构造命令行参数 + Dxf2JsonUtil.dxf2json(exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG); + String jsonFilePath = bashPath + File.separator + uuid + "." + DesignMapFileConstant.JSONFileSuffix; + String jsonFileName = FileUtil.getPrefix(fileName) + "." + DesignMapFileConstant.JSONFileSuffix; + // 修改数据库信息 + BusProjectFile projectFile = new BusProjectFile(); + projectFile.setId(projectFileId); + projectFile.setFilePath(jsonFilePath); + projectFile.setFileName(jsonFileName); + projectFile.setFileType(DesignMapFileConstant.JSONFileSuffix); + projectFile.setProjectId(projectId); + projectFile.setRemark(dxfFilePath); + boolean update = this.saveOrUpdate(projectFile); + if (!update) throw new ServiceException("数据库修改异常"); + messageDto.setMessage("DXF 文件转换成 GeoJSON 成功"); + SseMessageUtils.publishMessage(messageDto); + } catch (Exception e) { + log.error("DXF 转换失败", e); + messageDto.setMessage("DXF 文件转换失败,请联系管理员处理"); + SseMessageUtils.publishMessage(messageDto); + } finally { + // 无论成功或失败都释放状态 + USER_TASK_RUNNING.remove(md5); + } + }); + return true; + } + + /** + * 获取项目文件存储视图对象 + * + * @param projectFile 项目文件存储对象 + * @return 项目文件存储视图对象 + */ + @Override + public BusProjectFileVo getVo(BusProjectFile projectFile) { + // 对象转封装类 + BusProjectFileVo projectFileVo = new BusProjectFileVo(); + if (projectFile == null) { + return projectFileVo; + } + BeanUtils.copyProperties(projectFile, projectFileVo); + return projectFileVo; + } + + /** + * 获取项目文件存储查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusProjectFileQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String fileType = req.getFileType(); + String fileName = req.getFileName(); + lqw.like(StringUtils.isNotBlank(fileName), BusProjectFile::getFileName, fileName); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusProjectFile::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(fileType), BusProjectFile::getFileType, fileType); + return lqw; + } + + /** + * 获取项目文件存储分页对象视图 + * + * @param projectFilePage 项目文件存储分页对象 + * @return 项目文件存储分页对象视图 + */ + @Override + public Page getVoPage(Page projectFilePage) { + List projectFileList = projectFilePage.getRecords(); + Page projectFileVoPage = new Page<>( + projectFilePage.getCurrent(), + projectFilePage.getSize(), + projectFilePage.getTotal()); + if (CollUtil.isEmpty(projectFileList)) { + return projectFileVoPage; + } + List projectFileVoList = projectFileList.stream().map(this::getVo).toList(); + projectFileVoPage.setRecords(projectFileVoList); + return projectFileVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectNewsServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectNewsServiceImpl.java new file mode 100644 index 0000000..9d23716 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectNewsServiceImpl.java @@ -0,0 +1,243 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.domain.BusProjectNews; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsCreateReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsGisReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsQueryReq; +import org.dromara.project.domain.dto.projectnews.BusProjectNewsUpdateReq; +import org.dromara.project.domain.vo.projectnews.BusProjectNewsGisVo; +import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo; +import org.dromara.project.mapper.BusProjectNewsMapper; +import org.dromara.project.service.IBusProjectNewsService; +import org.dromara.project.service.IBusProjectService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 项目新闻Service业务层处理 + * + * @author lilemy + * @date 2025-04-28 + */ +@Service +public class BusProjectNewsServiceImpl extends ServiceImpl + implements IBusProjectNewsService { + + @Resource + private IBusProjectService projectService; + + /** + * 查询项目新闻 + * + * @param id 主键 + * @return 项目新闻 + */ + @Override + public BusProjectNewsVo queryById(Long id) { + BusProjectNews projectNews = this.getById(id); + if (projectNews == null) { + throw new ServiceException("对应项目新闻存储信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(projectNews); + } + + /** + * 分页查询项目新闻列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目新闻分页列表 + */ + @Override + public TableDataInfo queryPageList(BusProjectNewsQueryReq req, PageQuery pageQuery) { + Page projectNewsPage = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(projectNewsPage)); + } + + /** + * 查询符合条件的项目新闻列表 + * + * @param req 查询条件 + * @return 项目新闻列表 + */ + @Override + public List queryList(BusProjectNewsQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 查询大屏项目新闻列表 + * + * @param req 列表查询条件 + * @return 大屏项目新闻列表 + */ + @Override + public List queryGisList(BusProjectNewsGisReq req) { + Long projectId = req.getProjectId(); + if (projectId == null || projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + List projectNewsList = this.lambdaQuery() + .select(BusProjectNews::getId, BusProjectNews::getTitle) + .eq(BusProjectNews::getProjectId, projectId) + .list(); + return projectNewsList.stream().map(projectNews -> { + BusProjectNewsGisVo projectNewsGisResp = new BusProjectNewsGisVo(); + BeanUtils.copyProperties(projectNews, projectNewsGisResp); + projectNewsGisResp.setShow(false); + return projectNewsGisResp; + }).toList(); + } + + /** + * 新增项目新闻 + * + * @param req 项目新闻 + * @return 新增项目新闻id + */ + @Override + public Long insertByBo(BusProjectNewsCreateReq req) { + // 将实体类和 DTO 进行转换 + BusProjectNews projectNews = new BusProjectNews(); + BeanUtils.copyProperties(req, projectNews); + // 数据校验 + validEntityBeforeSave(projectNews, true); + // 操作数据库 + boolean save = this.save(projectNews); + if (!save) { + throw new ServiceException("新增项目新闻存储失败,数据库异常", HttpStatus.ERROR); + } + return projectNews.getId(); + } + + /** + * 修改项目新闻 + * + * @param req 项目新闻 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusProjectNewsUpdateReq req) { + // 将实体类和 DTO 进行转换 + BusProjectNews projectNews = new BusProjectNews(); + BeanUtils.copyProperties(req, projectNews); + // 数据校验 + validEntityBeforeSave(projectNews, false); + // 判断是否存在 + BusProjectNews oldProjectNews = this.getById(projectNews.getId()); + if (oldProjectNews == null) { + throw new ServiceException("修改项目新闻存储失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + boolean update = this.updateById(projectNews); + if (!update) { + throw new ServiceException("修改项目新闻存储失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusProjectNews entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除项目新闻信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List projectNewsList = this.listByIds(ids); + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + List projectId = projectNewsList.stream().map(BusProjectNews::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取项目新闻存储视图对象 + * + * @param projectNews 项目新闻存储对象 + * @return 项目新闻存储视图对象 + */ + @Override + public BusProjectNewsVo getVo(BusProjectNews projectNews) { + // 对象转封装类 + BusProjectNewsVo projectNewsVo = new BusProjectNewsVo(); + if (projectNews == null) { + return projectNewsVo; + } + BeanUtils.copyProperties(projectNews, projectNewsVo); + return projectNewsVo; + } + + /** + * 获取项目新闻存储查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusProjectNewsQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long projectId = req.getProjectId(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusProjectNews::getProjectId, projectId); + return lqw; + } + + /** + * 获取项目新闻存储分页对象视图 + * + * @param projectNewsPage 项目新闻存储分页对象 + * @return 项目新闻存储分页对象视图 + */ + @Override + public Page getVoPage(Page projectNewsPage) { + List projectNewsList = projectNewsPage.getRecords(); + Page projectNewsVoPage = new Page<>( + projectNewsPage.getCurrent(), + projectNewsPage.getSize(), + projectNewsPage.getTotal()); + if (CollUtil.isEmpty(projectNewsList)) { + return projectNewsVoPage; + } + List projectNewsVoList = projectNewsList.stream().map(this::getVo).toList(); + projectNewsVoPage.setRecords(projectNewsVoList); + return projectNewsVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectServiceImpl.java new file mode 100644 index 0000000..a0cd090 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectServiceImpl.java @@ -0,0 +1,854 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.PhoneUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.vo.IdAndNameVO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.design.service.IDesTechnicalStandardService; +import org.dromara.facility.domain.FacMatrix; +import org.dromara.facility.domain.vo.matrix.FacMatrixBySubProjectVo; +import org.dromara.facility.service.IFacMatrixService; +import org.dromara.manager.weathermanager.WeatherConstant; +import org.dromara.manager.weathermanager.WeatherManager; +import org.dromara.project.constant.BusProjectConstant; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.BusProjectFile; +import org.dromara.project.domain.BusUserProjectRelevancy; +import org.dromara.project.domain.dto.project.BusProjectCreateReq; +import org.dromara.project.domain.dto.project.BusProjectCreateSubReq; +import org.dromara.project.domain.dto.project.BusProjectQueryReq; +import org.dromara.project.domain.dto.project.BusProjectUpdateReq; +import org.dromara.project.domain.vo.project.*; +import org.dromara.project.mapper.BusProjectMapper; +import org.dromara.project.service.IBusProjectFileService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusUserProjectRelevancyService; +import org.dromara.quality.service.IQltKnowledgeDocumentService; +import org.dromara.safety.service.IHseKnowledgeDocumentService; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.enums.SysDeptTypeEnum; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 项目Service业务层处理 + * + * @author lilemy + * @date 2025-03-04 + */ +@Slf4j +@Service +public class BusProjectServiceImpl extends ServiceImpl + implements IBusProjectService { + + @Lazy + @Resource + private IBusUserProjectRelevancyService userProjectRelevancyService; + + @Lazy + @Resource + private ISubContractorService contractorService; + + @Lazy + @Resource + private IBusProjectFileService projectFileService; + + @Resource + private WeatherManager weatherManager; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + @Lazy + @Resource + private IFacMatrixService matrixService; + + @Lazy + @Resource + private IHseKnowledgeDocumentService hseKnowledgeDocumentService; + + @Lazy + @Resource + private IQltKnowledgeDocumentService qltKnowledgeDocumentService; + + @Lazy + @Resource + private IDesTechnicalStandardService desTechnicalStandardService; + + @Resource + private IFlwDefinitionService flwDefinitionService; + + @Lazy + @Resource + private SysDeptMapper deptMapper; + + @Lazy + @Resource + private IBusProjectService self; + + private final Cache WEATHER_CACHE = + Caffeine.newBuilder().initialCapacity(1024) + .maximumSize(10000L) + // 缓存 60 分钟移除 + .expireAfterWrite(60L, TimeUnit.MINUTES) + .build(); + + /** + * 查询项目 + * + * @param id 主键 + * @return 项目 + */ + @Override + public BusProjectVo queryById(Long id) { + BusProject project = this.getById(id); + if (project == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(project); + } + + /** + * 分页查询项目列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目分页列表 + */ + @Override + public TableDataInfo queryPageList(BusProjectQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + // 查询数据库 + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的项目列表 + * + * @param req 查询条件 + * @return 项目列表 + */ + @Override + public List queryList(BusProjectQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 查询未绑定部门的项目列表(不查询子项目) + * + * @return 项目列表 + */ + @Override + public List queryListNoDept() { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(SysDept::getDeptType, SysDeptTypeEnum.PROJECT.getCode()); + lqw.isNotNull(SysDept::getProjectId); + List depts = deptMapper.selectList(lqw); + List idList = depts.stream().map(SysDept::getProjectId).toList(); + List projectList = this.lambdaQuery() + .notIn(CollUtil.isNotEmpty(idList), BusProject::getId, idList) + .eq(BusProject::getPId, BusProjectConstant.PARENT_ID) + .list(); + return projectList.stream().map(this::getVo).toList(); + } + + /** + * 查询项目下的子项目列表 + * + * @param id 父项目id + * @return 项目下的子项目列表 + */ + @Override + public List querySubList(Long id) { + BusProject project = this.getById(id); + if (project == null) { + throw new ServiceException("查询项目不存在", HttpStatus.NOT_FOUND); + } + List subProjectList = this.list(new LambdaQueryWrapper() + .eq(BusProject::getPId, id)); + return subProjectList.stream().map(subProject -> { + BusSubProjectVo subProjectVo = new BusSubProjectVo(); + BeanUtils.copyProperties(subProject, subProjectVo); + return subProjectVo; + }).toList(); + } + + /** + * 获取项目子项目方阵信息 + * + * @param id 项目id + * @return 子项目方阵信息列表 + */ + @Override + public List querySubProjectMatrixList(Long id) { + // 获取项目信息 + BusProject project = this.getById(id); + if (project == null) { + throw new ServiceException("查询项目不存在", HttpStatus.NOT_FOUND); + } + // 获取项目下的子项目信息 + List subProjectList = this.lambdaQuery() + .select(BusProject::getId, BusProject::getProjectName) + .eq(BusProject::getPId, id) + .list(); + if (CollUtil.isEmpty(subProjectList)) { + return List.of(); + } + List subProjectIdList = subProjectList.stream().map(BusProject::getId).toList(); + // 获取方阵信息 + List matrixList = matrixService.lambdaQuery() + .select(FacMatrix::getId, FacMatrix::getProjectId, FacMatrix::getMatrixName) + .in(FacMatrix::getProjectId, subProjectIdList) + .list(); + if (CollUtil.isEmpty(matrixList)) { + return subProjectList.stream().map(subProject -> { + BusSubProjectMatrixVo vo = new BusSubProjectMatrixVo(); + vo.setProjectId(subProject.getId()); + vo.setName(subProject.getProjectName()); + vo.setChildren(List.of()); + return vo; + }).toList(); + } + // 获取子项目下的方阵信息 + Map> matrixMap = matrixList.stream() + .collect(Collectors.groupingBy(FacMatrix::getProjectId)); + return subProjectList.stream().map(subProject -> { + BusSubProjectMatrixVo vo = new BusSubProjectMatrixVo(); + vo.setProjectId(subProject.getId()); + vo.setName(subProject.getProjectName()); + if (matrixMap.containsKey(subProject.getId())) { + List subProjectMatrix = matrixMap.get(subProject.getId()); + vo.setChildren(subProjectMatrix.stream().map(matrix -> { + FacMatrixBySubProjectVo matrixVo = new FacMatrixBySubProjectVo(); + matrixVo.setMatrixId(matrix.getId()); + matrixVo.setName(matrix.getMatrixName()); + return matrixVo; + }).toList()); + } + return vo; + }).toList(); + } + + /** + * 查询当前登录用户项目列表以及项目列表下的分包公司列表 + * + * @return 项目列表以及项目列表下的分包公司列表 + */ + @Override + public List queryProjectContractorList() { + Long userId = LoginHelper.getUserId(); + // 获取当前登录用户的项目列表 + LambdaQueryWrapper userProjectRelevancyLqw = Wrappers.lambdaQuery(BusUserProjectRelevancy.class) + .select(BusUserProjectRelevancy::getProjectId) + .eq(BusUserProjectRelevancy::getUserId, userId); + List projectIdList = userProjectRelevancyService.listObjs(userProjectRelevancyLqw, obj -> (Long) obj); + List projectList = this.listByIds(projectIdList); + // 获取项目列表下的分包公司列表 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.in(SubContractor::getProjectId, projectIdList); + Map> projectIdContractorList = contractorService.list(lqw).stream() + .collect(Collectors.groupingBy(SubContractor::getProjectId)); + // 获取封装 + return projectList.stream() + .filter(project -> { + List contractorList = projectIdContractorList.get(project.getId()); + return !CollUtil.isEmpty(contractorList); // 过滤掉没有分包单位的项目 + }) + .map(project -> { + BusProjectContractorListVo projectContractorListResp = new BusProjectContractorListVo(); + // 添加项目信息 + projectContractorListResp.setId(project.getId()); + projectContractorListResp.setProjectName(project.getProjectName()); + // 获取分包公司列表 + List contractorList = projectIdContractorList.get(project.getId()); + List idAndNameVOS = contractorList.stream() + .map(contractor -> IdAndNameVO.build(contractor.getId(), contractor.getName())).toList(); + projectContractorListResp.setContractorList(idAndNameVOS); + return projectContractorListResp; + }).toList(); + } + + /** + * 新增项目 + * + * @param req 项目 + * @return 新项目 id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(BusProjectCreateReq req) { + // 将实体类和 DTO 进行转换 + BusProject project = new BusProject(); + BeanUtils.copyProperties(req, project); + String playCardStart = req.getPlayCardStart(); + String playCardEnd = req.getPlayCardEnd(); + String punchRange = playCardStart + "," + playCardEnd; + project.setPunchRange(punchRange); + // 数据校验 + validEntityBeforeSave(project, true); + if (this.lambdaQuery().eq(BusProject::getProjectName, req.getProjectName()).count() > 0) { + throw new ServiceException("项目名称已存在", HttpStatus.BAD_REQUEST); + } + if (this.lambdaQuery().eq(BusProject::getShortName, req.getShortName()).count() > 0) { + throw new ServiceException("项目简称已存在", HttpStatus.BAD_REQUEST); + } + // 写入数据库 + boolean save = this.save(project); + if (!save) { + throw new ServiceException("新增项目失败,数据库异常", HttpStatus.ERROR); + } + Long projectId = project.getId(); + // 保存管理员与项目关联 + BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy(); + userProjectRelevancy.setUserId(SystemConstants.SUPER_ADMIN_ID); + userProjectRelevancy.setProjectId(projectId); + boolean saveRelevancy = userProjectRelevancyService.save(userProjectRelevancy); + if (!saveRelevancy) { + throw new ServiceException("新增用户与项目关联失败,数据库异常", HttpStatus.ERROR); + } + // 异步执行数据同步 + self.insertProjectSyncThing(projectId) + .thenAccept(result -> log.info("项目[{}-{}]异步执行数据同步成功", req.getProjectName(), projectId)) + .exceptionally(ex -> { + log.error("项目[{}-{}]异步执行数据同步失败", req.getProjectName(), projectId, ex); + return null; + }); + // 返回新写入的数据 projectId + return projectId; + } + + /** + * 新增子项目 + * + * @param dto 子项目 + * @return 子项目 id + */ + @Override + public Long insertSubByProject(BusProjectCreateSubReq dto) { + String projectName = dto.getProjectName(); + Long pId = dto.getPId(); + if (StringUtils.isBlank(projectName)) { + throw new ServiceException("子项目名称不能为空", HttpStatus.BAD_REQUEST); + } + BusProject project = this.getById(pId); + if (project == null) { + throw new ServiceException("父项目不存在", HttpStatus.NOT_FOUND); + } + // 权限校验 + Long userId = LoginHelper.getUserId(); + validAuth(project.getId(), userId); + BusProject subProject = new BusProject(); + subProject.setPId(pId); + subProject.setProjectName(projectName); + boolean save = this.save(subProject); + if (!save) { + throw new ServiceException("新增子项目失败,数据库异常", HttpStatus.ERROR); + } + Long subProjectId = subProject.getId(); + // 同步保存用户与项目关联 + Set userIdList = new HashSet<>(List.of(userId, SystemConstants.SUPER_ADMIN_ID)); + List userProjectRelevancyList = userIdList.stream().map(id -> { + BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy(); + userProjectRelevancy.setUserId(id); + userProjectRelevancy.setProjectId(subProjectId); + return userProjectRelevancy; + }).toList(); + boolean saveRelevancy = userProjectRelevancyService.saveBatch(userProjectRelevancyList); + if (!saveRelevancy) { + throw new ServiceException("新增用户与项目关联失败,数据库异常", HttpStatus.ERROR); + } + return subProjectId; + } + + /** + * 创建项目需同步的事务 + * + * @param id 项目id + * @return 是否同步成功 + */ + @Async + @Override + public CompletableFuture insertProjectSyncThing(Long id) { + BusProject project = this.getById(id); + if (project == null) { + log.error("同步数据失败,项目[{}]不存在", id); + return CompletableFuture.completedFuture(false); + } + // 安全、质量知识库文件夹模版 + Boolean saveHseKnowledgeDocument = hseKnowledgeDocumentService.insertFolderByTemplate(id); + if (!saveHseKnowledgeDocument) { + log.error("同步数据失败,项目[{}]新增安全知识库文件夹模版失败", id); + } + Boolean saveQltKnowledgeDocument = qltKnowledgeDocumentService.insertFolderByTemplate(id); + if (!saveQltKnowledgeDocument) { + log.error("同步数据失败,项目[{}]新增质量知识库文件夹模版失败", id); + } + // 技术标准管理文件夹模版 + Boolean saveTechnicalStandard = desTechnicalStandardService.insertFolderByTemplate(id); + if (!saveTechnicalStandard) { + log.error("同步数据失败,项目[{}]新增技术标准管理文件夹模版失败", id); + } + // 流程定义模版 + flwDefinitionService.insertDefByProjectId(id); + return CompletableFuture.completedFuture(true); + } + + /** + * 修改项目 + * + * @param req 项目 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusProjectUpdateReq req) { + // 将实体类和 DTO 进行转换 + BusProject project = new BusProject(); + BeanUtils.copyProperties(req, project); + String playCardStart = req.getPlayCardStart(); + String playCardEnd = req.getPlayCardEnd(); + if (StringUtils.isNotBlank(playCardStart) && StringUtils.isNotBlank(playCardEnd)) { + String punchRange = playCardStart + "," + playCardEnd; + project.setPunchRange(punchRange); + } + // 数据校验 + validEntityBeforeSave(project, false); + // 权限校验 + Long userId = LoginHelper.getUserId(); + validAuth(project.getId(), userId); + // 判断是否存在 + BusProject oldProject = this.getById(project.getId()); + if (oldProject == null) { + throw new ServiceException("修改项目失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 判断名称是否重复 + if (req.getProjectName() != null && !req.getProjectName().equals(oldProject.getProjectName())) { + Long count = this.lambdaQuery().eq(BusProject::getProjectName, req.getProjectName()).count(); + if (count > 0) { + throw new ServiceException("项目名称重复", HttpStatus.BAD_REQUEST); + } + } + // 操作数据库 + return this.updateById(project); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusProject entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + String projectName = entity.getProjectName(); + String principalPhone = entity.getPrincipalPhone(); + // 新增项目参数验证 + if (create) { + if (StringUtils.isBlank(projectName)) { + throw new ServiceException("项目名称不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(principalPhone)) { + throw new ServiceException("负责人电话不能为空", HttpStatus.BAD_REQUEST); + } + } + if (StringUtils.isNotBlank(principalPhone) && !PhoneUtil.isPhone(principalPhone)) { + throw new ServiceException("负责人手机号格式不正确", HttpStatus.BAD_REQUEST); + } + } + + /** + * 校验并批量删除项目信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + this.validAuth(ids, userId); + // 查看是否有子项目 + Long count = this.lambdaQuery() + .in(BusProject::getPId, ids) + .count(); + if (count > 0) { + throw new ServiceException("删除项目中存在子项目,请先删除子项目", HttpStatus.BAD_REQUEST); + } + } + // 删除项目 + boolean removeProjectList = this.removeBatchByIds(ids); + if (!removeProjectList) { + throw new ServiceException("删除项目失败,数据库异常", HttpStatus.ERROR); + } + // 删除用户与项目关联表 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.in(BusUserProjectRelevancy::getProjectId, ids); + boolean removeRelevancyList = userProjectRelevancyService.remove(lqw); + if (!removeRelevancyList) { + throw new ServiceException("删除项目与用户关联失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 获取项目视图对象 + * + * @param project 项目对象 + * @return 项目视图对象 + */ + @Override + public BusProjectVo getVo(BusProject project) { + if (project == null) { + return null; + } + // 对象转封装类 + BusProjectVo projectVo = new BusProjectVo(); + BeanUtils.copyProperties(project, projectVo); + String punchRange = project.getPunchRange(); + if (StringUtils.isNotBlank(punchRange)) { + String[] split = punchRange.split(","); + projectVo.setPlayCardStart(split[0]); + projectVo.setPlayCardEnd(split[1]); + } + // 关联子项目列表 + List subProjectList = this.lambdaQuery() + .select(BusProject::getId, BusProject::getProjectName, BusProject::getCreateTime) + .eq(BusProject::getPId, project.getId()) + .list(); + if (CollUtil.isNotEmpty(subProjectList)) { + List subIdList = subProjectList.stream().map(BusProject::getId).toList(); + // 关联设计id + List projectFileList = projectFileService.lambdaQuery() + .in(BusProjectFile::getProjectId, subIdList) + .list(); + Map> map = projectFileList.stream().collect(Collectors.groupingBy(BusProjectFile::getProjectId)); + List subProjectVoList = subProjectList.stream().map(subProject -> { + BusSubProjectVo subProjectVo = new BusSubProjectVo(); + BeanUtils.copyProperties(subProject, subProjectVo); + Long id = subProject.getId(); + if (map.containsKey(id)) { + subProjectVo.setDesignId(map.get(id).getFirst().getId()); + } + return subProjectVo; + }).toList(); + projectVo.setChildren(subProjectVoList); + } + return projectVo; + } + + /** + * 获取项目查询条件封装(不查询子项目) + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusProjectQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + String projectName = req.getProjectName(); + String shortName = req.getShortName(); + Long pId = req.getPId(); + String status = req.getStatus(); + String remark = req.getRemark(); + String projectType = req.getProjectType(); + String projectCategory = req.getProjectCategory(); + String projectSite = req.getProjectSite(); + String principal = req.getPrincipal(); + String principalPhone = req.getPrincipalPhone(); + String actual = req.getActual(); + String plan = req.getPlan(); + String onStreamTime = req.getOnStreamTime(); + String punchRange = req.getPunchRange(); + Long designTotal = req.getDesignTotal(); + String showHidden = req.getShowHidden(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(projectName), BusProject::getProjectName, projectName); + lqw.like(StringUtils.isNotBlank(shortName), BusProject::getShortName, shortName); + lqw.like(StringUtils.isNotBlank(remark), BusProject::getRemark, remark); + lqw.like(StringUtils.isNotBlank(projectSite), BusProject::getProjectSite, projectSite); + lqw.like(StringUtils.isNotBlank(principal), BusProject::getPrincipal, principal); + lqw.like(StringUtils.isNotBlank(principalPhone), BusProject::getPrincipalPhone, principalPhone); + lqw.like(StringUtils.isNotBlank(actual), BusProject::getActual, actual); + lqw.like(StringUtils.isNotBlank(plan), BusProject::getPlan, plan); + lqw.like(StringUtils.isNotBlank(onStreamTime), BusProject::getOnStreamTime, onStreamTime); + lqw.like(StringUtils.isNotBlank(punchRange), BusProject::getPunchRange, punchRange); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(pId), BusProject::getPId, pId); + lqw.eq(ObjectUtils.isNotEmpty(status), BusProject::getStatus, status); + lqw.eq(ObjectUtils.isNotEmpty(id), BusProject::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectType), BusProject::getProjectType, projectType); + lqw.eq(ObjectUtils.isNotEmpty(projectCategory), BusProject::getProjectCategory, projectCategory); + lqw.eq(ObjectUtils.isNotEmpty(designTotal), BusProject::getDesignTotal, designTotal); + lqw.eq(ObjectUtils.isNotEmpty(showHidden), BusProject::getShowHidden, showHidden); + // 排序 + lqw.orderByAsc(BusProject::getSort); + // 不查询子项目 + final Long PID = 0L; + lqw.eq(BusProject::getPId, PID); + return lqw; + } + + + @Override + public Page getVoPage(Page projectPage) { + List projectList = projectPage.getRecords(); + Page projectVoPage = new Page<>(projectPage.getCurrent(), projectPage.getSize(), projectPage.getTotal()); + if (CollUtil.isEmpty(projectList)) { + return projectVoPage; + } + // 获取项目文件id + Set projectIdList = projectList.stream().map(BusProject::getId).collect(Collectors.toSet()); + // 获取子项目列表 + List subProjectList = this.lambdaQuery() + .select(BusProject::getId, BusProject::getPId, BusProject::getProjectName, BusProject::getCreateTime) + .in(BusProject::getPId, projectIdList) + .list(); + Set subIdList = subProjectList.stream().map(BusProject::getId).collect(Collectors.toSet()); + Map> subProjectMap = subProjectList.stream().collect(Collectors.groupingBy(BusProject::getPId)); + Map> projectFileMap = projectFileService.lambdaQuery() + .in(CollUtil.isNotEmpty(subIdList), BusProjectFile::getProjectId, subIdList).list() + .stream().collect(Collectors.groupingBy(BusProjectFile::getProjectId)); + + // 对象列表 => 封装对象列表 + List projectVoList = projectList.stream().map(project -> { + // 对象转封装类 + BusProjectVo projectVo = new BusProjectVo(); + BeanUtils.copyProperties(project, projectVo); + String punchRange = project.getPunchRange(); + if (StringUtils.isNotBlank(punchRange)) { + String[] split = punchRange.split(","); + projectVo.setPlayCardStart(split[0]); + projectVo.setPlayCardEnd(split[1]); + } + // 关联子项目 + List subProjectVoList = new ArrayList<>(); + if (subProjectMap.containsKey(project.getId())) { + subProjectVoList = subProjectMap.get(project.getId()).stream().map(subProject -> { + BusSubProjectVo subProjectVo = new BusSubProjectVo(); + BeanUtils.copyProperties(subProject, subProjectVo); + Long id = subProject.getId(); + // 关联设计id + if (projectFileMap.containsKey(id)) { + subProjectVo.setDesignId(projectFileMap.get(id).getFirst().getId()); + } + return subProjectVo; + }).toList(); + } + projectVo.setChildren(subProjectVoList); + return projectVo; + }).toList(); + projectVoPage.setRecords(projectVoList); + return projectVoPage; + } + + /** + * 校验用户是否拥有操作项目的权限 + * + * @param projectId 项目对象 + * @param userId 需要鉴权的用户id + */ + @Override + public void validAuth(Long projectId, Long userId) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(BusUserProjectRelevancy::getProjectId, projectId); + lqw.eq(BusUserProjectRelevancy::getUserId, userId); + if (userProjectRelevancyService.count(lqw) <= 0) { + throw new ServiceException("当前用户无该项目权限操作", HttpStatus.FORBIDDEN); + } + } + + /** + * 校验用户是否拥有操作项目的权限 + * + * @param projectIdList 项目id列表 + * @param userId 需要鉴权的用户id + */ + @Override + public void validAuth(Collection projectIdList, Long userId) { + // 查询关联表,返回和用户关联的项目ID列表 + Set collect = userProjectRelevancyService.listObjs( + new LambdaQueryWrapper() + .select(BusUserProjectRelevancy::getProjectId) + .in(BusUserProjectRelevancy::getProjectId, projectIdList) + .eq(BusUserProjectRelevancy::getUserId, userId) + .groupBy(BusUserProjectRelevancy::getProjectId) + ).stream().map(obj -> (Long) obj).collect(Collectors.toSet()); + // 找出没有关联数据的项目ID + List invalidIds = projectIdList.stream() + .filter(id -> !collect.contains(id)) + .toList(); + if (!invalidIds.isEmpty()) { + throw new ServiceException("操作失败,项目编号为:" + invalidIds + ",没有操作权限", HttpStatus.FORBIDDEN); + } + } + + /** + * 获取天气信息 + * + * @param id 项目id + * @return 天气信息列表 + */ + @Override + public List getWeather(Long id) { + BusProject project = this.getById(id); + if (project == null) { + throw new ServiceException("项目不存在"); + } + // 构建缓存 key + String cacheKey = String.format("%s:%s", BusProjectConstant.PROJECT_WEATHER_LIST_VO_REDIS_KEY_PREFIX, id); + // 查询本地缓存(caffeine) + String cachedValue = WEATHER_CACHE.getIfPresent(cacheKey); + if (cachedValue != null) { + // 如果缓存命中,返回结果 + return JSONUtil.toList(cachedValue, BusProjectWeatherVo.class); + } + // 查询分布式缓存(Redis) + ValueOperations valueOps = stringRedisTemplate.opsForValue(); + cachedValue = valueOps.get(cacheKey); + if (cachedValue != null) { + // 如果命中Redis,存入本地缓存并返回结果 + WEATHER_CACHE.put(cacheKey, cachedValue); + return JSONUtil.toList(cachedValue, BusProjectWeatherVo.class); + } + // 获取当天及之后的天气信息 + String lng = project.getLng(); + String lat = project.getLat(); + if (StringUtils.isAnyBlank(lng, lat)) { + throw new ServiceException("项目坐标信息为空"); + } + String weatherStr = weatherManager.getWeather(lng, lat, WeatherConstant.THREE_DAYS_WEATHER_PATH); + // 解析为 JSONObject + JSONObject weatherJson = JSONUtil.parseObj(weatherStr); + // 获取 daily 数组 + JSONArray dailyArray = weatherJson.getJSONArray(WeatherConstant.DAILY); + // 循环遍历,封装项目天气信息 + List weatherList = new ArrayList<>(); + for (int i = 0; i < dailyArray.size(); i++) { + JSONObject day = dailyArray.getJSONObject(i); + BusProjectWeatherVo weatherVo = new BusProjectWeatherVo(); + // 获取星期 + String dateStr = day.getStr(WeatherConstant.FX_DATE); + DateTime date = DateUtil.parse(dateStr, "yyyy-MM-dd"); + String week = DateUtil.format(date, "EEE"); + // 获取天气图标 + String textDay = day.getStr(WeatherConstant.TEXT_DAY); + String textNight = day.getStr(WeatherConstant.TEXT_NIGHT); + Map> weatherStatusMap = WeatherConstant.getWeatherStatusMap(); + String dayStatus = getWeatherCategory(textDay, weatherStatusMap); + String nightStatus = getWeatherCategory(textNight, weatherStatusMap); + // 封装数据 + weatherVo.setDate(dateStr); + weatherVo.setWeek(week); + weatherVo.setTempMax(day.getStr(WeatherConstant.TEMP_MAX)); + weatherVo.setTempMin(day.getStr(WeatherConstant.TEMP_MIN)); + weatherVo.setSunRise(day.getStr(WeatherConstant.SUN_RISE)); + weatherVo.setSunSet(day.getStr(WeatherConstant.SUN_SET)); + weatherVo.setDayStatus(textDay); + weatherVo.setNightStatus(textNight); + weatherVo.setDayIcon(dayStatus); + weatherVo.setNightIcon(nightStatus); + weatherList.add(weatherVo); + } + // 更新缓存 + String cacheValue = JSONUtil.toJsonStr(weatherList); + // 更新本地缓存 + WEATHER_CACHE.put(cacheKey, cacheValue); + // 更新 Redis 缓存,设置 5 - 10 分钟随机过期,防止雪崩 + int cacheExpireTime = 60 * 60 + RandomUtil.randomInt(0, 300); + valueOps.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.SECONDS); + // 返回结果 + return weatherList; + } + + /** + * 获取项目安全天数 + * + * @param id 项目id + * @return 安全天数 + */ + @Override + public BusProjectSafetyDayVo getSafetyDay(Long id) { + // 构建缓存 key + String cacheKey = String.format("%s:%s", BusProjectConstant.PROJECT_SAFETY_DAYS_REDIS_KEY_PREFIX, id); + // 查询分布式缓存(Redis) + ValueOperations valueOps = stringRedisTemplate.opsForValue(); + String cachedValue = valueOps.get(cacheKey); + if (cachedValue != null) { + // 如果命中Redis,返回结果 + return JSONUtil.toBean(cachedValue, BusProjectSafetyDayVo.class); + } + BusProject project = this.getById(id); + if (project == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + int days = DateUtils.differentDaysByMillisecond(project.getCreateTime(), new Date()); + BusProjectSafetyDayVo safetyDayVo = new BusProjectSafetyDayVo(); + safetyDayVo.setSafetyDay(days); + // 更新缓存 + String cacheValue = JSONUtil.toJsonStr(safetyDayVo); + // 更新 Redis 缓存 + int cacheExpireTime = 12; + valueOps.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.HOURS); + // 返回结果 + return safetyDayVo; + } + + /** + * 根据天气图标获取天气类别 + * + * @param icon 天气图标 + * @param map 天气图标与天气类别的映射关系 + * @return 天气类别 + */ + public static String getWeatherCategory(String icon, Map> map) { + for (Map.Entry> entry : map.entrySet()) { + if (entry.getValue().contains(icon)) { + return entry.getKey(); + } + } + return "cloudy"; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamMemberServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamMemberServiceImpl.java new file mode 100644 index 0000000..857573b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamMemberServiceImpl.java @@ -0,0 +1,360 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.domain.BusConstructionUserExit; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.project.domain.enums.BusProjectTeamMemberPostEnum; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberCreateReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberExitReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberQueryReq; +import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberUpdateReq; +import org.dromara.project.domain.vo.projectteammember.BusProjectTeamMemberVo; +import org.dromara.project.mapper.BusProjectTeamMemberMapper; +import org.dromara.project.service.*; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 项目班组下的成员Service业务层处理 + * + * @author lilemy + * @date 2025-03-07 + */ +@Service +public class BusProjectTeamMemberServiceImpl extends ServiceImpl + implements IBusProjectTeamMemberService { + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private IBusProjectTeamService projectTeamService; + + @Resource + private IBusProjectService projectService; + + @Resource + private IBusConstructionBlacklistService constructionBlacklistService; + + @Resource + private IBusConstructionUserExitService constructionUserExitService; + + /** + * 查询项目班组下的成员 + * + * @param id 主键 + * @return 项目班组下的成员 + */ + @Override + public BusProjectTeamMemberVo queryById(Long id) { + BusProjectTeamMember projectTeamMember = this.getById(id); + if (projectTeamMember == null) { + throw new ServiceException("对应项目班组下的成员不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(projectTeamMember); + } + + /** + * 分页查询项目班组下的成员列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目班组下的成员分页列表 + */ + @Override + public TableDataInfo queryPageList(BusProjectTeamMemberQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的项目班组下的成员列表 + * + * @param req 查询条件 + * @return 项目班组下的成员列表 + */ + @Override + public List queryList(BusProjectTeamMemberQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + List list = this.list(lqw); + return list.stream().map(this::getVo).toList(); + } + + /** + * 新增项目班组下的成员 + * + * @param req 项目班组下的成员 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(BusProjectTeamMemberCreateReq req) { + // 将实体类和 DTO 进行转换 + BusProjectTeamMember projectTeamMember = new BusProjectTeamMember(); + BeanUtils.copyProperties(req, projectTeamMember); + // 数据校验 + validEntityBeforeSave(projectTeamMember, true); + // 判断班组信息是否存在 + Long teamId = req.getTeamId(); + BusProjectTeam projectTeam = projectTeamService.getById(teamId); + if (projectTeam == null) { + throw new ServiceException("对应班组不存在", HttpStatus.NOT_FOUND); + } + // 判断用户是否已经被拉黑 + constructionBlacklistService.validUserInBlacklist(projectTeamMember.getMemberId(), projectTeamMember.getProjectId()); + // 判断对应的用户与项目关联是否存在 + BusProjectTeamMember teamMember = this.getOne(new LambdaQueryWrapper() + .eq(BusProjectTeamMember::getMemberId, projectTeamMember.getMemberId()) + .eq(BusProjectTeamMember::getProjectId, projectTeamMember.getProjectId())); + if (teamMember != null) { + throw new ServiceException("当前用户已入场", HttpStatus.BAD_REQUEST); + } + // 操作数据库 + boolean save = this.save(projectTeamMember); + if (!save) { + throw new ServiceException("新增项目班组下的成员失败,数据库异常", HttpStatus.ERROR); + } + // 同步修改用户表的team_id字段并添加入场时间 + LambdaUpdateWrapper constructionUserLuw = Wrappers.lambdaUpdate(SubConstructionUser.class) + .eq(SubConstructionUser::getId, projectTeamMember.getMemberId()) + .set(SubConstructionUser::getTeamId, projectTeamMember.getTeamId()) + .set(SubConstructionUser::getTeamName, projectTeam.getTeamName()) + .set(SubConstructionUser::getEntryDate, new Date()) + .set(SubConstructionUser::getLeaveDate, null); + constructionUserService.update(constructionUserLuw); + return projectTeamMember.getId(); + } + + /** + * 修改项目班组下的成员 + * + * @param req 项目班组下的成员 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(BusProjectTeamMemberUpdateReq req) { + // 将实体类和 DTO 进行转换 + BusProjectTeamMember projectTeamMember = new BusProjectTeamMember(); + BeanUtils.copyProperties(req, projectTeamMember); + // 数据校验 + validEntityBeforeSave(projectTeamMember, false); + // 判断班组信息是否存在 + Long teamId = req.getTeamId(); + BusProjectTeam projectTeam = projectTeamService.getById(teamId); + if (projectTeam == null) { + throw new ServiceException("对应班组不存在", HttpStatus.NOT_FOUND); + } + // 判断是否存在 + BusProjectTeamMember oldProjectTeamMember = this.getById(projectTeamMember.getId()); + if (oldProjectTeamMember == null) { + throw new ServiceException("修改项目班组下的成员,数据不存在", HttpStatus.NOT_FOUND); + } + // 如果修改了班组信息,同步修改用户表的字段 + if (!oldProjectTeamMember.getTeamId().equals(teamId)) { + LambdaUpdateWrapper constructionUserLuw = Wrappers.lambdaUpdate(SubConstructionUser.class) + .eq(SubConstructionUser::getId, projectTeamMember.getMemberId()) + .set(SubConstructionUser::getTeamId, projectTeamMember.getTeamId()) + .set(SubConstructionUser::getTeamName, projectTeam.getTeamName()); + constructionUserService.update(constructionUserLuw); + } + // 操作数据库 + return this.updateById(projectTeamMember); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusProjectTeamMember entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long memberId = entity.getMemberId(); + String postId = entity.getPostId(); + BusProjectTeamMemberPostEnum postEnum = BusProjectTeamMemberPostEnum.getEnumByValue(postId); + if (create) { + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (memberId == null) { + throw new ServiceException("人员 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (postEnum == null) { + throw new ServiceException("请选择正确的岗位", HttpStatus.BAD_REQUEST); + } + } + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (constructionUserService.getById(memberId) == null) { + throw new ServiceException("对应人员不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 根据主键删除项目班组与人员关联(人员退场) + * + * @param req 班组人员退场对象 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteById(BusProjectTeamMemberExitReq req) { + // 判断是否有权限操作对应项目下的内容 + Long userId = LoginHelper.getUserId(); + Long id = req.getId(); + String filePath = req.getFilePath(); + if (StringUtils.isBlank(filePath)) { + throw new ServiceException("请上传退场文件", HttpStatus.BAD_REQUEST); + } + BusProjectTeamMember projectTeamMember = this.getById(id); + if (projectTeamMember == null) { + throw new ServiceException("对应项目班组下的成员不存在", HttpStatus.NOT_FOUND); + } + projectService.validAuth(projectTeamMember.getProjectId(), userId); + boolean result = this.removeById(id); + if (!result) { + throw new ServiceException("删除项目班组下的成员失败,数据库异常", HttpStatus.ERROR); + } + // 将文件信息保存到数据库 + SubConstructionUser constructionUser = constructionUserService.getById(projectTeamMember.getMemberId()); + BusConstructionUserExit constructionUserExit = new BusConstructionUserExit(); + constructionUserExit.setProjectId(constructionUser.getProjectId()); + constructionUserExit.setUserId(constructionUser.getId()); + constructionUserExit.setPath(filePath); + constructionUserExit.setTeamId(constructionUser.getTeamId()); + constructionUserExit.setSfzNumber(constructionUser.getSfzNumber()); + constructionUserExit.setEntryDate(constructionUser.getEntryDate()); + constructionUserExit.setLeaveDate(new Date()); + constructionUserExit.setRemark(req.getRemark()); + constructionUserExitService.save(constructionUserExit); + // 同步修改用户表的team_id字段 + LambdaUpdateWrapper constructionUserLuw = Wrappers.lambdaUpdate(SubConstructionUser.class) + .eq(SubConstructionUser::getId, projectTeamMember.getMemberId()) + .set(SubConstructionUser::getTeamId, null) + .set(SubConstructionUser::getLeaveDate, new Date()); + constructionUserService.update(constructionUserLuw); + return true; + } + + /** + * 获取项目班组成员视图对象 + * + * @param projectTeamMember 项目班组成员对象 + * @return 项目班组成员视图对象 + */ + @Override + public BusProjectTeamMemberVo getVo(BusProjectTeamMember projectTeamMember) { + // 对象转封装类 + BusProjectTeamMemberVo projectTeamMemberVo = new BusProjectTeamMemberVo(); + if (projectTeamMember == null) { + return projectTeamMemberVo; + } + BeanUtils.copyProperties(projectTeamMember, projectTeamMemberVo); + // 关联获取施工人员信息 + Long memberId = projectTeamMember.getMemberId(); + SubConstructionUser constructionUser = constructionUserService.getById(memberId); + projectTeamMemberVo.setMemberName(constructionUser.getUserName()); + return projectTeamMemberVo; + } + + /** + * 获取项目班组成员查询条件封装 + * + * @param req 项目班组成员查询条件 + * @return 项目班组成员查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusProjectTeamMemberQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + Long teamId = req.getTeamId(); + Long projectId = req.getProjectId(); + Long memberId = req.getMemberId(); + String memberName = req.getMemberName(); + String postId = req.getPostId(); + String remark = req.getRemark(); + // 联表查询 + if (StringUtils.isNotBlank(memberName)) { + QueryWrapper constructionUserQueryWrapper = new QueryWrapper<>(); + constructionUserQueryWrapper.select("id"); + constructionUserQueryWrapper.like("user_name", memberName); + List constructionUserIdList = constructionUserService.listObjs(constructionUserQueryWrapper, obj -> (Long) obj); + lqw.in(BusProjectTeamMember::getMemberId, constructionUserIdList); + } + // 模糊查询 + lqw.like(StringUtils.isNotBlank(remark), BusProjectTeamMember::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusProjectTeamMember::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusProjectTeamMember::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), BusProjectTeamMember::getTeamId, teamId); + lqw.eq(ObjectUtils.isNotEmpty(memberId), BusProjectTeamMember::getMemberId, memberId); + lqw.eq(ObjectUtils.isNotEmpty(postId), BusProjectTeamMember::getPostId, postId); + return lqw; + } + + /** + * 获取项目班组成员分页对象视图 + * + * @param projectTeamMemberPage 项目班组成员分页对象 + * @return 项目班组成员分页对象视图 + */ + @Override + public Page getVoPage(Page projectTeamMemberPage) { + List projectTeamMemberList = projectTeamMemberPage.getRecords(); + Page projectTeamMemberVoPage = new Page<>( + projectTeamMemberPage.getCurrent(), + projectTeamMemberPage.getSize(), + projectTeamMemberPage.getTotal()); + if (CollUtil.isEmpty(projectTeamMemberList)) { + return projectTeamMemberVoPage; + } + // 关联查询施工人员信息 + Set teamMemberIdSet = projectTeamMemberList.stream().map(BusProjectTeamMember::getMemberId) + .collect(Collectors.toSet()); + Map> contractorIdContractorList = constructionUserService.listByIds(teamMemberIdSet).stream() + .collect(Collectors.groupingBy(SubConstructionUser::getId)); + // 填充信息 + List projectTeamMemberVoList = projectTeamMemberList.stream().map(projectTeamMember -> { + BusProjectTeamMemberVo projectTeamMemberVo = new BusProjectTeamMemberVo(); + BeanUtils.copyProperties(projectTeamMember, projectTeamMemberVo); + Long memberId = projectTeamMember.getMemberId(); + String memberName = null; + if (contractorIdContractorList.containsKey(memberId)) { + memberName = contractorIdContractorList.get(memberId).get(0).getUserName(); + } + projectTeamMemberVo.setMemberName(memberName); + return projectTeamMemberVo; + }).toList(); + projectTeamMemberVoPage.setRecords(projectTeamMemberVoList); + return projectTeamMemberVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamServiceImpl.java new file mode 100644 index 0000000..8aadbc3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectTeamServiceImpl.java @@ -0,0 +1,338 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.project.domain.enums.BusProjectTeamMemberPostEnum; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamCreateReq; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq; +import org.dromara.project.domain.dto.projectteam.BusProjectTeamUpdateReq; +import org.dromara.project.domain.vo.projectteam.BusForemanVo; +import org.dromara.project.domain.vo.projectteam.BusProjectTeamForemanVo; +import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo; +import org.dromara.project.mapper.BusProjectTeamMapper; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusProjectTeamMemberService; +import org.dromara.project.service.IBusProjectTeamService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 项目班组Service业务层处理 + * + * @author lilemy + * @date 2025-03-07 + */ +@Service +public class BusProjectTeamServiceImpl extends ServiceImpl + implements IBusProjectTeamService { + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private IBusProjectTeamMemberService projectTeamMemberService; + + @Lazy + @Resource + private ISubConstructionUserService constructionUserService; + + /** + * 查询项目班组 + * + * @param id 主键 + * @return 项目班组 + */ + @Override + public BusProjectTeamVo queryById(Long id) { + BusProjectTeam projectTeam = this.getById(id); + if (projectTeam == null) { + throw new ServiceException("对应项目班组不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(projectTeam); + } + + /** + * 分页查询项目班组列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 项目班组分页列表 + */ + @Override + public TableDataInfo queryPageList(BusProjectTeamQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的项目班组列表 + * + * @param req 查询条件 + * @return 项目班组列表 + */ + @Override + public List queryList(BusProjectTeamQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + List list = this.list(lqw); + return list.stream().map(this::getVo).toList(); + } + + /** + * 新增项目班组 + * + * @param req 项目班组 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(BusProjectTeamCreateReq req) { + // 将实体类和 DTO 进行转换 + BusProjectTeam projectTeam = new BusProjectTeam(); + BeanUtils.copyProperties(req, projectTeam); + // 数据校验 + validEntityBeforeSave(projectTeam); + // 操作数据库 + boolean save = this.save(projectTeam); + if (!save) { + throw new ServiceException("新增项目班组失败,数据库异常", HttpStatus.ERROR); + } + return projectTeam.getId(); + } + + /** + * 修改项目班组 + * + * @param req 项目班组 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusProjectTeamUpdateReq req) { + // 将实体类和 DTO 进行转换 + BusProjectTeam projectTeam = new BusProjectTeam(); + BeanUtils.copyProperties(req, projectTeam); + // 数据校验 + validEntityBeforeSave(projectTeam); + // 判断是否存在 + BusProjectTeam oldProjectTeam = this.getById(projectTeam.getId()); + if (oldProjectTeam == null) { + throw new ServiceException("修改项目班组失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(projectTeam); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusProjectTeam entity) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + // 判断是否重名 + String teamName = entity.getTeamName(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(BusProjectTeam::getTeamName, teamName); + long count = this.count(queryWrapper); + if (count > 0) { + throw new ServiceException("项目组名重复", HttpStatus.BAD_REQUEST); + } + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + // 查询项目是否存在 + if (projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + // 判断用户是否对项目下的内容有操作权限 + Long userId = LoginHelper.getUserId(); + projectService.validAuth(projectId, userId); + } + + /** + * 校验并批量删除项目班组信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + // 获取当前登录用户 + Long userId = LoginHelper.getUserId(); + // 获取待删除数据详情 + List projectTeamList = this.listByIds(ids); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + // 获取项目id列表 + List projectIdList = projectTeamList.stream().map(BusProjectTeam::getProjectId).toList(); + // 判断是否有权限操作对应项目下的内容 + projectService.validAuth(projectIdList, userId); + } + // 判断对应数据是否都存在 + if (projectTeamList.size() != ids.size()) { + throw new ServiceException("删除项目班组失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return this.removeBatchByIds(ids); + } + + /** + * 查询项目班组和班组长分页列表 + * + * @param projectId 项目id + * @return 项目班组和班组长分页列表 + */ + @Override + public List queryForemanList(Long projectId) { + List projectTeamList = this.list(Wrappers.lambdaQuery(BusProjectTeam.class).eq(BusProjectTeam::getProjectId, projectId)); + if (CollUtil.isEmpty(projectTeamList)) { + return List.of(); + } + // 获取项目班组id列表 + List teamIdList = projectTeamList.stream().map(BusProjectTeam::getId).toList(); + // 获取项目班组班组长id列表 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(BusProjectTeamMember.class) + .select(BusProjectTeamMember::getMemberId) + .eq(BusProjectTeamMember::getProjectId, projectId) + .in(BusProjectTeamMember::getTeamId, teamIdList) + .eq(BusProjectTeamMember::getPostId, BusProjectTeamMemberPostEnum.FOREMAN.getValue()); + Set foremanIdList = projectTeamMemberService.list(lqw).stream() + .map(BusProjectTeamMember::getMemberId).collect(Collectors.toSet()); + if (CollUtil.isEmpty(foremanIdList)) { + return List.of(); + } + // 获取项目班组长信息 + Map> foremanMap = constructionUserService.listByIds(foremanIdList).stream() + .collect(Collectors.groupingBy(SubConstructionUser::getTeamId)); + // 封装数据 + return projectTeamList.stream().map(projectTeam -> { + BusProjectTeamForemanVo projectTeamForemanResp = new BusProjectTeamForemanVo(); + projectTeamForemanResp.setId(projectTeam.getId()); + projectTeamForemanResp.setTeamName(projectTeam.getTeamName()); + projectTeamForemanResp.setProjectId(projectTeam.getProjectId()); + if (foremanMap.containsKey(projectTeam.getId())) { + List constructionUserList = foremanMap.get(projectTeam.getId()); + List foremanVoList = constructionUserList.stream() + .map(constructionUser -> new BusForemanVo(constructionUser.getId(), constructionUser.getUserName())) + .toList(); + projectTeamForemanResp.setForemanList(foremanVoList); + } + return projectTeamForemanResp; + }).toList(); + } + + /** + * 获取项目班组视图对象 + * + * @param projectTeam 项目班组对象 + * @return 项目班组视图对象 + */ + @Override + public BusProjectTeamVo getVo(BusProjectTeam projectTeam) { + // 对象转封装类 + BusProjectTeamVo projectTeamVo = new BusProjectTeamVo(); + if (projectTeam == null) { + return projectTeamVo; + } + BeanUtils.copyProperties(projectTeam, projectTeamVo); + // 获取班组人数 + Long peopleNumber = projectTeamMemberService.lambdaQuery() + .eq(BusProjectTeamMember::getTeamId, projectTeam.getId()) + .count(); + projectTeamVo.setPeopleNumber(peopleNumber); + return projectTeamVo; + } + + /** + * 获取项目班组查询条件封装 + * + * @param req 项目班组查询条件 + * @return 项目班组查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusProjectTeamQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + // 从对象中取值 + Long id = req.getId(); + Long projectId = req.getProjectId(); + String teamName = req.getTeamName(); + String isClockIn = req.getIsClockIn(); + String remark = req.getRemark(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(teamName), BusProjectTeam::getTeamName, teamName); + lqw.like(StringUtils.isNotBlank(remark), BusProjectTeam::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusProjectTeam::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusProjectTeam::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(isClockIn), BusProjectTeam::getIsClockIn, isClockIn); + return lqw; + } + + /** + * 获取项目班组分页对象视图 + * + * @param projectTeamPage 项目班组分页对象 + * @return 项目班组分页对象视图 + */ + @Override + public Page getVoPage(Page projectTeamPage) { + List projectTeamList = projectTeamPage.getRecords(); + Page projectTeamVoPage = new Page<>( + projectTeamPage.getCurrent(), + projectTeamPage.getSize(), + projectTeamPage.getTotal()); + if (CollUtil.isEmpty(projectTeamList)) { + return projectTeamVoPage; + } + // 1. 获取各班组人数 + List teamIdList = projectTeamList.stream().map(BusProjectTeam::getId).toList(); + List> mapList = projectTeamMemberService.listMaps( + new QueryWrapper() + .select("team_id", "COUNT(*) as count") + .in("team_id", teamIdList) + .groupBy("team_id") + ); + // 2. 将查询结果转换成 Map + Map teamCountMap = mapList.stream() + .collect(Collectors.toMap( + m -> ((Number) m.get("team_id")).longValue(), + m -> ((Number) m.get("count")).longValue() + )); + // 对象列表 => 封装对象列表 + List projectTeamVoList = projectTeamList.stream().map(projectTeam -> { + BusProjectTeamVo projectTeamVo = new BusProjectTeamVo(); + BeanUtils.copyProperties(projectTeam, projectTeamVo); + projectTeamVo.setPeopleNumber(teamCountMap.getOrDefault(projectTeam.getId(), 0L)); + return projectTeamVo; + }).toList(); + projectTeamVoPage.setRecords(projectTeamVoList); + return projectTeamVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusReissueCardServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusReissueCardServiceImpl.java new file mode 100644 index 0000000..ddeddc8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusReissueCardServiceImpl.java @@ -0,0 +1,278 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusAttendance; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.project.domain.BusReissueCard; +import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum; +import org.dromara.project.domain.enums.BusAttendanceCommuterEnum; +import org.dromara.project.domain.enums.BusOpinionStatusEnum; +import org.dromara.project.domain.enums.BusReviewStatusEnum; +import org.dromara.project.domain.dto.reissuecard.BusReissueCardManagerReviewReq; +import org.dromara.project.domain.dto.reissuecard.BusReissueCardQueryReq; +import org.dromara.project.domain.vo.reissuecard.BusReissueCardVo; +import org.dromara.project.mapper.BusReissueCardMapper; +import org.dromara.project.service.IBusAttendanceService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusProjectTeamService; +import org.dromara.project.service.IBusReissueCardService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 施工人员补卡申请Service业务层处理 + * + * @author lilemy + * @date 2025-04-08 + */ +@Service +public class BusReissueCardServiceImpl extends ServiceImpl + implements IBusReissueCardService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IBusProjectTeamService projectTeamService; + + @Resource + private IBusAttendanceService attendanceService; + + /** + * 查询施工人员补卡申请 + * + * @param id 主键 + * @return 施工人员补卡申请 + */ + @Override + public BusReissueCardVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询施工人员补卡申请列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员补卡申请分页列表 + */ + @Override + public TableDataInfo queryPageList(BusReissueCardQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的施工人员补卡申请列表 + * + * @param req 查询条件 + * @return 施工人员补卡申请列表 + */ + @Override + public List queryList(BusReissueCardQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return baseMapper.selectVoList(lqw); + } + + /** + * 管理员审核施工人员补卡申请 + * + * @param req 管理员审核施工人员补卡申请 + * @return 是否审核成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean managerReview(BusReissueCardManagerReviewReq req) { + Long id = req.getId(); + String managerOpinion = req.getManagerOpinion(); + // 判断该补卡记录是否存在 + BusReissueCard oldReissueCard = this.getById(id); + if (oldReissueCard == null) { + throw new ServiceException("施工人员补卡申请不存在", HttpStatus.NOT_FOUND); + } + // 如果已经审核过,则返回 + if (!BusOpinionStatusEnum.UNREAD.getValue().equals(managerOpinion)) { + throw new ServiceException("该请假已审核,请勿重复操作", HttpStatus.BAD_REQUEST); + } + // 判断班组长是否审核通过 + String gangerOpinion = oldReissueCard.getGangerOpinion(); + if (!BusOpinionStatusEnum.PASS.getValue().equals(gangerOpinion)) { + throw new ServiceException("请等待班组长审核通过后再进行操作", HttpStatus.BAD_REQUEST); + } + // todo 判断当前用户是否为项目管理员 + // 填充默认值,更新数据 + BusReissueCard reissueCard = new BusReissueCard(); + reissueCard.setId(id); + reissueCard.setManagerOpinion(managerOpinion); + reissueCard.setManagerExplain(req.getManagerExplain()); + reissueCard.setManagerTime(new Date()); + reissueCard.setRemark(req.getRemark()); + boolean result = this.updateById(reissueCard); + if (!result) { + throw new ServiceException("更新管理员审核操作失败", HttpStatus.ERROR); + } + // 更新考勤表记录 + BusAttendance oldAttendance = attendanceService.getById(oldReissueCard.getAttendanceId()); + if (oldAttendance == null) { + throw new ServiceException("考勤记录不存在", HttpStatus.NOT_FOUND); + } + BusAttendance attendance = new BusAttendance(); + BusProject project = projectService.getById(oldReissueCard.getProjectId()); + // 根据补卡类型更新考勤时间 + String[] clockTime = project.getPunchRange().split(","); + String reissueCardType = oldReissueCard.getReissueCardType(); + if (BusAttendanceCommuterEnum.CLOCKIN.getValue().equals(reissueCardType)) { + // 拼接时间,获取项目的上班打卡时间 + Date date = DateUtils.combineDateAndTime(oldAttendance.getClockDate(), clockTime[0] + ":00"); + attendance.setClockTime(date); + } else if (BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(reissueCardType)) { + // 拼接时间,获取项目的下班打卡时间 + Date date = DateUtils.combineDateAndTime(oldAttendance.getClockDate(), clockTime[1] + ":00"); + attendance.setClockTime(date); + } + attendance.setId(oldReissueCard.getAttendanceId()); + attendance.setClockStatus(BusAttendanceClockStatusEnum.REISSUE.getValue()); + boolean updateAttendance = attendanceService.updateById(attendance); + if (!updateAttendance) { + throw new ServiceException("更新考勤记录失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 校验并批量删除施工人员补卡申请信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 获取施工人员补卡申请视图对象 + * + * @param reissueCard 施工人员补卡申请对象 + * @return 施工人员补卡申请视图对象 + */ + @Override + public BusReissueCardVo getVo(BusReissueCard reissueCard) { + // 对象转封装类 + BusReissueCardVo reissueCardVo = new BusReissueCardVo(); + if (reissueCard == null) { + return reissueCardVo; + } + BeanUtils.copyProperties(reissueCard, reissueCardVo); + // 获取班组信息 + Long teamId = reissueCard.getTeamId(); + if (teamId != null) { + BusProjectTeam team = projectTeamService.lambdaQuery() + .eq(BusProjectTeam::getId, teamId).select(BusProjectTeam::getTeamName).one(); + reissueCardVo.setTeamName(team.getTeamName()); + } + // 添加审核状态 + String status = BusReviewStatusEnum.getEnumByOpinionStatus(reissueCard.getGangerOpinion(), reissueCard.getManagerOpinion()); + reissueCardVo.setStatus(status); + return reissueCardVo; + } + + /** + * 获取施工人员补卡申请查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusReissueCardQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long userId = req.getUserId(); + String userName = req.getUserName(); + Long gangerId = req.getGangerId(); + String gangerName = req.getGangerName(); + String gangerOpinion = req.getGangerOpinion(); + String managerOpinion = req.getManagerOpinion(); + Long projectId = req.getProjectId(); + Long teamId = req.getTeamId(); + String reissueCardType = req.getReissueCardType(); + Long attendanceId = req.getAttendanceId(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), BusReissueCard::getUserName, userName); + lqw.like(StringUtils.isNotBlank(gangerName), BusReissueCard::getGangerName, gangerName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusReissueCard::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(userId), BusReissueCard::getUserId, userId); + lqw.eq(ObjectUtils.isNotEmpty(gangerId), BusReissueCard::getGangerId, gangerId); + lqw.eq(StringUtils.isNotBlank(gangerOpinion), BusReissueCard::getGangerOpinion, gangerOpinion); + lqw.eq(StringUtils.isNotBlank(managerOpinion), BusReissueCard::getManagerOpinion, managerOpinion); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusReissueCard::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), BusReissueCard::getTeamId, teamId); + lqw.eq(StringUtils.isNotBlank(reissueCardType), BusReissueCard::getReissueCardType, reissueCardType); + lqw.eq(ObjectUtils.isNotEmpty(attendanceId), BusReissueCard::getAttendanceId, attendanceId); + return lqw; + } + + /** + * 获取施工人员补卡申请分页对象视图 + * + * @param reissueCardPage 施工人员补卡申请分页对象 + * @return 施工人员补卡申请分页对象视图 + */ + @Override + public Page getVoPage(Page reissueCardPage) { + List reissueCardList = reissueCardPage.getRecords(); + Page reissueCardVoPage = new Page<>( + reissueCardPage.getCurrent(), + reissueCardPage.getSize(), + reissueCardPage.getTotal()); + if (CollUtil.isEmpty(reissueCardList)) { + return reissueCardVoPage; + } + // 关联查询班组信息 + Set teamIdSet = reissueCardList.stream().map(BusReissueCard::getTeamId) + .collect(Collectors.toSet()); + Map> teamIdTeamMap = projectTeamService.listByIds(teamIdSet).stream() + .collect(Collectors.groupingBy(BusProjectTeam::getId)); + List reissueCardVoList = reissueCardList.stream().map(reissueCard -> { + BusReissueCardVo reissueCardVo = new BusReissueCardVo(); + BeanUtils.copyProperties(reissueCard, reissueCardVo); + // 关联班组信息 + Long teamId = reissueCard.getTeamId(); + String teamName = null; + if (teamIdTeamMap.containsKey(teamId)) { + teamName = projectTeamService.getVo(teamIdTeamMap.get(teamId).get(0)).getTeamName(); + } + reissueCardVo.setTeamName(teamName); + // 添加审核状态 + String status = BusReviewStatusEnum.getEnumByOpinionStatus(reissueCard.getGangerOpinion(), reissueCard.getManagerOpinion()); + reissueCardVo.setStatus(status); + return reissueCardVo; + }).toList(); + reissueCardVoPage.setRecords(reissueCardVoList); + return reissueCardVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusUserProjectRelevancyServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusUserProjectRelevancyServiceImpl.java new file mode 100644 index 0000000..b3b4348 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusUserProjectRelevancyServiceImpl.java @@ -0,0 +1,457 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.constant.BusProjectConstant; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.BusUserProjectRelevancy; +import org.dromara.project.domain.dto.project.BusProjectBatchByProjectListReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyCreateReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyQueryReq; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyUpdateReq; +import org.dromara.project.domain.vo.userprojectrelevancy.BusLoginUserProjectRelevancyVo; +import org.dromara.project.domain.vo.userprojectrelevancy.BusUserProjectRelevancyVo; +import org.dromara.project.mapper.BusUserProjectRelevancyMapper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusUserProjectRelevancyService; +import org.dromara.system.service.ISysUserService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 系统用户与项目关联Service业务层处理 + * + * @author lilemy + * @date 2025-03-04 + */ +@Service +public class BusUserProjectRelevancyServiceImpl extends ServiceImpl + implements IBusUserProjectRelevancyService { + + @Resource + private IBusProjectService projectService; + + @Lazy + @Resource + private ISysUserService userService; + + /** + * 查询系统用户与项目关联 + * + * @param id 主键 + * @return 系统用户与项目关联 + */ + @Override + public BusUserProjectRelevancyVo queryById(Long id) { + // 查询数据 + BusUserProjectRelevancy userProjectRelevancy = this.getById(id); + if (userProjectRelevancy == null) { + throw new ServiceException("对应用户与项目关联不存在", HttpStatus.NOT_FOUND); + } + // 封装并返回 + return this.getVo(userProjectRelevancy); + } + + /** + * 分页查询系统用户与项目关联列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 系统用户与项目关联分页列表 + */ + @Override + public TableDataInfo queryPageList(BusUserProjectRelevancyQueryReq req, PageQuery pageQuery) { + // 查询数据库 + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的系统用户与项目关联列表 + * + * @param req 查询条件 + * @return 系统用户与项目关联列表 + */ + @Override + public List queryList(BusUserProjectRelevancyQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增系统用户与项目关联 + * + * @param req 系统用户与项目关联 + * @return 新增关联id + */ + @Override + public Long insertByBo(BusUserProjectRelevancyCreateReq req) { + // 将实体类和 DTO 进行转换 + BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy(); + BeanUtils.copyProperties(req, userProjectRelevancy); + // 数据校验 + validEntityBeforeSave(userProjectRelevancy, true); + // 判断对应的用户与项目关联是否存在 + if (this.getOne(new LambdaQueryWrapper() + .eq(BusUserProjectRelevancy::getUserId, userProjectRelevancy.getUserId()) + .eq(BusUserProjectRelevancy::getProjectId, userProjectRelevancy.getProjectId())) != null) { + throw new ServiceException("用户和项目关联已存在", HttpStatus.CONFLICT); + } + // 写入数据库 + boolean save = this.save(userProjectRelevancy); + if (!save) { + throw new ServiceException("新增用户和项目关联失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 id + return userProjectRelevancy.getId(); + } + + /** + * 批量新增用户和项目关联 + * + * @param projectId 项目ID + * @param userIdList 用户ID列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void saveBatchByUserList(Long projectId, List userIdList) { + if (ObjectUtils.isEmpty(projectId) || ObjectUtils.isEmpty(userIdList)) { + return; + } + List userProjectRelevancyList = userIdList.stream().map(userId -> { + BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy(); + userProjectRelevancy.setUserId(userId); + userProjectRelevancy.setProjectId(projectId); + return userProjectRelevancy; + }).toList(); + boolean saveRelevancy = this.saveBatch(userProjectRelevancyList); + if (!saveRelevancy) { + throw new ServiceException("新增用户和项目关联失败,数据库异常", HttpStatus.ERROR); + } + } + + /** + * 批量新增用户和项目关联 + * + * @param projectIdList 项目ID列表 + * @param userId 用户ID + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void saveBatchByProjectList(List projectIdList, Long userId) { + if (ObjectUtils.isEmpty(projectIdList) || ObjectUtils.isEmpty(userId)) { + return; + } + List userProjectRelevancyList = projectIdList.stream().map(projectId -> { + BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy(); + userProjectRelevancy.setUserId(userId); + userProjectRelevancy.setProjectId(projectId); + return userProjectRelevancy; + }).toList(); + boolean saveRelevancy = this.saveBatch(userProjectRelevancyList); + if (!saveRelevancy) { + throw new ServiceException("新增用户和项目关联失败,数据库异常", HttpStatus.ERROR); + } + } + + /** + * 修改系统用户与项目关联 + * + * @param req 系统用户与项目关联 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusUserProjectRelevancyUpdateReq req) { + // 将实体类和 DTO 进行转换 + BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy(); + BeanUtils.copyProperties(req, userProjectRelevancy); + // 数据校验 + validEntityBeforeSave(userProjectRelevancy, false); + // 判断是否存在 + BusUserProjectRelevancy oldUserProjectRelevancy = this.getById(userProjectRelevancy.getId()); + if (oldUserProjectRelevancy == null) { + throw new ServiceException("修改用户和项目关联失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(oldUserProjectRelevancy); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusUserProjectRelevancy entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long userId = entity.getUserId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST); + } + if (userId == null) { + throw new ServiceException("用户 id 不能为空", HttpStatus.BAD_REQUEST); + } + } + // 判断对应项目是否存在 + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 判断对应用户是否存在 + if (userService.selectUserById(userId) == null) { + throw new ServiceException("用户不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除系统用户与项目关联信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + // 获取当前登录用户 + Long userId = LoginHelper.getUserId(); + // 获取待删除数据详情 + List busUserProjectRelevancyList = this.listByIds(ids); + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + // 获取项目id列表 + List projectIdList = busUserProjectRelevancyList.stream().map(BusUserProjectRelevancy::getProjectId).toList(); + // 判断是否有权限操作对应项目下的内容 + projectService.validAuth(projectIdList, userId); + } + // 判断对应数据是否都存在 + if (busUserProjectRelevancyList.size() != ids.size()) { + throw new ServiceException("删除系统用户与项目关联失败,数据缺失", HttpStatus.BAD_REQUEST); + } + return this.removeBatchByIds(ids); + } + + /** + * 根据用户ID删除系统用户与项目关联 + * + * @param userId 用户ID + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteByUserId(Long userId) { + List relevancyList = this.lambdaQuery() + .eq(BusUserProjectRelevancy::getUserId, userId) + .list(); + if (CollUtil.isNotEmpty(relevancyList)) { + boolean result = this.removeBatchByIds(relevancyList); + if (!result) { + throw new ServiceException("删除用户项目关联失败,数据库异常", HttpStatus.ERROR); + } + } + } + + /** + * 根据项目ID和用户ID列表删除系统用户与项目关联 + * + * @param oldProjectId 项目ID + * @param userIds 用户ID列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteByProjectAndUserIds(Long oldProjectId, List userIds) { + List relevancyList = this.lambdaQuery() + .eq(BusUserProjectRelevancy::getProjectId, oldProjectId) + .in(BusUserProjectRelevancy::getUserId, userIds) + .list(); + if (CollUtil.isNotEmpty(relevancyList)) { + boolean result = this.removeBatchByIds(relevancyList); + if (!result) { + throw new ServiceException("删除用户项目关联失败,数据库异常", HttpStatus.ERROR); + } + } + } + + /** + * 获取当前登录用户项目列表 + * + * @param userId 登录用户ID + * @return 当前登录用户项目列表 + */ + @Override + public List queryListByUserId(Long userId) { + // 添加查询条件,根据当前用户,获取数据 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(BusUserProjectRelevancy::getUserId, userId); + // 查询数据库,获取数据 + List list = this.list(queryWrapper); + List projectIdList = list.stream().map(BusUserProjectRelevancy::getProjectId).toList(); + if (CollUtil.isEmpty(projectIdList)) { + return new ArrayList<>(); + } + Map> projectMap = projectService.lambdaQuery() + .select(BusProject::getId, BusProject::getPId, BusProject::getProjectName, BusProject::getShortName) + .in(BusProject::getId, projectIdList) + .eq(BusProject::getPId, BusProjectConstant.PARENT_ID) + .list() + .stream().collect(Collectors.groupingBy(BusProject::getId)); + // 获取封装 + return list.stream() + .map(userProjectRelevancy -> { + Long projectId = userProjectRelevancy.getProjectId(); + BusProject project = null; + if (projectMap.containsKey(projectId)) { + project = projectMap.get(projectId).getFirst(); + } + if (project != null && project.getPId().equals(BusProjectConstant.PARENT_ID)) { + BusLoginUserProjectRelevancyVo loginUserProjectRelevancy = new BusLoginUserProjectRelevancyVo(); + loginUserProjectRelevancy.setId(userProjectRelevancy.getId()); + loginUserProjectRelevancy.setUserId(userProjectRelevancy.getUserId()); + loginUserProjectRelevancy.setProjectId(projectId); + loginUserProjectRelevancy.setProjectName(project.getProjectName()); + loginUserProjectRelevancy.setShortName(project.getShortName()); + return loginUserProjectRelevancy; + } + return null; + }) + .filter(Objects::nonNull) + .toList(); + } + + /** + * 获取当前登录用户项目分页 + * + * @param userId 登录用户ID + * @param req 分页查询条件 + * @param pageQuery 分页查询条件 + * @return 当前登录用户项目分页 + */ + @Override + public TableDataInfo queryPageByUserId(Long userId, BusUserProjectRelevancyQueryReq req, + PageQuery pageQuery) { + // 添加查询条件 + req.setUserId(userId); + LambdaQueryWrapper queryWrapper = this.buildQueryWrapper(req); + // 查询数据库 + Page result = this.page(pageQuery.build(), queryWrapper); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 批量新增用户和项目关联 + * + * @param req 新增参数 + * @return 是否增加成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertBatchByProjectList(BusProjectBatchByProjectListReq req) { + Long userId = req.getUserId(); + Long[] projectIdList = req.getProjectIdList(); + long count = projectService.count(new QueryWrapper().in("id", (Object[]) projectIdList)); + if (count < projectIdList.length) { + throw new ServiceException("项目ID列表错误,一个或多个项目不存在", HttpStatus.NOT_FOUND); + } + List userProjectRelevancyList = Arrays.stream(projectIdList).map(projectId -> { + BusUserProjectRelevancy userProjectRelevancy = new BusUserProjectRelevancy(); + userProjectRelevancy.setUserId(userId); + userProjectRelevancy.setProjectId(projectId); + // 查询对应用户与项目关联信息是否存在 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id", userId); + queryWrapper.eq("project_id", projectId); + // 如果存在则不保存 + BusUserProjectRelevancy one = this.getOne(queryWrapper); + if (one != null) { + return null; + } + return userProjectRelevancy; + }).filter(Objects::nonNull).toList(); + if (userProjectRelevancyList.isEmpty()) { + throw new ServiceException("对应用户与项目关系均已存在,无需重复添加", HttpStatus.BAD_REQUEST); + } + // 当用户与项目关系存在时修改,不存在则保存 + return this.saveOrUpdateBatch(userProjectRelevancyList); + } + + /** + * 获取系统用户与项目关联视图 + * + * @param userProjectRelevancy 系统用户与项目关联 + * @return 系统用户与项目关联视图 + */ + @Override + public BusUserProjectRelevancyVo getVo(BusUserProjectRelevancy userProjectRelevancy) { + // 对象转封装类 + BusUserProjectRelevancyVo userProjectRelevancyVo = new BusUserProjectRelevancyVo(); + if (userProjectRelevancy == null) { + return userProjectRelevancyVo; + } + BeanUtils.copyProperties(userProjectRelevancy, userProjectRelevancyVo); + // 关联查询项目信息 + Long projectId = userProjectRelevancy.getProjectId(); + if (projectId != null) { + userProjectRelevancyVo.setProject(projectService.queryById(projectId)); + } + return userProjectRelevancyVo; + } + + /** + * 获取用户和项目关联对象查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusUserProjectRelevancyQueryReq req) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (req == null) { + return queryWrapper; + } + // 从对象中取值 + Long id = req.getId(); + Long userId = req.getUserId(); + Long projectId = req.getProjectId(); + // 精确查询 + queryWrapper.eq(ObjectUtils.isNotEmpty(id), BusUserProjectRelevancy::getId, id); + queryWrapper.eq(ObjectUtils.isNotEmpty(userId), BusUserProjectRelevancy::getUserId, userId); + queryWrapper.eq(ObjectUtils.isNotEmpty(projectId), BusUserProjectRelevancy::getProjectId, projectId); + return queryWrapper; + } + + /** + * 获取系统用户与项目关联分页视图 + * + * @param userProjectRelevancyPage 系统用户与项目关联分页 + * @return 系统用户与项目关联分页视图 + */ + @Override + public Page getVoPage(Page userProjectRelevancyPage) { + List userProjectRelevancyList = userProjectRelevancyPage.getRecords(); + Page userProjectRelevancyVoPage = new Page<>( + userProjectRelevancyPage.getCurrent(), + userProjectRelevancyPage.getSize(), + userProjectRelevancyPage.getTotal()); + if (CollUtil.isEmpty(userProjectRelevancyList)) { + return userProjectRelevancyVoPage; + } + // 对象列表 => 封装对象列表 + List userProjectRelevancyVoList = userProjectRelevancyList.stream().map(this::getVo).toList(); + userProjectRelevancyVoPage.setRecords(userProjectRelevancyVoList); + return userProjectRelevancyVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusWorkWageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusWorkWageServiceImpl.java new file mode 100644 index 0000000..7bae799 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusWorkWageServiceImpl.java @@ -0,0 +1,259 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.domain.BusWorkWage; +import org.dromara.project.domain.enums.BusWageMeasureUnitEnum; +import org.dromara.project.domain.dto.workwage.BusWorkWageCreateReq; +import org.dromara.project.domain.dto.workwage.BusWorkWageQueryReq; +import org.dromara.project.domain.dto.workwage.BusWorkWageUpdateReq; +import org.dromara.project.domain.vo.workwage.BusWorkWageVo; +import org.dromara.project.mapper.BusWorkWageMapper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusWorkWageService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 工种薪水Service业务层处理 + * + * @author lilemy + * @date 2025-03-26 + */ +@Service +public class BusWorkWageServiceImpl extends ServiceImpl + implements IBusWorkWageService { + + @Resource + private IBusProjectService projectService; + + /** + * 查询工种薪水 + * + * @param id 主键 + * @return 工种薪水 + */ + @Override + public BusWorkWageVo queryById(Long id) { + BusWorkWage workWage = this.getById(id); + if (workWage == null) { + throw new ServiceException("工种薪水信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(workWage); + } + + /** + * 分页查询工种薪水列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 工种薪水分页列表 + */ + @Override + public TableDataInfo queryPageList(BusWorkWageQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的工种薪水列表 + * + * @param req 查询条件 + * @return 工种薪水列表 + */ + @Override + public List queryList(BusWorkWageQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增工种薪水 + * + * @param req 工种薪水 + * @return 新增工种薪水id + */ + @Override + public Long insertByBo(BusWorkWageCreateReq req) { + // 将实体类和 DTO 进行转换 + BusWorkWage workWage = new BusWorkWage(); + BeanUtils.copyProperties(req, workWage); + // 数据校验 + validEntityBeforeSave(workWage, true); + // 判断是否存在 + Long count = this.lambdaQuery() + .eq(BusWorkWage::getProjectId, workWage.getProjectId()) + .eq(BusWorkWage::getWorkType, workWage.getWorkType()) + .eq(BusWorkWage::getWageCalculationType, workWage.getWageCalculationType()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在该工种薪水信息", HttpStatus.CONFLICT); + } + // 填充默认值 + String wageCalculationType = req.getWageCalculationType(); + switch (wageCalculationType) { + case "1": + workWage.setWageMeasureUnit(BusWageMeasureUnitEnum.TIME.getValue()); + break; + case "2": + workWage.setWageMeasureUnit(BusWageMeasureUnitEnum.PIECE.getValue()); + break; + default: + throw new ServiceException("工资计算方式错误", HttpStatus.BAD_REQUEST); + } + // 操作数据库 + boolean save = this.save(workWage); + if (!save) { + throw new ServiceException("新增工种薪水失败,数据库异常", HttpStatus.ERROR); + } + return workWage.getId(); + } + + /** + * 修改工种薪水 + * + * @param req 工种薪水 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(BusWorkWageUpdateReq req) { + // 将实体类和 DTO 进行转换 + BusWorkWage workWage = new BusWorkWage(); + BeanUtils.copyProperties(req, workWage); + // 数据校验 + validEntityBeforeSave(workWage, false); + // 判断是否存在 + BusWorkWage oldWorkWage = this.getById(workWage.getId()); + if (oldWorkWage == null) { + throw new ServiceException("修改工种薪水失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(workWage); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BusWorkWage entity, Boolean create) { + // 做一些数据校验,如唯一约束 + Long userId = LoginHelper.getUserId(); + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + projectService.validAuth(projectId, userId); + } + + /** + * 校验并批量删除工种薪水信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + // 获取当前登录用户 + Long userId = LoginHelper.getUserId(); + // 获取待删除数据详情 + List workWageList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectIdList = workWageList.stream().map(BusWorkWage::getProjectId).toList(); + projectService.validAuth(projectIdList, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取工种薪水视图对象 + * + * @param workWage 工种薪水对象 + * @return 工种薪水视图对象 + */ + @Override + public BusWorkWageVo getVo(BusWorkWage workWage) { + // 对象转封装类 + BusWorkWageVo workWageVo = new BusWorkWageVo(); + if (workWage == null) { + return workWageVo; + } + BeanUtils.copyProperties(workWage, workWageVo); + return workWageVo; + } + + /** + * 获取工种薪水查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusWorkWageQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + String workType = req.getWorkType(); + String isSpecialType = req.getIsSpecialType(); + String wageCalculationType = req.getWageCalculationType(); + Long wage = req.getWage(); + String wageMeasureUnit = req.getWageMeasureUnit(); + String remark = req.getRemark(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(remark), BusWorkWage::getRemark, remark); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusWorkWage::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusWorkWage::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(workType), BusWorkWage::getWorkType, workType); + lqw.eq(StringUtils.isNotBlank(isSpecialType), BusWorkWage::getIsSpecialType, isSpecialType); + lqw.eq(StringUtils.isNotBlank(wageCalculationType), BusWorkWage::getWageCalculationType, wageCalculationType); + lqw.eq(ObjectUtils.isNotEmpty(wage), BusWorkWage::getWage, wage); + lqw.eq(StringUtils.isNotBlank(wageMeasureUnit), BusWorkWage::getWageMeasureUnit, wageMeasureUnit); + return lqw; + } + + /** + * 获取工种薪水分页对象视图 + * + * @param workWagePage 工种薪水分页对象 + * @return 工种薪水分页对象视图 + */ + @Override + public Page getVoPage(Page workWagePage) { + List workWageList = workWagePage.getRecords(); + Page workWageVoPage = new Page<>( + workWagePage.getCurrent(), + workWagePage.getSize(), + workWagePage.getTotal() + ); + if (CollUtil.isEmpty(workWageList)) { + return workWageVoPage; + } + List workWageVoList = workWageList.stream().map(this::getVo).toList(); + workWageVoPage.setRecords(workWageVoList); + return workWageVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusWorkerDailyReportServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusWorkerDailyReportServiceImpl.java new file mode 100644 index 0000000..2c9f661 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusWorkerDailyReportServiceImpl.java @@ -0,0 +1,222 @@ +package org.dromara.project.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.domain.BusDailyPieceItem; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.project.domain.BusWorkerDailyReport; +import org.dromara.project.domain.dto.workerdailyreport.BusWorkerDailyReportQueryReq; +import org.dromara.project.domain.vo.dailypieceitem.BusDailyPieceItemVo; +import org.dromara.project.domain.vo.workerdailyreport.BusWorkerDailyReportVo; +import org.dromara.project.mapper.BusWorkerDailyReportMapper; +import org.dromara.project.service.IBusDailyPieceItemService; +import org.dromara.project.service.IBusProjectTeamService; +import org.dromara.project.service.IBusWorkerDailyReportService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 施工人员日报Service业务层处理 + * + * @author lilemy + * @date 2025-04-09 + */ +@Service +public class BusWorkerDailyReportServiceImpl extends ServiceImpl + implements IBusWorkerDailyReportService { + + @Resource + private IBusDailyPieceItemService dailyPieceItemService; + + @Resource + private IBusProjectTeamService projectTeamService; + + @Resource + private ISysOssService ossService; + + /** + * 查询施工人员日报 + * + * @param id 主键 + * @return 施工人员日报 + */ + @Override + public BusWorkerDailyReportVo queryById(Long id) { + BusWorkerDailyReport workerDailyReport = this.getById(id); + if (workerDailyReport == null) { + throw new ServiceException("施工人员日报信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(workerDailyReport); + } + + /** + * 分页查询施工人员日报列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 施工人员日报分页列表 + */ + @Override + public TableDataInfo queryPageList(BusWorkerDailyReportQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的施工人员日报列表 + * + * @param req 查询条件 + * @return 施工人员日报列表 + */ + @Override + public List queryList(BusWorkerDailyReportQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return baseMapper.selectVoList(lqw); + } + + /** + * 校验并批量删除施工人员日报信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 获取施工人员日报列表视图对象 + * + * @param workerDailyReport 施工人员日报列表对象 + * @return 施工人员日报列表视图对象 + */ + @Override + public BusWorkerDailyReportVo getVo(BusWorkerDailyReport workerDailyReport) { + // 对象转封装类 + BusWorkerDailyReportVo workerDailyReportVo = new BusWorkerDailyReportVo(); + if (workerDailyReport == null) { + return workerDailyReportVo; + } + BeanUtils.copyProperties(workerDailyReport, workerDailyReportVo); + // 获取日报计件详情信息 + List dailyPieceItemList = dailyPieceItemService.lambdaQuery() + .eq(BusDailyPieceItem::getReportId, workerDailyReport.getId()).list(); + workerDailyReportVo.setDailyPieceItemVoList(dailyPieceItemService.getListVo(dailyPieceItemList)); + // 获取班组详情信息 + workerDailyReportVo.setTeamName(projectTeamService.getById(workerDailyReport.getTeamId()).getTeamName()); + // 获取图片信息 + String file = workerDailyReport.getFile(); + if (StringUtils.isNotEmpty(file)) { + List picList = Arrays.stream(file.split(",")) + .map(Long::parseLong) + .toList(); + List pictureList = ossService.listByIds(picList); + workerDailyReportVo.setFileList(pictureList.stream().map(SysOssVo::getUrl).toList()); + } + return workerDailyReportVo; + } + + /** + * 获取施工人员日报列表查询条件封装 + * + * @param req 施工人员日报列表查询条件 + * @return 施工人员日报列表查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(BusWorkerDailyReportQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + Long teamId = req.getTeamId(); + Long userId = req.getUserId(); + String userName = req.getUserName(); + Date reportDate = req.getReportDate(); + Long isResubmit = req.getIsResubmit(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(userName), BusWorkerDailyReport::getUserName, userName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), BusWorkerDailyReport::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), BusWorkerDailyReport::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), BusWorkerDailyReport::getTeamId, teamId); + lqw.eq(ObjectUtils.isNotEmpty(userId), BusWorkerDailyReport::getUserId, userId); + lqw.eq(ObjectUtils.isNotEmpty(reportDate), BusWorkerDailyReport::getReportDate, reportDate); + lqw.eq(ObjectUtils.isNotEmpty(isResubmit), BusWorkerDailyReport::getIsResubmit, isResubmit); + return lqw; + } + + /** + * 获取施工人员日报列表分页对象视图 + * + * @param workerDailyReportPage 施工人员日报列表分页对象 + * @return 施工人员日报列表分页对象视图 + */ + @Override + public Page getVoPage(Page workerDailyReportPage) { + // 对象列表 => 封装对象列表 + List workerDailyReportList = workerDailyReportPage.getRecords(); + Page workerDailyReportVoPage = new Page<>( + workerDailyReportPage.getCurrent(), + workerDailyReportPage.getSize(), + workerDailyReportPage.getTotal()); + if (CollUtil.isEmpty(workerDailyReportList)) { + return workerDailyReportVoPage; + } + // 获取日报计件详情信息 + List idList = workerDailyReportList.stream().map(BusWorkerDailyReport::getId).toList(); + Map> reportIdDailyPieceItemMap = dailyPieceItemService.lambdaQuery() + .in(BusDailyPieceItem::getReportId, idList).list() + .stream().collect(Collectors.groupingBy(BusDailyPieceItem::getReportId)); + // 获取班组详情信息 + List teamIdList = workerDailyReportList.stream().map(BusWorkerDailyReport::getTeamId).toList(); + Map> teamIdProjectTeamMap = projectTeamService.lambdaQuery() + .in(BusProjectTeam::getId, teamIdList).list() + .stream().collect(Collectors.groupingBy(BusProjectTeam::getId)); + // 封装对象 + List workerDailyReportVoList = workerDailyReportList.stream().map(workerDailyReport -> { + BusWorkerDailyReportVo workerDailyReportVo = new BusWorkerDailyReportVo(); + BeanUtils.copyProperties(workerDailyReport, workerDailyReportVo); + Long id = workerDailyReport.getId(); + // 获取日报计件详情信息 + List dailyPieceItemVoList = new ArrayList<>(); + if (reportIdDailyPieceItemMap.containsKey(id)) { + List dailyPieceItemList = reportIdDailyPieceItemMap.get(id); + dailyPieceItemVoList = dailyPieceItemService.getListVo(dailyPieceItemList); + } + workerDailyReportVo.setDailyPieceItemVoList(dailyPieceItemVoList); + // 获取班组详情信息 + String teamName = null; + if (teamIdProjectTeamMap.containsKey(workerDailyReport.getTeamId())) { + BusProjectTeam projectTeam = teamIdProjectTeamMap.get(workerDailyReport.getTeamId()).get(0); + teamName = projectTeam.getTeamName(); + } + workerDailyReportVo.setTeamName(teamName); + return workerDailyReportVo; + }).toList(); + workerDailyReportVoPage.setRecords(workerDailyReportVoList); + return workerDailyReportVoPage; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QltKnowledgeDocumentConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QltKnowledgeDocumentConstant.java new file mode 100644 index 0000000..f293519 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QltKnowledgeDocumentConstant.java @@ -0,0 +1,41 @@ +package org.dromara.quality.constant; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/26 11:02 + */ +public interface QltKnowledgeDocumentConstant { + + /** + * 顶级目录前缀 + */ + String TOP_FOLDER_PREFIX = "doc/quality/knowledge/"; + + /** + * 顶级目录名称 + */ + String TOP_FOLDER_NAME = "知识库"; + + /** + * 二级目录名称 + */ + List SECOND_LEVEL_FOLDER_NAME = List.of("指导手册", "交底记录", "强条"); + + /** + * 图片后缀列表 + */ + List PICTURE_SUFFIX_LIST = List.of("jpeg", "jpg", "png", "webp"); + + /** + * 获取顶级目录前缀 + * + * @param projectId 项目id + * @return 顶级目录前缀 + */ + static String getTopFolderPrefix(Long projectId) { + return String.format("%s%s/", TOP_FOLDER_PREFIX, projectId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QltQualityConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QltQualityConstant.java new file mode 100644 index 0000000..71fbfd5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/constant/QltQualityConstant.java @@ -0,0 +1,47 @@ +package org.dromara.quality.constant; + +import org.dromara.common.core.utils.DateUtils; +import org.dromara.quality.domain.QltQualityConstructionLog; +import org.dromara.quality.domain.QltQualityInspection; + +import java.text.SimpleDateFormat; + +/** + * @author lilemy + * @date 2025/4/17 14:36 + */ +public interface QltQualityConstant { + + String QUALITY_INSPECTION_CHECK_TYPE = "quality_inspection_check_type"; + + String QUALITY_INSPECTION_STATUS_TYPE = "quality_inspection_status_type"; + + String QUALITY_CONSTRUCTION_LOG_TEMPLATE_PATH = "template/施工日志模版.docx"; + + String QUALITY_CONSTRUCTION_LOG_FILE_URL = "docs/quality/constructionLog/"; + + static String getQualityConstructionLogFileUrl(QltQualityConstructionLog qualityConstructionLog) { + String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(qualityConstructionLog.getUpdateTime()); + return String.format("%s%s/%s", QUALITY_CONSTRUCTION_LOG_FILE_URL, qualityConstructionLog.getId(), timestamp); + } + + static String getQualityConstructionLogFileName(QltQualityConstructionLog qualityConstructionLog) { + String createDate = DateUtils.formatDate(qualityConstructionLog.getCreateTime()); + return String.format("施工日志(%s).docx", createDate); + } + + String QUALITY_INSPECTION_TEMPLATE_PATH = "template/整改通知单模版.docx"; + + String QUALITY_INSPECTION_FILE_URL = "docs/quality/inspection/"; + + static String getQualityInspectionFileUrl(QltQualityInspection qualityInspection) { + String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(qualityInspection.getUpdateTime()); + return String.format("%s%s/%s", QUALITY_INSPECTION_FILE_URL, qualityInspection.getId(), timestamp); + } + + static String getQualityInspectionFileName(QltQualityInspection qualityInspection) { + String createDate = DateUtils.formatDate(qualityInspection.getCreateTime()); + return String.format("整改通知单(%s).docx", createDate); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltKnowledgeDocumentController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltKnowledgeDocumentController.java new file mode 100644 index 0000000..843ba9c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltKnowledgeDocumentController.java @@ -0,0 +1,160 @@ +package org.dromara.quality.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileCreateReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileQueryReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentQueryReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileUpdateReq; +import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo; +import org.dromara.quality.service.IQltKnowledgeDocumentService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 质量知识库 + * + * @author lilemy + * @date 2025-06-25 + */ +@Validated +@RestController +@RequestMapping("/quality/knowledgeDocument") +public class QltKnowledgeDocumentController extends BaseController { + + @Resource + private IQltKnowledgeDocumentService qltKnowledgeDocumentService; + + /** + * 分页查询质量知识库文件列表 + */ + @SaCheckPermission("quality:knowledgeDocument:list") + @GetMapping("/file/page") + public TableDataInfo queryFilePageList(QltKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) { + return qltKnowledgeDocumentService.queryFilePageByFolderId(req, pageQuery); + } + + /** + * 查询质量知识库文件列表 + */ + @SaCheckPermission("quality:knowledgeDocument:list") + @GetMapping("/file/list/{folderId}") + public R> queryFileListByFolderId(@NotNull(message = "主键不能为空") + @PathVariable Long folderId) { + return R.ok(qltKnowledgeDocumentService.queryFileListByFolderId(folderId)); + } + + /** + * 查询质量知识库文件树列表 + */ + @SaCheckPermission("quality:knowledgeDocument:list") + @GetMapping("/folder/tree/list") + public R>> queryFolderTreeList(QltKnowledgeDocumentQueryReq req) { + List> list = qltKnowledgeDocumentService.queryFolderTreeList(req); + return R.ok(list); + } + + /** + * 查询质量知识库回收站文件列表 + */ + @SaCheckPermission("quality:knowledgeDocument:list") + @GetMapping("/recycleBin/list") + public TableDataInfo queryRecycleBinPageList(QltKnowledgeDocumentQueryReq req, PageQuery pageQuery) { + return qltKnowledgeDocumentService.queryRecycleBinPageList(req, pageQuery); + } + + /** + * 获取质量知识库详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("quality:knowledgeDocument:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(qltKnowledgeDocumentService.queryById(id)); + } + + /** + * 新增质量知识库文件 + */ + @SaCheckPermission("quality:knowledgeDocument:add") + @Log(title = "质量知识库", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/file") + public R add(@RequestPart("file") MultipartFile file, QltKnowledgeDocumentFileCreateReq req) { + return toAjax(qltKnowledgeDocumentService.insertFile(file, req)); + } + + /** + * 修改质量知识库 + */ + @SaCheckPermission("quality:knowledgeDocument:edit") + @Log(title = "质量知识库", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/file") + public R edit(@RequestBody QltKnowledgeDocumentFileUpdateReq req) { + return toAjax(qltKnowledgeDocumentService.updateFile(req)); + } + + /** + * 删除质量知识库文件 + * + * @param id 主键 + */ + @SaCheckPermission("quality:knowledgeDocument:remove") + @Log(title = "质量知识库", businessType = BusinessType.DELETE) + @DeleteMapping("/file/{id}") + public R remove(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(qltKnowledgeDocumentService.deleteFileById(id)); + } + + /** + * 批量删除质量知识库回收站文件信息 + * + * @param ids 主键串 + */ + @SaCheckPermission("quality:knowledgeDocument:remove") + @Log(title = "质量知识库", businessType = BusinessType.DELETE) + @DeleteMapping("/file/recycleBin/{ids}") + public R removeRecycleBin(@NotNull(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(qltKnowledgeDocumentService.deleteRecycleBinFileBatchByIds(List.of(ids))); + } + + /** + * 根据主键id批量恢复 + */ + @SaCheckPermission("quality:knowledgeDocument:recovery") + @Log(title = "质量知识库", businessType = BusinessType.UPDATE) + @PostMapping("/recovery/{ids}") + public R recoveryBatchById(@NotNull(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(qltKnowledgeDocumentService.recoveryBatchById(List.of(ids))); + } + + /** + * 畅写在线修改保存回调 + */ + @SaCheckPermission("quality:knowledgeDocument:edit") + @PostMapping("/changxie/callback/{id}") + public void singleFileUploads(@NotNull(message = "主键不能为空") + @PathVariable Long id, HttpServletRequest request, HttpServletResponse response) { + qltKnowledgeDocumentService.singleFileUploads(id, request, response); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltQualityConstructionLogController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltQualityConstructionLogController.java new file mode 100644 index 0000000..c765eec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltQualityConstructionLogController.java @@ -0,0 +1,119 @@ +package org.dromara.quality.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogCreateReq; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogQueryReq; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogUpdateReq; +import org.dromara.quality.domain.vo.qualityconstructionlog.QltQualityConstructionLogVo; +import org.dromara.quality.service.IQltQualityConstructionLogService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 质量-施工日志 + * + * @author lilemy + * @date 2025-04-16 + */ +@Validated +@RestController +@RequestMapping("/quality/qualityConstructionLog") +public class QltQualityConstructionLogController extends BaseController { + + @Resource + private IQltQualityConstructionLogService qualityConstructionLogService; + + /** + * 查询质量-施工日志列表 + */ + @SaCheckPermission("quality:qualityConstructionLog:list") + @GetMapping("/list") + public TableDataInfo list(QltQualityConstructionLogQueryReq req, PageQuery pageQuery) { + return qualityConstructionLogService.queryPageList(req, pageQuery); + } + + /** + * 导出质量-施工日志列表 + */ + @SaCheckPermission("quality:qualityConstructionLog:export") + @Log(title = "质量-施工日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(QltQualityConstructionLogQueryReq req, HttpServletResponse response) { + List list = qualityConstructionLogService.queryList(req); + ExcelUtil.exportExcel(list, "质量-施工日志", QltQualityConstructionLogVo.class, response); + } + + /** + * 根据主键导出质量-施工日志 + */ + @SaCheckPermission("quality:qualityConstructionLog:export") + @Log(title = "质量-施工日志", businessType = BusinessType.EXPORT) + @PostMapping("/export/word") + public void exportWordById(@NotNull(message = "主键不能为空") Long id, + HttpServletResponse response) { + qualityConstructionLogService.exportWordById(id, response); + } + + /** + * 获取质量-施工日志详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("quality:qualityConstructionLog:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(qualityConstructionLogService.queryById(id)); + } + + /** + * 新增质量-施工日志 + */ + @SaCheckPermission("quality:qualityConstructionLog:add") + @Log(title = "质量-施工日志", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody QltQualityConstructionLogCreateReq req) { + return R.ok(qualityConstructionLogService.insertByBo(req)); + } + + /** + * 修改质量-施工日志 + */ + @SaCheckPermission("quality:qualityConstructionLog:edit") + @Log(title = "质量-施工日志", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody QltQualityConstructionLogUpdateReq req) { + return toAjax(qualityConstructionLogService.updateByBo(req)); + } + + /** + * 删除质量-施工日志 + * + * @param ids 主键串 + */ + @SaCheckPermission("quality:qualityConstructionLog:remove") + @Log(title = "质量-施工日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(qualityConstructionLogService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltQualityInspectionController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltQualityInspectionController.java new file mode 100644 index 0000000..0c41863 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/controller/QltQualityInspectionController.java @@ -0,0 +1,129 @@ +package org.dromara.quality.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionCreateReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionGisReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionQueryReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionUpdateReq; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionVo; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionListGisVo; +import org.dromara.quality.service.IQltQualityInspectionService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 质量-检查工单 + * + * @author lilemy + * @date 2025-04-16 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/quality/qualityInspection") +public class QltQualityInspectionController extends BaseController { + + private final IQltQualityInspectionService qualityInspectionService; + + /** + * 查询质量-检查工单列表 + */ + @SaCheckPermission("quality:qualityInspection:list") + @GetMapping("/list") + public TableDataInfo list(QltQualityInspectionQueryReq req, PageQuery pageQuery) { + return qualityInspectionService.queryPageList(req, pageQuery); + } + + /** + * 导出质量-检查工单列表 + */ + @SaCheckPermission("quality:qualityInspection:export") + @Log(title = "质量-检查工单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(QltQualityInspectionQueryReq req, HttpServletResponse response) { + List list = qualityInspectionService.queryList(req); + ExcelUtil.exportExcel(list, "质量-检查工单", QltQualityInspectionVo.class, response); + } + + /** + * 查询大屏质量信息 + */ + @GetMapping("/gis") + public R queryGisList(QltQualityInspectionGisReq req) { + return R.ok(qualityInspectionService.queryGisList(req)); + } + + /** + * 根据主键导出质量-检查工单 + */ + @SaCheckPermission("quality:qualityInspection:export") + @Log(title = "质量-检查工单", businessType = BusinessType.EXPORT) + @PostMapping("/export/word") + public void exportWordById(@NotNull(message = "主键不能为空") Long id, + HttpServletResponse response) { + qualityInspectionService.exportWordById(id, response); + } + + /** + * 获取质量-检查工单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("quality:qualityInspection:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(qualityInspectionService.queryById(id)); + } + + /** + * 新增质量-检查工单 + */ + @SaCheckPermission("quality:qualityInspection:add") + @Log(title = "质量-检查工单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody QltQualityInspectionCreateReq req) { + return R.ok(qualityInspectionService.insertByBo(req)); + } + + /** + * 修改质量-检查工单 + */ + @SaCheckPermission("quality:qualityInspection:edit") + @Log(title = "质量-检查工单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody QltQualityInspectionUpdateReq req) { + return toAjax(qualityInspectionService.updateByBo(req)); + } + + /** + * 删除质量-检查工单 + * + * @param ids 主键串 + */ + @SaCheckPermission("quality:qualityInspection:remove") + @Log(title = "质量-检查工单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(qualityInspectionService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltKnowledgeDocument.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltKnowledgeDocument.java new file mode 100644 index 0000000..5f4c3aa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltKnowledgeDocument.java @@ -0,0 +1,87 @@ +package org.dromara.quality.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 质量知识库对象 qlt_knowledge_document + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("qlt_knowledge_document") +public class QltKnowledgeDocument extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件访问路径 + */ + private String fileUrl; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private Date deletedAt; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltQualityConstructionLog.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltQualityConstructionLog.java new file mode 100644 index 0000000..9c6586d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltQualityConstructionLog.java @@ -0,0 +1,62 @@ +package org.dromara.quality.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 质量-施工日志对象 qlt_quality_construction_log + * + * @author lilemy + * @date 2025-04-16 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("qlt_quality_construction_log") +public class QltQualityConstructionLog extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 发生日期 + */ + private Date happenDate; + + /** + * 生产情况 + */ + private String productionStatus; + + /** + * 技术质量安全工作 + */ + private String technologyQuality; + + /** + * 附件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltQualityInspection.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltQualityInspection.java new file mode 100644 index 0000000..27d3600 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/QltQualityInspection.java @@ -0,0 +1,117 @@ +package org.dromara.quality.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 质量-检查工单对象 qlt_quality_inspection + * + * @author lilemy + * @date 2025-04-16 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("qlt_quality_inspection") +public class QltQualityInspection extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 巡检类型 + */ + private String inspectionType; + + /** + * 巡检标题 + */ + private String inspectionHeadline; + + /** + * 巡检结果 + */ + private String inspectionResult; + + /** + * 工单状态(1通知 2整改 3验证) + */ + private String inspectionStatus; + + /** + * 巡检附件 + */ + private String inspectionFile; + + /** + * 班组id + */ + private Long teamId; + + /** + * 整改人(班组长) + */ + private Long corrector; + + /** + * 是否回复(1回复 2不回复) + */ + private String isReply; + + /** + * 回复期限日期 + */ + private Date replyPeriodDate; + + /** + * 整改反馈 + */ + private String rectificationResult; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 整改附件 + */ + private String rectificationFile; + + /** + * 验证结果 + */ + private String verificationResult; + + /** + * 验证状态(1通过 2未通过) + */ + private String verificationType; + + /** + * 验证时间 + */ + private Date verificationTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileCreateReq.java new file mode 100644 index 0000000..118cd96 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileCreateReq.java @@ -0,0 +1,33 @@ +package org.dromara.quality.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 18:43 + */ +@Data +public class QltKnowledgeDocumentFileCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2209500240715662744L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileQueryReq.java new file mode 100644 index 0000000..277f7c7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileQueryReq.java @@ -0,0 +1,32 @@ +package org.dromara.quality.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 18:44 + */ +@Data +public class QltKnowledgeDocumentFileQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3877587395295861071L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件夹id + */ + private Long folderId; + + /** + * 文件名 + */ + private String fileName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileUpdateReq.java new file mode 100644 index 0000000..4645ce7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentFileUpdateReq.java @@ -0,0 +1,37 @@ +package org.dromara.quality.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 18:44 + */ +@Data +public class QltKnowledgeDocumentFileUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2002756179428078203L; + + /** + * 主键id + */ + private Long id; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentQueryReq.java new file mode 100644 index 0000000..d6c6575 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/knowledgedocument/QltKnowledgeDocumentQueryReq.java @@ -0,0 +1,27 @@ +package org.dromara.quality.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 11:31 + */ +@Data +public class QltKnowledgeDocumentQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2232852522603216190L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件名 + */ + private String fileName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogCreateReq.java new file mode 100644 index 0000000..d3b70ff --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogCreateReq.java @@ -0,0 +1,51 @@ +package org.dromara.quality.domain.dto.qualityconstructionlog; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/16 11:54 + */ +@Data +public class QltQualityConstructionLogCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -9122588005233479105L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 发生日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date happenDate; + + /** + * 生产情况 + */ + private String productionStatus; + + /** + * 技术质量安全工作 + */ + private String technologyQuality; + + /** + * 附件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogQueryReq.java new file mode 100644 index 0000000..afa1f8d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogQueryReq.java @@ -0,0 +1,31 @@ +package org.dromara.quality.domain.dto.qualityconstructionlog; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/16 11:55 + */ +@Data +public class QltQualityConstructionLogQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4555254995729496353L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 发生日期 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date happenDate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogUpdateReq.java new file mode 100644 index 0000000..fce046a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityconstructionlog/QltQualityConstructionLogUpdateReq.java @@ -0,0 +1,48 @@ +package org.dromara.quality.domain.dto.qualityconstructionlog; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/16 11:57 + */ +@Data +public class QltQualityConstructionLogUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5378506292803717193L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 生产情况 + */ + private String productionStatus; + + /** + * 技术质量安全工作 + */ + private String technologyQuality; + + /** + * 附件 + */ + private String file; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionCreateReq.java new file mode 100644 index 0000000..c30cc22 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionCreateReq.java @@ -0,0 +1,64 @@ +package org.dromara.quality.domain.dto.qualityinspection; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/16 14:03 + */ +@Data +public class QltQualityInspectionCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4466466614771971424L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 巡检类型 + */ + private String inspectionType; + + /** + * 巡检标题 + */ + private String inspectionHeadline; + + /** + * 巡检结果 + */ + private String inspectionResult; + + /** + * 巡检附件 + */ + private String inspectionFile; + + /** + * 班组id + */ + private Long teamId; + + /** + * 整改人(班组长) + */ + private Long corrector; + + /** + * 回复期限日期 + */ + private Date replyPeriodDate; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionGisReq.java new file mode 100644 index 0000000..0a93dd7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionGisReq.java @@ -0,0 +1,30 @@ +package org.dromara.quality.domain.dto.qualityinspection; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 14:40 + */ +@Data +public class QltQualityInspectionGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1643422493177660330L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 分页大小 + */ + private Integer pageSize = 20; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionQueryReq.java new file mode 100644 index 0000000..e2736c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.quality.domain.dto.qualityinspection; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/16 14:04 + */ +@Data +public class QltQualityInspectionQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 3468757869732753393L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 巡检类型 + */ + private String inspectionType; + + /** + * 工单状态(1通知 2整改 3验证) + */ + private String inspectionStatus; + + /** + * 班组id + */ + private Long teamId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionUpdateReq.java new file mode 100644 index 0000000..a452f9c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/dto/qualityinspection/QltQualityInspectionUpdateReq.java @@ -0,0 +1,109 @@ +package org.dromara.quality.domain.dto.qualityinspection; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/16 14:04 + */ +@Data +public class QltQualityInspectionUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8931016399391922936L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 巡检类型 + */ + private String inspectionType; + + /** + * 巡检标题 + */ + private String inspectionHeadline; + + /** + * 巡检结果 + */ + private String inspectionResult; + + /** + * 工单状态(1通知 2整改 3验证) + */ + private String inspectionStatus; + + /** + * 巡检附件 + */ + private String inspectionFile; + + /** + * 班组id + */ + private Long teamId; + + /** + * 整改人(班组长) + */ + private Long corrector; + + /** + * 是否回复(1回复 2不回复) + */ + private String isReply; + + /** + * 回复期限日期 + */ + private Date replyPeriodDate; + + /** + * 整改反馈 + */ + private String rectificationResult; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 整改附件 + */ + private String rectificationFile; + + /** + * 验证结果 + */ + private String verificationResult; + + /** + * 验证状态(1通过 2未通过) + */ + private String verificationType; + + /** + * 验证时间 + */ + private Date verificationTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QltQualityInspectionStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QltQualityInspectionStatusEnum.java new file mode 100644 index 0000000..f00cfab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QltQualityInspectionStatusEnum.java @@ -0,0 +1,25 @@ +package org.dromara.quality.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/16 14:26 + */ +@Getter +public enum QltQualityInspectionStatusEnum { + + INFORM("通知", "1"), + RECTIFICATION("整改", "2"), + VERIFICATION("验证", "3"); + + private final String text; + + private final String value; + + QltQualityInspectionStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QltQualityInspectionVerificationTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QltQualityInspectionVerificationTypeEnum.java new file mode 100644 index 0000000..a9f0820 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/enums/QltQualityInspectionVerificationTypeEnum.java @@ -0,0 +1,24 @@ +package org.dromara.quality.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/28 14:59 + */ +@Getter +public enum QltQualityInspectionVerificationTypeEnum { + + PASS("通过", "1"), + UNPASS("未通过", "2"); + + private final String text; + + private final String value; + + QltQualityInspectionVerificationTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/knowledgedocument/QltKnowledgeDocumentVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/knowledgedocument/QltKnowledgeDocumentVo.java new file mode 100644 index 0000000..bec5e1a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/knowledgedocument/QltKnowledgeDocumentVo.java @@ -0,0 +1,85 @@ +package org.dromara.quality.domain.vo.knowledgedocument; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.quality.domain.QltKnowledgeDocument; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 质量知识库视图对象 qlt_knowledge_document + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@AutoMapper(target = QltKnowledgeDocument.class) +public class QltKnowledgeDocumentVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件访问路径 + */ + private String fileUrl; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityconstructionlog/QltQualityConstructionLogVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityconstructionlog/QltQualityConstructionLogVo.java new file mode 100644 index 0000000..f0ac066 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityconstructionlog/QltQualityConstructionLogVo.java @@ -0,0 +1,85 @@ +package org.dromara.quality.domain.vo.qualityconstructionlog; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.quality.domain.QltQualityConstructionLog; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 质量-施工日志视图对象 qlt_quality_construction_log + * + * @author lilemy + * @date 2025-04-16 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = QltQualityConstructionLog.class) +public class QltQualityConstructionLogVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 发生日期 + */ + @ExcelProperty(value = "发生日期") + private Date happenDate; + + /** + * 生产情况 + */ + @ExcelProperty(value = "生产情况") + private String productionStatus; + + /** + * 技术质量安全工作 + */ + @ExcelProperty(value = "技术质量安全工作") + private String technologyQuality; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 附件 + */ + private String file; + + /** + * 附件列表 + */ + private List fileList; + + /** + * 创建者 + */ + @ExcelProperty(value = "创建者") + private String createBy; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionGis.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionGis.java new file mode 100644 index 0000000..ee45e0b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionGis.java @@ -0,0 +1,42 @@ +package org.dromara.quality.domain.vo.qualityinspection; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/28 14:36 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QltQualityInspectionGis { + + /** + * 主键 + */ + private Long id; + + /** + * 巡检类型 + */ + private String inspectionTypeLabel; + + /** + * 巡检标题 + */ + private String inspectionHeadline; + + /** + * 创建时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd", + timezone = "GMT+8") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionListGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionListGisVo.java new file mode 100644 index 0000000..0bdef10 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionListGisVo.java @@ -0,0 +1,34 @@ +package org.dromara.quality.domain.vo.qualityinspection; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/28 14:22 + */ +@Data +public class QltQualityInspectionListGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -1100954070125585535L; + + /** + * 巡检列表 + */ + private List list; + + /** + * 巡检总数 + */ + private Long count; + + /** + * 巡检情况 + */ + private String correctSituation; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionVo.java new file mode 100644 index 0000000..efed9a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/domain/vo/qualityinspection/QltQualityInspectionVo.java @@ -0,0 +1,157 @@ +package org.dromara.quality.domain.vo.qualityinspection; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.quality.domain.QltQualityInspection; +import org.dromara.system.domain.vo.SysOssVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 质量-检查工单视图对象 qlt_quality_inspection + * + * @author lilemy + * @date 2025-04-16 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = QltQualityInspection.class) +public class QltQualityInspectionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 巡检类型 + */ + @ExcelProperty(value = "巡检类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "quality_inspection_check_type") + private String inspectionType; + + /** + * 巡检标题 + */ + @ExcelProperty(value = "巡检标题") + private String inspectionHeadline; + + /** + * 巡检结果 + */ + @ExcelProperty(value = "巡检结果") + private String inspectionResult; + + /** + * 工单状态(1通知 2整改 3验证) + */ + @ExcelProperty(value = "工单状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "quality_inspection_status_type") + private String inspectionStatus; + + /** + * 巡检附件 + */ + private String inspectionFile; + + /** + * 巡检附件列表 + */ + private List inspectionFileList; + + /** + * 班组id + */ + private Long teamId; + + /** + * 整改人(班组长) + */ + private Long corrector; + + /** + * 整改人姓名 + */ + private String correctorName; + + /** + * 是否回复(1回复 2不回复) + */ + private String isReply; + + /** + * 回复期限日期 + */ + private Date replyPeriodDate; + + /** + * 整改反馈 + */ + private String rectificationResult; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 整改附件 + */ + private String rectificationFile; + + /** + * 整改附件列表 + */ + private List rectificationFileList; + + /** + * 验证结果 + */ + private String verificationResult; + + /** + * 验证状态(1通过 2未通过) + */ + private String verificationType; + + /** + * 验证时间 + */ + private Date verificationTime; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建者 + */ + @ExcelProperty(value = "创建者") + private String createBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltKnowledgeDocumentMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltKnowledgeDocumentMapper.java new file mode 100644 index 0000000..f73a957 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltKnowledgeDocumentMapper.java @@ -0,0 +1,15 @@ +package org.dromara.quality.mapper; + +import org.dromara.quality.domain.QltKnowledgeDocument; +import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 质量知识库Mapper接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface QltKnowledgeDocumentMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltQualityConstructionLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltQualityConstructionLogMapper.java new file mode 100644 index 0000000..6d2688b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltQualityConstructionLogMapper.java @@ -0,0 +1,15 @@ +package org.dromara.quality.mapper; + +import org.dromara.quality.domain.QltQualityConstructionLog; +import org.dromara.quality.domain.vo.qualityconstructionlog.QltQualityConstructionLogVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 质量-施工日志Mapper接口 + * + * @author lilemy + * @date 2025-04-16 + */ +public interface QltQualityConstructionLogMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltQualityInspectionMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltQualityInspectionMapper.java new file mode 100644 index 0000000..4eb453b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/mapper/QltQualityInspectionMapper.java @@ -0,0 +1,15 @@ +package org.dromara.quality.mapper; + +import org.dromara.quality.domain.QltQualityInspection; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 质量-检查工单Mapper接口 + * + * @author lilemy + * @date 2025-04-16 + */ +public interface QltQualityInspectionMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltKnowledgeDocumentService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltKnowledgeDocumentService.java new file mode 100644 index 0000000..d093a30 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltKnowledgeDocumentService.java @@ -0,0 +1,152 @@ +package org.dromara.quality.service; + +import cn.hutool.core.lang.tree.Tree; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.quality.domain.QltKnowledgeDocument; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileCreateReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileQueryReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentQueryReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileUpdateReq; +import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; + +/** + * 质量知识库Service接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface IQltKnowledgeDocumentService extends IService { + + /** + * 查询质量知识库 + * + * @param id 主键 + * @return 质量知识库 + */ + QltKnowledgeDocumentVo queryById(Long id); + + /** + * 查询质量知识库文件夹树列表 + * + * @param req 查询参数 + * @return 质量知识库文件夹树列表 + */ + List> queryFolderTreeList(QltKnowledgeDocumentQueryReq req); + + /** + * 分页查询文件夹下的质量知识库文件列表 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 质量知识库文件列表 + */ + TableDataInfo queryFilePageByFolderId(QltKnowledgeDocumentFileQueryReq req, PageQuery pageQuery); + + /** + * 查询文件夹下的质量知识库文件列表 + * + * @param folderId 文件夹id + * @return 质量知识库文件列表 + */ + List queryFileListByFolderId(Long folderId); + + /** + * 查询回收站中的文件 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 回收站中的文件 + */ + TableDataInfo queryRecycleBinPageList(QltKnowledgeDocumentQueryReq req, PageQuery pageQuery); + + /** + * 新增质量知识库文件 + * + * @param file 文件 + * @param req 质量知识库 + * @return 是否新增成功 + */ + Boolean insertFile(MultipartFile file, QltKnowledgeDocumentFileCreateReq req); + + /** + * 新增质量知识库文件夹 + * + * @param projectId 项目id + * @return 是否新增成功 + */ + Boolean insertFolderByTemplate(Long projectId); + + /** + * 修改质量知识库文件 + * + * @param req 质量知识库 + * @return 是否修改成功 + */ + Boolean updateFile(QltKnowledgeDocumentFileUpdateReq req); + + /** + * 删除质量知识库文件信息 + * + * @param id 待删除文件的主键 + * @return 是否删除成功 + */ + Boolean deleteFileById(Long id); + + /** + * 批量删除质量知识库回收站文件信息 + * + * @param ids 待删除文件主键集合 + * @return 是否删除成功 + */ + Boolean deleteRecycleBinFileBatchByIds(Collection ids); + + /** + * 批量恢复质量会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean recoveryBatchById(Collection ids); + + /** + * 构建前端所需要下拉树结构 + * + * @param documentList 文档列表 + * @return 下拉树结构列表 + */ + List> buildTreeSelect(List documentList); + + /** + * 构建文档封装对象 + * + * @param document 文档 + * @return 文档封装对象 + */ + QltKnowledgeDocumentVo getVo(QltKnowledgeDocument document); + + /** + * 获取文档对象视图 + * + * @param documentPage 文档对象 + * @return 文档对象视图 + */ + Page getVoPage(Page documentPage); + + /** + * 畅写在线文件修改 + * + * @param id 文档id + * @param request 请求 + * @param response 响应 + */ + void singleFileUploads(Long id, HttpServletRequest request, HttpServletResponse response); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltQualityConstructionLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltQualityConstructionLogService.java new file mode 100644 index 0000000..c1dc1e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltQualityConstructionLogService.java @@ -0,0 +1,108 @@ +package org.dromara.quality.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.quality.domain.QltQualityConstructionLog; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogCreateReq; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogQueryReq; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogUpdateReq; +import org.dromara.quality.domain.vo.qualityconstructionlog.QltQualityConstructionLogVo; + +import java.util.Collection; +import java.util.List; + +/** + * 质量-施工日志Service接口 + * + * @author lilemy + * @date 2025-04-16 + */ +public interface IQltQualityConstructionLogService extends IService { + + /** + * 查询质量-施工日志 + * + * @param id 主键 + * @return 质量-施工日志 + */ + QltQualityConstructionLogVo queryById(Long id); + + /** + * 分页查询质量-施工日志列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 质量-施工日志分页列表 + */ + TableDataInfo queryPageList(QltQualityConstructionLogQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的质量-施工日志列表 + * + * @param req 查询条件 + * @return 质量-施工日志列表 + */ + List queryList(QltQualityConstructionLogQueryReq req); + + /** + * 新增质量-施工日志 + * + * @param req 质量-施工日志 + * @return 新增日志主键 + */ + Long insertByBo(QltQualityConstructionLogCreateReq req); + + /** + * 修改质量-施工日志 + * + * @param req 质量-施工日志 + * @return 是否修改成功 + */ + Boolean updateByBo(QltQualityConstructionLogUpdateReq req); + + /** + * 校验并批量删除质量-施工日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取质量-施工日志视图对象 + * + * @param qualityConstructionLog 质量-施工日志对象 + * @return 质量-施工日志视图对象 + */ + QltQualityConstructionLogVo getVo(QltQualityConstructionLog qualityConstructionLog); + + /** + * 获取质量-施工日志查询条件封装 + * + * @param req 质量-施工日志查询条件 + * @return 质量-施工日志查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(QltQualityConstructionLogQueryReq req); + + /** + * 获取质量-施工日志分页对象视图 + * + * @param qualityConstructionLogPage 质量-施工日志分页对象 + * @return 质量-施工日志分页对象视图 + */ + Page getVoPage(Page qualityConstructionLogPage); + + /** + * 导出质量-施工日志 + * + * @param id 主键 + * @param response 响应 + */ + void exportWordById(Long id, HttpServletResponse response); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltQualityInspectionService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltQualityInspectionService.java new file mode 100644 index 0000000..5d5144e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/IQltQualityInspectionService.java @@ -0,0 +1,118 @@ +package org.dromara.quality.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.quality.domain.QltQualityInspection; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionCreateReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionGisReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionQueryReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionUpdateReq; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionVo; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionListGisVo; + +import java.util.Collection; +import java.util.List; + +/** + * 质量-检查工单Service接口 + * + * @author lilemy + * @date 2025-04-16 + */ +public interface IQltQualityInspectionService extends IService { + + /** + * 查询质量-检查工单 + * + * @param id 主键 + * @return 质量-检查工单 + */ + QltQualityInspectionVo queryById(Long id); + + /** + * 分页查询质量-检查工单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 质量-检查工单分页列表 + */ + TableDataInfo queryPageList(QltQualityInspectionQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的质量-检查工单列表 + * + * @param req 查询条件 + * @return 质量-检查工单列表 + */ + List queryList(QltQualityInspectionQueryReq req); + + /** + * 查询大屏质量-检查工单列表 + * + * @param req 查询条件 + * @return 质量-检查工单列表 + */ + QltQualityInspectionListGisVo queryGisList(QltQualityInspectionGisReq req); + + /** + * 新增质量-检查工单 + * + * @param req 质量-检查工单 + * @return 新增检查工单id + */ + Long insertByBo(QltQualityInspectionCreateReq req); + + /** + * 修改质量-检查工单 + * + * @param req 质量-检查工单 + * @return 是否修改成功 + */ + Boolean updateByBo(QltQualityInspectionUpdateReq req); + + /** + * 校验并批量删除质量-检查工单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取质量-检查工单视图对象 + * + * @param qualityInspection 质量-检查工单对象 + * @return 质量-检查工单视图对象 + */ + QltQualityInspectionVo getVo(QltQualityInspection qualityInspection); + + /** + * 获取质量-检查工单查询条件封装 + * + * @param req 质量-检查工单查询条件 + * @return 质量-检查工单查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(QltQualityInspectionQueryReq req); + + /** + * 获取质量-检查工单分页对象视图 + * + * @param qualityInspectionPage 质量-检查工单分页对象 + * @return 质量-检查工单分页对象视图 + */ + Page getVoPage(Page qualityInspectionPage); + + /** + * 导出质量-检查工单 + * + * @param id 质量-检查工单id + * @param response HttpServletResponse + */ + void exportWordById(Long id, HttpServletResponse response); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltKnowledgeDocumentServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltKnowledgeDocumentServiceImpl.java new file mode 100644 index 0000000..5f11707 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltKnowledgeDocumentServiceImpl.java @@ -0,0 +1,516 @@ +package org.dromara.quality.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.enums.DocumentStatusEnum; +import org.dromara.common.enums.DocumentTypeEnum; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.quality.constant.QltKnowledgeDocumentConstant; +import org.dromara.quality.domain.QltKnowledgeDocument; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileCreateReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileQueryReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentQueryReq; +import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileUpdateReq; +import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo; +import org.dromara.quality.mapper.QltKnowledgeDocumentMapper; +import org.dromara.quality.service.IQltKnowledgeDocumentService; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 质量知识库Service业务层处理 + * + * @author lilemy + * @date 2025-06-25 + */ +@Service +public class QltKnowledgeDocumentServiceImpl extends ServiceImpl + implements IQltKnowledgeDocumentService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + /** + * 查询质量知识库 + * + * @param id 主键 + * @return 质量知识库 + */ + @Override + public QltKnowledgeDocumentVo queryById(Long id) { + QltKnowledgeDocument entity = this.getById(id); + if (entity == null) { + throw new ServiceException("质量知识库文件或文件夹不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(entity); + } + + /** + * 查询质量知识库文件夹树列表 + * + * @param req 查询参数 + * @return 质量知识库文件夹树列表 + */ + @Override + public List> queryFolderTreeList(QltKnowledgeDocumentQueryReq req) { + Long projectId = req.getProjectId(); + List folderList = this.lambdaQuery() + .eq(QltKnowledgeDocument::getProjectId, projectId) + .eq(QltKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue()) + .eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue()) + .list(); + return this.buildTreeSelect(folderList); + } + + /** + * 查询文件夹下的质量知识库文件列表 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 质量知识库文件列表 + */ + @Override + public TableDataInfo queryFilePageByFolderId(QltKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long folderId = req.getFolderId(); + if (folderId != null) { + QltKnowledgeDocument folder = this.getById(folderId); + if (folder == null) { + throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND); + } + if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) { + throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST); + } + lqw.eq(QltKnowledgeDocument::getPid, folderId); + } + lqw.eq(ObjectUtils.isNotEmpty(req.getProjectId()), QltKnowledgeDocument::getProjectId, req.getProjectId()); + lqw.ne(QltKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue()); + lqw.eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue()); + lqw.like(StringUtils.isNotBlank(req.getFileName()), QltKnowledgeDocument::getFileName, req.getFileName()); + Page documentPage = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(documentPage)); + } + + /** + * 查询文件夹下的质量知识库文件列表 + * + * @param folderId 文件夹id + * @return 质量知识库文件列表 + */ + @Override + public List queryFileListByFolderId(Long folderId) { + QltKnowledgeDocument folder = this.getById(folderId); + if (folder == null) { + throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND); + } + if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) { + throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST); + } + List list = this.lambdaQuery() + .eq(QltKnowledgeDocument::getPid, folderId) + .ne(QltKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue()) + .eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue()) + .list(); + return list.stream().map(this::getVo).toList(); + } + + /** + * 查询回收站中的文件 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 回收站中的文件 + */ + @Override + public TableDataInfo queryRecycleBinPageList(QltKnowledgeDocumentQueryReq req, PageQuery pageQuery) { + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(QltKnowledgeDocument::getProjectId, projectId); + lqw.eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue()); + lqw.like(StringUtils.isNotBlank(req.getFileName()), QltKnowledgeDocument::getFileName, req.getFileName()); + lqw.orderByDesc(QltKnowledgeDocument::getDeletedAt); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 新增质量知识库文件 + * + * @param file 文件 + * @param req 质量知识库 + * @return 是否新增成功 + */ + @Override + public Boolean insertFile(MultipartFile file, QltKnowledgeDocumentFileCreateReq req) { + // 数据校验 + if (ObjectUtils.isEmpty(file)) { + throw new ServiceException("文件不能为空", HttpStatus.BAD_REQUEST); + } + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); + } + // 拼接文件名 + String originalFilename = file.getOriginalFilename(); + String suffix = FileUtil.getSuffix(originalFilename); + if (StringUtils.isBlank(suffix)) { + throw new ServiceException("文件格式错误", HttpStatus.BAD_REQUEST); + } + String date = DateUtils.getDate(); + String uuid = IdUtil.fastSimpleUUID(); + String fileName = String.format("%s_%s.%s", date, uuid, suffix); + // 拼接文件路径 + Long pid = req.getPid(); + if (pid == null || pid == 0) { + throw new ServiceException("不能在根目录上传文件", HttpStatus.BAD_REQUEST); + } + QltKnowledgeDocument pQltKnowledgeDocument = this.getById(pid); + // 校验父级目录 + validParentFolder(pQltKnowledgeDocument, projectId); + String filePath = pQltKnowledgeDocument.getFilePath() + "/" + fileName; + // 上传文件 + SysOssUploadVo ossUploadVo = ossService.uploadWithNoSave(file, filePath); + // 保存文件信息 + QltKnowledgeDocument knowledgeDocument = new QltKnowledgeDocument(); + knowledgeDocument.setFilePath(filePath); + knowledgeDocument.setFileUrl(ossUploadVo.getUrl()); + knowledgeDocument.setFileSuffix(suffix); + if (QltKnowledgeDocumentConstant.PICTURE_SUFFIX_LIST.contains(suffix)) { + knowledgeDocument.setFileType(DocumentTypeEnum.PICTURE.getValue()); + } else { + knowledgeDocument.setFileType(DocumentTypeEnum.FILE.getValue()); + } + knowledgeDocument.setFileName(FileUtil.getPrefix(originalFilename)); + knowledgeDocument.setOriginalName(originalFilename); + knowledgeDocument.setProjectId(projectId); + knowledgeDocument.setPid(pid); + boolean save = this.save(knowledgeDocument); + if (!save) { + throw new ServiceException("新增文件失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 新增质量知识库文件夹 + * + * @param projectId 项目id + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertFolderByTemplate(Long projectId) { + // 创建顶级目录 + String prefix = QltKnowledgeDocumentConstant.getTopFolderPrefix(projectId); + String topPath = prefix + QltKnowledgeDocumentConstant.TOP_FOLDER_NAME; + QltKnowledgeDocument topFolder = new QltKnowledgeDocument(); + topFolder.setProjectId(projectId); + topFolder.setPid(0L); + topFolder.setFileName(QltKnowledgeDocumentConstant.TOP_FOLDER_NAME); + topFolder.setFilePath(topPath); + topFolder.setFileType(DocumentTypeEnum.FOLDER.getValue()); + boolean save = this.save(topFolder); + if (!save) { + throw new ServiceException("新增顶级目录失败,数据库异常", HttpStatus.ERROR); + } + // 创建二级目录 + Long pid = topFolder.getId(); + List documents = QltKnowledgeDocumentConstant.SECOND_LEVEL_FOLDER_NAME.stream().map(name -> { + QltKnowledgeDocument folder = new QltKnowledgeDocument(); + String path = topPath + "/" + name; + folder.setProjectId(projectId); + folder.setPid(pid); + folder.setFileName(name); + folder.setFilePath(path); + folder.setFileType(DocumentTypeEnum.FOLDER.getValue()); + return folder; + }).toList(); + return this.saveBatch(documents); + } + + /** + * 修改质量知识库文件 + * + * @param req 质量知识库 + * @return 是否修改成功 + */ + @Override + public Boolean updateFile(QltKnowledgeDocumentFileUpdateReq req) { + Long id = req.getId(); + QltKnowledgeDocument oldDocument = this.getById(id); + if (oldDocument == null) { + throw new ServiceException("修改质量知识库文件失败,数据不存在", HttpStatus.NOT_FOUND); + } + QltKnowledgeDocument document = new QltKnowledgeDocument(); + BeanUtils.copyProperties(req, document); + boolean result = this.updateById(document); + if (!result) { + throw new ServiceException("修改质量知识库文件失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 删除质量知识库文件信息 + * + * @param id 待删除文件的主键 + * @return 是否删除成功 + */ + @Override + public Boolean deleteFileById(Long id) { + QltKnowledgeDocument document = this.getById(id); + if (document == null) { + throw new ServiceException("文件不存在", HttpStatus.ERROR); + } + if (!document.getFileStatus().equals(DocumentStatusEnum.NORMAL.getValue())) { + throw new ServiceException("文件已删除", HttpStatus.ERROR); + } + if (document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) { + throw new ServiceException("文件夹不能删除", HttpStatus.ERROR); + } + QltKnowledgeDocument deleteDocument = new QltKnowledgeDocument(); + deleteDocument.setId(document.getId()); + deleteDocument.setDeletedAt(new Date()); + deleteDocument.setFileStatus(DocumentStatusEnum.DELETE.getValue()); + return this.updateById(deleteDocument); + } + + /** + * 批量删除质量知识库回收站文件信息 + * + * @param ids 待删除文件主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteRecycleBinFileBatchByIds(Collection ids) { + Long userId = LoginHelper.getUserId(); + List documentList = this.listByIds(ids); + if (CollUtil.isEmpty(documentList)) { + throw new ServiceException("文件不存在", HttpStatus.ERROR); + } + Set projectIdList = documentList.stream().map(QltKnowledgeDocument::getProjectId).collect(Collectors.toSet()); + projectService.validAuth(projectIdList, userId); + boolean result = this.removeBatchByIds(ids); + if (!result) { + throw new ServiceException("文件删除失败", HttpStatus.ERROR); + } + // 删除oss文件 + OssClient storage = OssFactory.instance(); + for (QltKnowledgeDocument document : documentList) { + if (!document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) { + storage.delete(document.getFileUrl()); + } + } + return true; + } + + /** + * 批量恢复质量会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean recoveryBatchById(Collection ids) { + List allParentIdsRecursively = getAllParentIdsRecursively(ids); + // 需要更新状态的文件集合 + allParentIdsRecursively.addAll(ids); + List updateList = allParentIdsRecursively.stream().map(id -> { + QltKnowledgeDocument documentSafetyMeeting = new QltKnowledgeDocument(); + documentSafetyMeeting.setId(id); + documentSafetyMeeting.setFileStatus(DocumentStatusEnum.NORMAL.getValue()); + return documentSafetyMeeting; + }).toList(); + boolean result = this.updateBatchById(updateList); + if (!result) { + throw new ServiceException("恢复文件失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param documentList 文档列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildTreeSelect(List documentList) { + if (CollUtil.isEmpty(documentList)) { + return CollUtil.newArrayList(); + } + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (QltKnowledgeDocument d : documentList) { + Long parentId = d.getPid(); + QltKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId)); + if (ObjectUtil.isNull(document)) { + List> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) -> + tree.setId(knowledgeDocument.getId()) + .setParentId(knowledgeDocument.getPid()) + .setName(knowledgeDocument.getFileName())); + Tree tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId())); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 构建文档封装对象 + * + * @param document 文档 + * @return 文档封装对象 + */ + @Override + public QltKnowledgeDocumentVo getVo(QltKnowledgeDocument document) { + QltKnowledgeDocumentVo vo = new QltKnowledgeDocumentVo(); + if (document == null) { + return vo; + } + BeanUtils.copyProperties(document, vo); + return vo; + } + + /** + * 获取文档对象视图 + * + * @param documentPage 文档对象 + * @return 文档对象视图 + */ + @Override + public Page getVoPage(Page documentPage) { + List documentList = documentPage.getRecords(); + Page documentVoPage = new Page<>( + documentPage.getCurrent(), + documentPage.getSize(), + documentPage.getTotal()); + if (CollUtil.isEmpty(documentList)) { + return documentVoPage; + } + List documentVoList = documentList.stream().map(entity -> { + QltKnowledgeDocumentVo documentVo = new QltKnowledgeDocumentVo(); + BeanUtils.copyProperties(entity, documentVo); + return documentVo; + }).toList(); + documentVoPage.setRecords(documentVoList); + return documentVoPage; + } + + /** + * 畅写在线文件修改 + * + * @param id 文档id + * @param request 请求 + * @param response 响应 + */ + @Override + public void singleFileUploads(Long id, HttpServletRequest request, HttpServletResponse response) { + try { + PrintWriter writer = response.getWriter(); + Scanner scanner = new Scanner(request.getInputStream(), "GBK").useDelimiter("\\A"); + String body = scanner.hasNext() ? scanner.next() : ""; + JSONObject jsonObj = JSONUtil.parseObj(body); + if (jsonObj.getInt("status") == 2 || jsonObj.getInt("status") == 6) { + String downloadUri = (String) jsonObj.get("url"); + QltKnowledgeDocument document = this.getById(id); + String filePath = document.getFilePath(); + ossService.uploadFileUrlWithNoSave(downloadUri, filePath); + } else if (jsonObj.getInt("status") == 3 || jsonObj.getInt("status") == 7) { + writer.write("{\"error\":-1}"); + } + writer.write("{\"error\":0}"); + } catch (IOException e) { + throw new ServiceException("质量知识库在线修改文件失败," + e); + } + } + + /** + * 校验父级目录是否存在 + * + * @param knowledgeDocument 父级目录 + * @param projectId 当前项目id + */ + private void validParentFolder(QltKnowledgeDocument knowledgeDocument, Long projectId) { + // 判断父级目录是否存在 + if (knowledgeDocument == null) { + throw new ServiceException("父级目录不存在", HttpStatus.NOT_FOUND); + } + // 判断父级目录是否是文件夹 + if (!DocumentTypeEnum.FOLDER.getValue().equals(knowledgeDocument.getFileType())) { + throw new ServiceException("父级目录不是文件夹", HttpStatus.BAD_REQUEST); + } + // 判断是否为同一个项目 + if (!knowledgeDocument.getProjectId().equals(projectId)) { + throw new ServiceException("父级目录不属于当前项目", HttpStatus.BAD_REQUEST); + } + } + + /** + * 递归查询所有父级 id + * + * @param ids id 列表 + * @return 父级 id 列表 + */ + private List getAllParentIdsRecursively(Collection ids) { + // 使用 list() 方法批量查询当前 id 列表对应的实体数据 + List fileList = this.lambdaQuery() + .in(QltKnowledgeDocument::getId, ids) + .eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue()) + .list(); + // 通过 stream 流过滤出非 0 的父 id,并去重 + List parentIdList = fileList.stream() + .map(QltKnowledgeDocument::getPid) + .filter(pid -> pid != 0) + .distinct() + .collect(Collectors.toList()); + // 如果父 id 列表为空,说明递归终止,返回空列表 + if (parentIdList.isEmpty()) { + return new ArrayList<>(); + } + // 递归查询父 id 列表对应的上级父 id + List higherParentIds = getAllParentIdsRecursively(parentIdList); + // 将当前层的父 id 和上级递归得到的父 id 合并 + List allParentIds = new ArrayList<>(); + allParentIds.addAll(parentIdList); + allParentIds.addAll(higherParentIds); + // 返回合并后去重的结果 + return allParentIds.stream().distinct().collect(Collectors.toList()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltQualityConstructionLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltQualityConstructionLogServiceImpl.java new file mode 100644 index 0000000..e0c00e5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltQualityConstructionLogServiceImpl.java @@ -0,0 +1,487 @@ +package org.dromara.quality.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.xwpf.usermodel.*; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.exception.OssException; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; +import org.dromara.quality.constant.QltQualityConstant; +import org.dromara.quality.domain.QltQualityConstructionLog; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogCreateReq; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogQueryReq; +import org.dromara.quality.domain.dto.qualityconstructionlog.QltQualityConstructionLogUpdateReq; +import org.dromara.quality.domain.vo.qualityconstructionlog.QltQualityConstructionLogVo; +import org.dromara.quality.mapper.QltQualityConstructionLogMapper; +import org.dromara.quality.service.IQltQualityConstructionLogService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysUserService; +import org.dromara.common.utils.DocumentUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipOutputStream; + +/** + * 质量-施工日志Service业务层处理 + * + * @author lilemy + * @date 2025-04-16 + */ +@Slf4j +@Service +public class QltQualityConstructionLogServiceImpl extends ServiceImpl + implements IQltQualityConstructionLogService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysUserService userService; + + @Resource + private ISysOssService ossService; + + /** + * 查询质量-施工日志 + * + * @param id 主键 + * @return 质量-施工日志 + */ + @Override + public QltQualityConstructionLogVo queryById(Long id) { + QltQualityConstructionLog qualityConstructionLog = this.getById(id); + if (qualityConstructionLog == null) { + throw new ServiceException("施工日志信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(qualityConstructionLog); + } + + /** + * 分页查询质量-施工日志列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 质量-施工日志分页列表 + */ + @Override + public TableDataInfo queryPageList(QltQualityConstructionLogQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的质量-施工日志列表 + * + * @param req 查询条件 + * @return 质量-施工日志列表 + */ + @Override + public List queryList(QltQualityConstructionLogQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增质量-施工日志 + * + * @param req 质量-施工日志 + * @return 新增日志主键 + */ + @Override + public Long insertByBo(QltQualityConstructionLogCreateReq req) { + // 将实体类和 DTO 进行转换 + QltQualityConstructionLog qualityConstructionLog = new QltQualityConstructionLog(); + BeanUtils.copyProperties(req, qualityConstructionLog); + // 数据校验 + validEntityBeforeSave(qualityConstructionLog, true); + // 写入数据库 + boolean save = this.save(qualityConstructionLog); + if (!save) { + throw new ServiceException("新增施工日志信息失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return qualityConstructionLog.getId(); + } + + /** + * 修改质量-施工日志 + * + * @param req 质量-施工日志 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(QltQualityConstructionLogUpdateReq req) { + // 将实体类和 DTO 进行转换 + QltQualityConstructionLog qualityConstructionLog = new QltQualityConstructionLog(); + BeanUtils.copyProperties(req, qualityConstructionLog); + // 数据校验 + validEntityBeforeSave(qualityConstructionLog, false); + // 判断是否存在 + QltQualityConstructionLog oldQualityConstructionLog = this.getById(qualityConstructionLog.getId()); + if (oldQualityConstructionLog == null) { + throw new ServiceException("修改施工日志信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(qualityConstructionLog); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(QltQualityConstructionLog entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除质量-施工日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List qualityConstructionLogList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = qualityConstructionLogList.stream().map(QltQualityConstructionLog::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取质量-施工日志视图对象 + * + * @param qualityConstructionLog 质量-施工日志对象 + * @return 质量-施工日志视图对象 + */ + @Override + public QltQualityConstructionLogVo getVo(QltQualityConstructionLog qualityConstructionLog) { + // 对象转封装类 + QltQualityConstructionLogVo qualityConstructionLogVo = new QltQualityConstructionLogVo(); + if (qualityConstructionLog == null) { + return qualityConstructionLogVo; + } + BeanUtils.copyProperties(qualityConstructionLog, qualityConstructionLogVo); + // 关联项目信息 + Long projectId = qualityConstructionLog.getProjectId(); + if (projectId != null) { + qualityConstructionLogVo.setProjectName(projectService.getById(projectId).getProjectName()); + } + // 关联创建用户信息 + Long createBy = qualityConstructionLog.getCreateBy(); + if (createBy != null) { + SysUserVo sysUserVo = userService.selectUserById(createBy); + qualityConstructionLogVo.setCreateBy(sysUserVo.getNickName()); + } + // 关联附件信息 + String file = qualityConstructionLog.getFile(); + if (StringUtils.isNotBlank(file)) { + List ossIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + qualityConstructionLogVo.setFileList(ossVoList); + } + return qualityConstructionLogVo; + } + + /** + * 获取质量-施工日志查询条件封装 + * + * @param req 质量-施工日志查询条件 + * @return 质量-施工日志查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(QltQualityConstructionLogQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Date happenDate = req.getHappenDate(); + // 精准查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), QltQualityConstructionLog::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(happenDate), QltQualityConstructionLog::getHappenDate, happenDate); + return lqw; + } + + /** + * 获取质量-施工日志分页对象视图 + * + * @param qualityConstructionLogPage 质量-施工日志分页对象 + * @return 质量-施工日志分页对象视图 + */ + @Override + public Page getVoPage(Page qualityConstructionLogPage) { + // 获取质量-施工日志列表 + List qualityConstructionLogList = qualityConstructionLogPage.getRecords(); + // 添加分页信息 + Page qualityConstructionLogVoPage = new Page<>( + qualityConstructionLogPage.getCurrent(), + qualityConstructionLogPage.getSize(), + qualityConstructionLogPage.getTotal()); + if (CollUtil.isEmpty(qualityConstructionLogList)) { + return qualityConstructionLogVoPage; + } + // 获取项目名称 + List projectIdList = qualityConstructionLogList.stream().map(QltQualityConstructionLog::getProjectId).distinct().toList(); + if (projectIdList.size() != 1) { + throw new ServiceException("仅能查询单个项目下的施工日志", HttpStatus.BAD_REQUEST); + } + BusProject project = projectService.getById(projectIdList.get(0)); + if (project == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 获取创建用户信息 + List createByList = qualityConstructionLogList.stream().map(QltQualityConstructionLog::getCreateBy).distinct().toList(); + List userVoList = userService.selectUserByIds(createByList, null); + Map userMap = userVoList.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName)); + // 获取附件信息 + List ossIdList = qualityConstructionLogList.stream().map(QltQualityConstructionLog::getFile).filter(StringUtils::isNotBlank) + .flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList(); + Map> ossMap = ossService.listByIds(ossIdList) + .stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + // 对象列表 => 封装对象列表 + List qualityConstructionLogVoList = qualityConstructionLogList.stream().map(qualityConstructionLog -> { + QltQualityConstructionLogVo qualityConstructionLogVo = new QltQualityConstructionLogVo(); + // 对象转封装类 + BeanUtils.copyProperties(qualityConstructionLog, qualityConstructionLogVo); + // 项目名称 + qualityConstructionLogVo.setProjectName(project.getProjectName()); + // 创建用户姓名 + Long createBy = qualityConstructionLog.getCreateBy(); + String createByName = null; + if (userMap.containsKey(createBy)) { + createByName = userMap.get(createBy); + } + qualityConstructionLogVo.setCreateBy(createByName); + // 附件信息 + String file = qualityConstructionLog.getFile(); + List fileList = new ArrayList<>(); + if (StringUtils.isNotBlank(file)) { + List fileIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList(); + for (Long fileId : fileIdList) { + if (ossMap.containsKey(fileId)) { + fileList.add(ossMap.get(fileId).get(0)); + } + } + } + qualityConstructionLogVo.setFileList(fileList); + return qualityConstructionLogVo; + }).toList(); + qualityConstructionLogVoPage.setRecords(qualityConstructionLogVoList); + return qualityConstructionLogVoPage; + } + + /** + * 导出质量-施工日志 + * + * @param id 主键 + * @param response 响应 + */ + @Override + public void exportWordById(Long id, HttpServletResponse response) { + QltQualityConstructionLog qualityConstructionLog = this.getById(id); + if (qualityConstructionLog == null) { + throw new ServiceException("质量-施工日志不存在"); + } + Map replacementMap = getReplacementMap(qualityConstructionLog); + Path targetDir = Paths.get(QltQualityConstant.getQualityConstructionLogFileUrl(qualityConstructionLog)); + // 如果存在目录则直接返回,不存在则生成文件并返回 + if (!Files.exists(targetDir)) { + // 清理旧文件 + String baseUrl = QltQualityConstant.QUALITY_CONSTRUCTION_LOG_FILE_URL + qualityConstructionLog.getId(); + try { + Path dirPath = Paths.get(baseUrl); + if (Files.exists(dirPath)) { + FileUtils.deleteDirectory(dirPath); + } + } catch (IOException e) { + log.error("文件目录:{},清理失败", baseUrl, e); + } + // 生成文件 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(QltQualityConstant.QUALITY_CONSTRUCTION_LOG_TEMPLATE_PATH)) { + if (is == null) { + throw new ServiceException("模板文件不存在"); + } + try (XWPFDocument document = new XWPFDocument(is)) { + // 替换段落中的文本 + for (XWPFParagraph paragraph : document.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, qualityConstructionLog); + } + // 替换表格中的文本(如果模板中有表格) + for (XWPFTable table : document.getTables()) { + for (XWPFTableRow row : table.getRows()) { + for (XWPFTableCell cell : row.getTableCells()) { + for (XWPFParagraph paragraph : cell.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, qualityConstructionLog); + } + } + } + } + // 创建目标目录 + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); + } + // 组合目标文件名 + String fileName = QltQualityConstant.getQualityConstructionLogFileName(qualityConstructionLog); + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) { + document.write(fos); + } + } + } catch (IOException | InvalidFormatException e) { + throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + } + } + // 设置响应头,返回ZIP文件 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + DocumentUtil.zipDirectory(targetDir, targetDir, zos); + zos.flush(); + } catch (Exception e) { + throw new OssException("生成ZIP文件失败,错误信息: " + e.getMessage()); + } + } + + /** + * 根据实体获取Word的文本Map + * + * @param qualityConstructionLog 施工日志对象 + * @return Map + */ + public Map getReplacementMap(QltQualityConstructionLog qualityConstructionLog) { + Map replacementMap = new HashMap<>(); + String createName = userService.selectUserById(qualityConstructionLog.getCreateBy()).getNickName(); + replacementMap.put("${createName}", createName); + Date createTime = qualityConstructionLog.getCreateTime(); + replacementMap.put("${createTime}", createTime != null ? DateUtils.formatDateTime(createTime) : ""); + String projectName = projectService.getById(qualityConstructionLog.getProjectId()).getProjectName(); + replacementMap.put("${projectName}", projectName); + Date happenDate = qualityConstructionLog.getHappenDate(); + replacementMap.put("${happenDate}", happenDate != null ? DateUtils.formatDate(happenDate) : ""); + replacementMap.put("${productionStatus}", qualityConstructionLog.getProductionStatus()); + replacementMap.put("${technologyQuality}", qualityConstructionLog.getTechnologyQuality()); + replacementMap.put("${remark}", qualityConstructionLog.getRemark()); + replacementMap.put("${file}", qualityConstructionLog.getFile()); + return replacementMap; + } + + /** + * 替换段落中所有文本运行的占位符内容,对于 checkFile 和 rectificationFile + * 插入图片或超链接(附件)展示。 + * + * @param paragraph 当前段落 + * @param replacements 占位符与替换内容的映射 + * @param document 当前文档,用于插入图片或创建超链接 + */ + public void replaceInParagraph(XWPFParagraph paragraph, + Map replacements, + XWPFDocument document, + QltQualityConstructionLog qualityConstructionLog) throws InvalidFormatException, IOException { + // 先拷贝 paragraph 里所有的 run + List runs = new ArrayList<>(paragraph.getRuns()); + // 在拷贝上遍历,修改原 paragraph(增删 run)都不会抛 CME + for (XWPFRun run : runs) { + String text = run.getText(0); + if (text != null) { + // 针对每个占位符进行检查 + for (Map.Entry entry : replacements.entrySet()) { + String placeholder = entry.getKey(); + String value = entry.getValue(); + if (text.contains(placeholder)) { + // 针对 file 进行特殊处理 + if (placeholder.equals("${file}")) { + // 判断该 run 中的文本是否仅包含该占位符(建议模板中独占一行) + if (text.trim().equals(placeholder)) { + // 清空原有文本 + run.setText("", 0); + // 根据附件的后缀决定以图片或超链接展示 + if (StringUtils.isBlank(value)) { + continue; + } + // 获取附件的ossId + List ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = QltQualityConstant.getQualityConstructionLogFileUrl(qualityConstructionLog) + "/file"; + for (SysOssVo ossVo : ossVoList) { + String lowerVal = ossVo.getUrl().toLowerCase(); + OssClient storage = OssFactory.instance(ossVo.getService()); + String fileDownload = storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + if (lowerVal.endsWith(".png") || lowerVal.endsWith(".jpg") || lowerVal.endsWith(".jpeg") || lowerVal.endsWith(".gif")) { + try { + DocumentUtil.insertImageDynamic(run, fileDownload, document, 300); + } catch (Exception e) { + throw new ServiceException("插入图片失败"); + } + } else { + // —— 非图片:插入超链接 —— + XWPFHyperlinkRun link = paragraph.createHyperlinkRun(ossVo.getUrl()); + link.setText(ossVo.getOriginalName()); + link.setColor("0000FF"); + link.setUnderline(UnderlinePatterns.SINGLE); + } + } + } else { + // 如果占位符与其它文本混合,可进行文本替换,提示附件展示请单独使用占位符 + text = text.replace(placeholder, "[附件]"); + run.setText(text, 0); + } + } else { + // 普通文本占位符直接替换 + if (StringUtils.isBlank(value)) { + // 如果填入值为空,清空原有文本 + run.setText("", 0); + continue; + } + text = text.replace(placeholder, value); + run.setText(text, 0); + } + } + } + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltQualityInspectionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltQualityInspectionServiceImpl.java new file mode 100644 index 0000000..ee8cc08 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/quality/service/impl/QltQualityInspectionServiceImpl.java @@ -0,0 +1,610 @@ +package org.dromara.quality.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.xwpf.usermodel.*; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.exception.OssException; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.project.domain.BusProject; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.quality.constant.QltQualityConstant; +import org.dromara.quality.domain.QltQualityInspection; +import org.dromara.quality.domain.enums.QltQualityInspectionStatusEnum; +import org.dromara.quality.domain.enums.QltQualityInspectionVerificationTypeEnum; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionCreateReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionGisReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionQueryReq; +import org.dromara.quality.domain.dto.qualityinspection.QltQualityInspectionUpdateReq; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionGis; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionListGisVo; +import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionVo; +import org.dromara.quality.mapper.QltQualityInspectionMapper; +import org.dromara.quality.service.IQltQualityInspectionService; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.system.service.ISysDictTypeService; +import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysUserService; +import org.dromara.common.utils.DocumentUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipOutputStream; + +/** + * 质量-检查工单Service业务层处理 + * + * @author lilemy + * @date 2025-04-16 + */ +@Slf4j +@Service +public class QltQualityInspectionServiceImpl extends ServiceImpl + implements IQltQualityInspectionService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysUserService userService; + + @Resource + private ISysOssService ossService; + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private ISysDictDataService dictDataService; + + @Resource + private ISysDictTypeService dictTypeService; + + /** + * 查询质量-检查工单 + * + * @param id 主键 + * @return 质量-检查工单 + */ + @Override + public QltQualityInspectionVo queryById(Long id) { + QltQualityInspection qualityInspection = this.getById(id); + if (qualityInspection == null) { + throw new ServiceException("检查工单信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(qualityInspection); + } + + /** + * 分页查询质量-检查工单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 质量-检查工单分页列表 + */ + @Override + public TableDataInfo queryPageList(QltQualityInspectionQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的质量-检查工单列表 + * + * @param req 查询条件 + * @return 质量-检查工单列表 + */ + @Override + public List queryList(QltQualityInspectionQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 查询大屏质量-检查工单列表 + * + * @param req 查询条件 + * @return 质量-检查工单列表 + */ + @Override + public QltQualityInspectionListGisVo queryGisList(QltQualityInspectionGisReq req) { + Long projectId = req.getProjectId(); + if (projectId == null || projectService.getById(projectId) == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + QltQualityInspectionListGisVo gisVo = new QltQualityInspectionListGisVo(); + List qualityInspectionList = this.lambdaQuery() + .eq(QltQualityInspection::getProjectId, projectId) + .list(); + if (CollUtil.isEmpty(qualityInspectionList)) { + return gisVo; + } + // 获取字典值 + List dictDataVoList = dictTypeService.selectDictDataByType(QltQualityConstant.QUALITY_INSPECTION_CHECK_TYPE); + Map dictDataMap = dictDataVoList.stream().collect(Collectors.toMap(SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel)); + // 获取最新的检查工单 + List topList = qualityInspectionList.stream() + .sorted(Comparator.comparing(QltQualityInspection::getCreateTime).reversed()) + .limit(Optional.ofNullable(req.getPageSize()).orElse(20)) + .toList(); + // 转换为 GIS 对象,并设置标签 + List gisList = topList.stream().map(qualityInspection -> { + QltQualityInspectionGis gis = new QltQualityInspectionGis(); + BeanUtils.copyProperties(qualityInspection, gis); + String label = dictDataMap.get(qualityInspection.getInspectionType()); + if (label != null) { + gis.setInspectionTypeLabel(label); + } + return gis; + }).toList(); + // 获取整改情况 + long passCount = 0L; + for (QltQualityInspection qualityInspection : qualityInspectionList) { + if (QltQualityInspectionStatusEnum.VERIFICATION.getValue().equals(qualityInspection.getInspectionStatus()) + && QltQualityInspectionVerificationTypeEnum.PASS.getValue().equals(qualityInspection.getVerificationType())) { + passCount++; + } + } + gisVo.setList(gisList); + gisVo.setCount((long) qualityInspectionList.size()); + gisVo.setCorrectSituation(String.format("%.2f", passCount * 100.0 / qualityInspectionList.size())); + return gisVo; + } + + /** + * 新增质量-检查工单 + * + * @param req 质量-检查工单 + * @return 新增检查工单id + */ + @Override + public Long insertByBo(QltQualityInspectionCreateReq req) { + // 将实体类和 DTO 进行转换 + QltQualityInspection qualityInspection = new QltQualityInspection(); + BeanUtils.copyProperties(req, qualityInspection); + // 数据校验 + validEntityBeforeSave(qualityInspection, true); + // 填充默认值 + qualityInspection.setInspectionStatus(QltQualityInspectionStatusEnum.INFORM.getValue()); + // 写入数据库 + boolean save = this.save(qualityInspection); + if (!save) { + throw new ServiceException("新增检查工单信息失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return qualityInspection.getId(); + } + + /** + * 修改质量-检查工单 + * + * @param req 质量-检查工单 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(QltQualityInspectionUpdateReq req) { + // 将实体类和 DTO 进行转换 + QltQualityInspection qualityInspection = new QltQualityInspection(); + BeanUtils.copyProperties(req, qualityInspection); + // 数据校验 + validEntityBeforeSave(qualityInspection, false); + // 判断是否存在 + QltQualityInspection oldQualityInspection = this.getById(qualityInspection.getId()); + if (oldQualityInspection == null) { + throw new ServiceException("修改检查工单信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(qualityInspection); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(QltQualityInspection entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除质量-检查工单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List qualityInspectionList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = qualityInspectionList.stream().map(QltQualityInspection::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取质量-检查工单视图对象 + * + * @param qualityInspection 质量-检查工单对象 + * @return 质量-检查工单视图对象 + */ + @Override + public QltQualityInspectionVo getVo(QltQualityInspection qualityInspection) { + // 对象转封装类 + QltQualityInspectionVo qualityInspectionVo = new QltQualityInspectionVo(); + if (qualityInspection == null) { + return qualityInspectionVo; + } + BeanUtils.copyProperties(qualityInspection, qualityInspectionVo); + // 关联项目信息 + Long projectId = qualityInspection.getProjectId(); + if (projectId != null) { + qualityInspectionVo.setProjectName(projectService.getById(projectId).getProjectName()); + } + // 关联创建用户信息 + Long createBy = qualityInspection.getCreateBy(); + if (createBy != null) { + SysUserVo sysUserVo = userService.selectUserById(createBy); + qualityInspectionVo.setCreateBy(sysUserVo.getNickName()); + } + // 关联整改人信息 + Long corrector = qualityInspection.getCorrector(); + if (corrector != null) { + String userName = constructionUserService.getById(corrector).getUserName(); + qualityInspectionVo.setCorrectorName(userName); + } + // 关联附件信息 + String inspectionFile = qualityInspection.getInspectionFile(); + if (StringUtils.isNotBlank(inspectionFile)) { + List ossIdList = Arrays.stream(inspectionFile.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + qualityInspectionVo.setInspectionFileList(ossVoList); + } + String rectificationFile = qualityInspection.getRectificationFile(); + if (StringUtils.isNotBlank(rectificationFile)) { + List ossIdList = Arrays.stream(rectificationFile.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + qualityInspectionVo.setRectificationFileList(ossVoList); + } + return qualityInspectionVo; + } + + /** + * 获取质量-检查工单查询条件封装 + * + * @param req 质量-检查工单查询条件 + * @return 质量-检查工单查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(QltQualityInspectionQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String inspectionType = req.getInspectionType(); + String inspectionStatus = req.getInspectionStatus(); + Long teamId = req.getTeamId(); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), QltQualityInspection::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(inspectionType), QltQualityInspection::getInspectionType, inspectionType); + lqw.eq(ObjectUtils.isNotEmpty(inspectionStatus), QltQualityInspection::getInspectionStatus, inspectionStatus); + lqw.eq(ObjectUtils.isNotEmpty(teamId), QltQualityInspection::getTeamId, teamId); + return lqw; + } + + /** + * 获取质量-检查工单分页对象视图 + * + * @param qualityInspectionPage 质量-检查工单分页对象 + * @return 质量-检查工单分页对象视图 + */ + @Override + public Page getVoPage(Page qualityInspectionPage) { + // 获取质量-检查工单列表 + List qualityInspectionList = qualityInspectionPage.getRecords(); + // 添加分页信息 + Page qualityInspectionVoPage = new Page<>( + qualityInspectionPage.getCurrent(), + qualityInspectionPage.getSize(), + qualityInspectionPage.getTotal()); + if (CollUtil.isEmpty(qualityInspectionList)) { + return qualityInspectionVoPage; + } + // 获取项目名称 + List projectIdList = qualityInspectionList.stream().map(QltQualityInspection::getProjectId).distinct().toList(); + if (projectIdList.size() != 1) { + throw new ServiceException("仅能查询单个项目下的施工日志", HttpStatus.BAD_REQUEST); + } + BusProject project = projectService.getById(projectIdList.get(0)); + if (project == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 获取整改人信息 + List correctorList = qualityInspectionList.stream().map(QltQualityInspection::getCorrector).distinct().toList(); + Map correctorMap = constructionUserService.listByIds(correctorList) + .stream().collect(Collectors.toMap(SubConstructionUser::getId, SubConstructionUser::getUserName)); + // 获取创建用户信息 + List createByList = qualityInspectionList.stream().map(QltQualityInspection::getCreateBy).distinct().toList(); + List userVoList = userService.selectUserByIds(createByList, null); + Map userMap = userVoList.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName)); + // 获取附件信息 + List ossInspectionFileIdList = qualityInspectionList.stream().map(QltQualityInspection::getInspectionFile).filter(StringUtils::isNotBlank) + .flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList(); + List ossIdList = new ArrayList<>(ossInspectionFileIdList); + List ossRectificationFileIdList = qualityInspectionList.stream().map(QltQualityInspection::getRectificationFile).filter(StringUtils::isNotBlank) + .flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).distinct().toList(); + ossIdList.addAll(ossRectificationFileIdList); + Map> ossMap = ossService.listByIds(ossIdList) + .stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + // 对象列表 => 封装对象列表 + List qualityInspectionVoList = qualityInspectionList.stream().map(qualityInspection -> { + QltQualityInspectionVo qualityInspectionVo = new QltQualityInspectionVo(); + BeanUtils.copyProperties(qualityInspection, qualityInspectionVo); + qualityInspectionVo.setProjectName(project.getProjectName()); + // 关联整改人信息 + Long corrector = qualityInspection.getCorrector(); + String correctorName = null; + if (correctorMap.containsKey(corrector)) { + correctorName = correctorMap.get(corrector); + } + qualityInspectionVo.setCorrectorName(correctorName); + // 关联创建用户信息 + Long createBy = qualityInspection.getCreateBy(); + String createByName = null; + if (userMap.containsKey(createBy)) { + createByName = userMap.get(createBy); + } + qualityInspectionVo.setCreateBy(createByName); + // 关联附件信息 + String inspectionFile = qualityInspection.getInspectionFile(); + List inspectionFileList = new ArrayList<>(); + if (StringUtils.isNotBlank(inspectionFile)) { + List inspectionFileIdList = Arrays.stream(inspectionFile.split(",")).map(Long::parseLong).toList(); + for (Long id : inspectionFileIdList) { + if (ossMap.containsKey(id)) { + inspectionFileList.add(ossMap.get(id).get(0)); + } + } + } + qualityInspectionVo.setInspectionFileList(inspectionFileList); + String rectificationFile = qualityInspection.getRectificationFile(); + List rectificationFileList = new ArrayList<>(); + if (StringUtils.isNotBlank(rectificationFile)) { + List rectificationFileIdList = Arrays.stream(rectificationFile.split(",")).map(Long::parseLong).toList(); + for (Long id : rectificationFileIdList) { + if (ossMap.containsKey(id)) { + rectificationFileList.add(ossMap.get(id).get(0)); + } + } + } + qualityInspectionVo.setRectificationFileList(rectificationFileList); + return qualityInspectionVo; + }).toList(); + qualityInspectionVoPage.setRecords(qualityInspectionVoList); + return qualityInspectionVoPage; + } + + /** + * 导出质量-检查工单 + * + * @param id 质量-检查工单id + * @param response HttpServletResponse + */ + @Override + public void exportWordById(Long id, HttpServletResponse response) { + QltQualityInspection qualityInspection = this.getById(id); + if (qualityInspection == null) { + throw new ServiceException("质量-检查工单不存在"); + } + Map replacementMap = getReplacementMap(qualityInspection); + Path targetDir = Paths.get(QltQualityConstant.getQualityInspectionFileUrl(qualityInspection)); + // 如果存在目录则直接返回,不存在则生成文件并返回 + if (!Files.exists(targetDir)) { + // 清理旧文件 + String baseUrl = QltQualityConstant.QUALITY_INSPECTION_FILE_URL + qualityInspection.getId(); + try { + Path dirPath = Paths.get(baseUrl); + if (Files.exists(dirPath)) { + FileUtils.deleteDirectory(dirPath); + } + } catch (IOException e) { + log.error("文件目录:{},清理失败", baseUrl, e); + } + // 生成文件 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(QltQualityConstant.QUALITY_INSPECTION_TEMPLATE_PATH)) { + if (is == null) { + throw new ServiceException("模板文件不存在"); + } + try (XWPFDocument document = new XWPFDocument(is)) { + // 替换段落中的文本 + for (XWPFParagraph paragraph : document.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, qualityInspection); + } + // 替换表格中的文本(如果模板中有表格) + for (XWPFTable table : document.getTables()) { + for (XWPFTableRow row : table.getRows()) { + for (XWPFTableCell cell : row.getTableCells()) { + for (XWPFParagraph paragraph : cell.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, qualityInspection); + } + } + } + } + // 创建目标目录 + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); + } + // 组合目标文件名 + String fileName = QltQualityConstant.getQualityInspectionFileName(qualityInspection); + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) { + document.write(fos); + } + } + } catch (IOException | InvalidFormatException e) { + throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + } + } + // 设置响应头,返回ZIP文件 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + DocumentUtil.zipDirectory(targetDir, targetDir, zos); + zos.flush(); + } catch (Exception e) { + throw new OssException("生成ZIP文件失败,错误信息: " + e.getMessage()); + } + } + + /** + * 根据实体获取Word的文本Map + * + * @param qualityInspection 质量-检查工单对象 + * @return Map + */ + public Map getReplacementMap(QltQualityInspection qualityInspection) { + Map replacementMap = new HashMap<>(); + String createName = userService.selectUserById(qualityInspection.getCreateBy()).getNickName(); + replacementMap.put("${createName}", createName); + Date createTime = qualityInspection.getCreateTime(); + replacementMap.put("${createTime}", createTime != null ? DateUtils.formatDateTime(createTime) : ""); + String projectName = projectService.getById(qualityInspection.getProjectId()).getProjectName(); + replacementMap.put("${projectName}", projectName); + replacementMap.put("${inspectionHeadline}", qualityInspection.getInspectionHeadline()); + String correctorName = constructionUserService.getById(qualityInspection.getCorrector()).getUserName(); + replacementMap.put("${correctorName}", correctorName); + Date rectificationTime = qualityInspection.getRectificationTime(); + replacementMap.put("${rectificationTime}", rectificationTime != null ? DateUtils.formatDateTime(rectificationTime) : ""); + String inspectionType = dictDataService.selectDictLabel(QltQualityConstant.QUALITY_INSPECTION_CHECK_TYPE, qualityInspection.getInspectionType()); + replacementMap.put("${inspectionType}", inspectionType); + Date replyPeriodDate = qualityInspection.getReplyPeriodDate(); + replacementMap.put("${replyPeriodDate}", replyPeriodDate != null ? DateUtils.formatDate(replyPeriodDate) : ""); + replacementMap.put("${inspectionResult}", qualityInspection.getInspectionResult()); + replacementMap.put("${inspectionFile}", qualityInspection.getInspectionFile()); + String inspectionStatus = dictDataService.selectDictLabel(QltQualityConstant.QUALITY_INSPECTION_STATUS_TYPE, qualityInspection.getInspectionStatus()); + replacementMap.put("${inspectionStatus}", inspectionStatus); + replacementMap.put("${rectificationResult}", qualityInspection.getRectificationResult()); + replacementMap.put("${rectificationFile}", qualityInspection.getRectificationFile()); + replacementMap.put("${verificationResult}", qualityInspection.getVerificationResult()); + return replacementMap; + } + + /** + * 替换段落中所有文本运行的占位符内容,对于 checkFile 和 rectificationFile + * 插入图片或超链接(附件)展示。 + * + * @param paragraph 当前段落 + * @param replacements 占位符与替换内容的映射 + * @param document 当前文档,用于插入图片或创建超链接 + */ + public void replaceInParagraph(XWPFParagraph paragraph, + Map replacements, + XWPFDocument document, + QltQualityInspection qualityInspection) + throws InvalidFormatException, IOException { + // 先拷贝 paragraph 里所有的 run + List runs = new ArrayList<>(paragraph.getRuns()); + // 在拷贝上遍历,修改原 paragraph(增删 run)都不会抛 CME + for (XWPFRun run : runs) { + String text = run.getText(0); + if (text != null) { + // 针对每个占位符进行检查 + for (Map.Entry entry : replacements.entrySet()) { + String placeholder = entry.getKey(); + String value = entry.getValue(); + if (text.contains(placeholder)) { + // 针对 file 进行特殊处理 + if (placeholder.equals("${inspectionFile}") || placeholder.equals("${rectificationFile}")) { + // 判断该 run 中的文本是否仅包含该占位符(建议模板中独占一行) + if (text.trim().equals(placeholder)) { + // 清空原有文本 + run.setText("", 0); + // 根据附件的后缀决定以图片或超链接展示 + if (StringUtils.isBlank(value)) { + continue; + } + // 获取附件的ossId + List ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = QltQualityConstant.getQualityInspectionFileUrl(qualityInspection) + "/file"; + for (SysOssVo ossVo : ossVoList) { + String lowerVal = ossVo.getUrl().toLowerCase(); + OssClient storage = OssFactory.instance(ossVo.getService()); + String fileDownload = storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + if (lowerVal.endsWith(".png") || lowerVal.endsWith(".jpg") || lowerVal.endsWith(".jpeg") || lowerVal.endsWith(".gif")) { + try { + DocumentUtil.insertImageDynamic(run, fileDownload, document, 300); + } catch (Exception e) { + throw new ServiceException("插入图片失败"); + } + } else { + // —— 非图片:插入超链接 —— + XWPFHyperlinkRun link = paragraph.createHyperlinkRun(ossVo.getUrl()); + link.setText(ossVo.getOriginalName()); + link.setColor("0000FF"); + link.setUnderline(UnderlinePatterns.SINGLE); + } + } + } else { + // 如果占位符与其它文本混合,可进行文本替换,提示附件展示请单独使用占位符 + text = text.replace(placeholder, "[附件]"); + run.setText(text, 0); + } + } else { + // 普通文本占位符直接替换 + if (StringUtils.isBlank(value)) { + // 如果填入值为空,清空原有文本 + run.setText("", 0); + continue; + } + text = text.replace(placeholder, value); + run.setText(text, 0); + } + } + } + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseDocumentSafetyMeetingConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseDocumentSafetyMeetingConstant.java new file mode 100644 index 0000000..d91a439 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseDocumentSafetyMeetingConstant.java @@ -0,0 +1,31 @@ +package org.dromara.safety.constant; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/14 10:50 + */ +public interface HseDocumentSafetyMeetingConstant { + + /** + * 顶级目录前缀 + */ + String TOP_FOLDER_PREFIX = "/doc/safety/meeting/"; + + /** + * 获取顶级目录前缀 + * + * @param projectId 项目id + * @return 顶级目录前缀 + */ + static String getTopFolderPrefix(Long projectId) { + return String.format("%s%s/", TOP_FOLDER_PREFIX, projectId); + } + + /** + * 图片后缀列表 + */ + List PICTURE_SUFFIX_LIST = List.of("jpeg", "jpg", "png", "webp"); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseKnowledgeDocumentConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseKnowledgeDocumentConstant.java new file mode 100644 index 0000000..c81a5a0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseKnowledgeDocumentConstant.java @@ -0,0 +1,42 @@ +package org.dromara.safety.constant; + +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/26 10:29 + */ +public interface HseKnowledgeDocumentConstant { + + /** + * 顶级目录前缀 + */ + String TOP_FOLDER_PREFIX = "doc/safety/knowledge/"; + + /** + * 顶级目录名称 + */ + String TOP_FOLDER_NAME = "知识库"; + + /** + * 二级目录名称 + */ + List SECOND_LEVEL_FOLDER_NAME = List.of("指导手册", "交底记录", "强条"); + + /** + * 图片后缀列表 + */ + List PICTURE_SUFFIX_LIST = List.of("jpeg", "jpg", "png", "webp"); + + /** + * 获取顶级目录前缀 + * + * @param projectId 项目id + * @return 顶级目录前缀 + */ + static String getTopFolderPrefix(Long projectId) { + return String.format("%s%s/", TOP_FOLDER_PREFIX, projectId); + } + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseSafetyConstant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseSafetyConstant.java new file mode 100644 index 0000000..b84aaa9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/constant/HseSafetyConstant.java @@ -0,0 +1,36 @@ +package org.dromara.safety.constant; + +import org.dromara.common.core.utils.DateUtils; +import org.dromara.safety.domain.HseSafetyInspection; + +import java.text.SimpleDateFormat; + +/** + * @author lilemy + * @date 2025/4/16 23:09 + */ +public interface HseSafetyConstant { + + String SAFETY_INSPECTION_TYPE = "safety_inspection_type"; + + String SAFETY_INSPECTION_CHECK_TYPE = "safety_inspection_check_type"; + + String SAFETY_INSPECTION_VIOLATION_TYPE = "safety_inspection_violation_type"; + + String SAFETY_INSPECTION_FILE_URL = "docs/safety/inspection/"; + + String SAFETY_INSPECTION_TEMPLATE_PATH = "template/安全生产监督检查通知书模版.docx"; + + static String getSafetyInspectionFileUrl(HseSafetyInspection safetyInspection) { + String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(safetyInspection.getUpdateTime()); + return String.format("%s%s/%s", SAFETY_INSPECTION_FILE_URL, safetyInspection.getId(), timestamp); + } + + static String getSafetyInspectionFileName(HseSafetyInspection safetyInspection) { + String createDate = DateUtils.formatDate(safetyInspection.getCreateTime()); + return String.format("安全生产监督检查通知书(%s).docx", createDate); + } + + String VIOLATION_LEVEL_TYPE = "violation_level_type"; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseDocumentSafetyMeetingController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseDocumentSafetyMeetingController.java new file mode 100644 index 0000000..6f2f159 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseDocumentSafetyMeetingController.java @@ -0,0 +1,132 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFileReq; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFolderReq; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingQueryReq; +import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingVo; +import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingRecycleBinVo; +import org.dromara.safety.service.IHseDocumentSafetyMeetingService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 安全会议纪要 + * + * @author lilemy + * @date 2025-04-14 + */ +@Validated +@RestController +@RequestMapping("/safety/documentSafetyMeeting") +public class HseDocumentSafetyMeetingController extends BaseController { + + @Resource + private IHseDocumentSafetyMeetingService documentSafetyMeetingService; + + /** + * 查询安全会议纪要列表 + */ + @SaCheckPermission("safety:documentSafetyMeeting:list") + @GetMapping("/list") + public R> list(HseDocumentSafetyMeetingQueryReq req) { + return R.ok(documentSafetyMeetingService.queryList(req)); + } + + /** + * 查询安全会议纪要回收站列表 + */ + @SaCheckPermission("safety:documentSafetyMeeting:list") + @GetMapping("/recycleBin/list") + public TableDataInfo list(HseDocumentSafetyMeetingQueryReq req, PageQuery pageQuery) { + return documentSafetyMeetingService.queryRecycleBinPageList(req, pageQuery); + } + + /** + * 获取安全会议纪要详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:documentSafetyMeeting:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(documentSafetyMeetingService.queryById(id)); + } + + /** + * 新增安全会议纪要文件夹 + */ + @SaCheckPermission("safety:documentSafetyMeeting:add") + @Log(title = "安全会议纪要", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/folder") + public R addFolder(@RequestBody HseDocumentSafetyMeetingCreateFolderReq req) { + return R.ok(documentSafetyMeetingService.insertByFolder(req)); + } + + /** + * 新增安全会议纪要文件 + */ + @SaCheckPermission("safety:documentSafetyMeeting:add") + @Log(title = "安全会议纪要", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/file") + public R addFile(@RequestPart("file") MultipartFile file, HseDocumentSafetyMeetingCreateFileReq req) { + return R.ok(documentSafetyMeetingService.insertByFile(file, req)); + } + + /** + * 批量恢复安全会议纪要文件 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:documentSafetyMeeting:edit") + @Log(title = "安全会议纪要", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/recovery/{ids}") + public R recovery(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(documentSafetyMeetingService.recoveryBatchById(List.of(ids))); + } + + /** + * 删除安全会议纪要 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:documentSafetyMeeting:remove") + @Log(title = "安全会议纪要", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(documentSafetyMeetingService.deleteWithRecycleBin(List.of(ids))); + } + + /** + * 彻底删除安全会议纪要 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:documentSafetyMeeting:remove") + @Log(title = "安全会议纪要", businessType = BusinessType.DELETE) + @DeleteMapping("/completelyDelete/{ids}") + public R completelyDelete(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(documentSafetyMeetingService.completelyDelete(List.of(ids))); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseKnowledgeDocumentController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseKnowledgeDocumentController.java new file mode 100644 index 0000000..3c6693e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseKnowledgeDocumentController.java @@ -0,0 +1,160 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileCreateReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileQueryReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentQueryReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileUpdateReq; +import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo; +import org.dromara.safety.service.IHseKnowledgeDocumentService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 安全知识库 + * + * @author lilemy + * @date 2025-06-25 + */ +@Validated +@RestController +@RequestMapping("/safety/knowledgeDocument") +public class HseKnowledgeDocumentController extends BaseController { + + @Resource + private IHseKnowledgeDocumentService hseKnowledgeDocumentService; + + /** + * 分页查询安全知识库文件列表 + */ + @SaCheckPermission("safety:knowledgeDocument:list") + @GetMapping("/file/page") + public TableDataInfo queryFilePageList(HseKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) { + return hseKnowledgeDocumentService.queryFilePageByFolderId(req, pageQuery); + } + + /** + * 查询安全知识库文件列表 + */ + @SaCheckPermission("safety:knowledgeDocument:list") + @GetMapping("/file/list/{folderId}") + public R> queryFileListByFolderId(@NotNull(message = "主键不能为空") + @PathVariable Long folderId) { + return R.ok(hseKnowledgeDocumentService.queryFileListByFolderId(folderId)); + } + + /** + * 查询安全知识库文件树列表 + */ + @SaCheckPermission("safety:knowledgeDocument:list") + @GetMapping("/folder/tree/list") + public R>> queryFolderTreeList(HseKnowledgeDocumentQueryReq req) { + List> list = hseKnowledgeDocumentService.queryFolderTreeList(req); + return R.ok(list); + } + + /** + * 查询安全知识库回收站文件列表 + */ + @SaCheckPermission("safety:knowledgeDocument:list") + @GetMapping("/recycleBin/list") + public TableDataInfo queryRecycleBinPageList(HseKnowledgeDocumentQueryReq req, PageQuery pageQuery) { + return hseKnowledgeDocumentService.queryRecycleBinPageList(req, pageQuery); + } + + /** + * 获取安全知识库详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:knowledgeDocument:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(hseKnowledgeDocumentService.queryById(id)); + } + + /** + * 新增安全知识库文件 + */ + @SaCheckPermission("safety:knowledgeDocument:add") + @Log(title = "安全知识库", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/file") + public R add(@RequestPart("file") MultipartFile file, HseKnowledgeDocumentFileCreateReq req) { + return toAjax(hseKnowledgeDocumentService.insertFile(file, req)); + } + + /** + * 修改安全知识库 + */ + @SaCheckPermission("safety:knowledgeDocument:edit") + @Log(title = "安全知识库", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/file") + public R edit(@RequestBody HseKnowledgeDocumentFileUpdateReq req) { + return toAjax(hseKnowledgeDocumentService.updateFile(req)); + } + + /** + * 删除安全知识库文件 + * + * @param id 主键 + */ + @SaCheckPermission("safety:knowledgeDocument:remove") + @Log(title = "安全知识库", businessType = BusinessType.DELETE) + @DeleteMapping("/file/{id}") + public R remove(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(hseKnowledgeDocumentService.deleteFileById(id)); + } + + /** + * 批量删除安全知识库回收站文件信息 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:knowledgeDocument:remove") + @Log(title = "安全知识库", businessType = BusinessType.DELETE) + @DeleteMapping("/file/recycleBin/{ids}") + public R removeRecycleBin(@NotNull(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(hseKnowledgeDocumentService.deleteRecycleBinFileBatchByIds(List.of(ids))); + } + + /** + * 根据主键id批量恢复 + */ + @SaCheckPermission("safety:knowledgeDocument:recovery") + @Log(title = "安全知识库", businessType = BusinessType.UPDATE) + @PostMapping("/recovery/{ids}") + public R recoveryBatchById(@NotNull(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(hseKnowledgeDocumentService.recoveryBatchById(List.of(ids))); + } + + /** + * 畅写在线修改保存回调 + */ + @SaCheckPermission("safety:knowledgeDocument:edit") + @PostMapping("/changxie/callback/{id}") + public void singleFileUploads(@NotNull(message = "主键不能为空") + @PathVariable Long id, HttpServletRequest request, HttpServletResponse response) { + hseKnowledgeDocumentService.singleFileUploads(id, request, response); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionBankController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionBankController.java new file mode 100644 index 0000000..d086f00 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionBankController.java @@ -0,0 +1,110 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankCreateReq; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankQueryReq; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankUpdateReq; +import org.dromara.safety.domain.vo.questionbank.HseQuestionBankVo; +import org.dromara.safety.service.IHseQuestionBankService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 题库 + * + * @author lilemy + * @date 2025-03-24 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/questionBank") +public class HseQuestionBankController extends BaseController { + + private final IHseQuestionBankService questionBankService; + + /** + * 查询题库列表 + */ + @SaCheckPermission("safety:questionBank:list") + @GetMapping("/list") + public TableDataInfo list(HseQuestionBankQueryReq req, PageQuery pageQuery) { + return questionBankService.queryPageList(req, pageQuery); + } + + /** + * 导出题库列表 + */ + @SaCheckPermission("safety:questionBank:export") + @Log(title = "题库", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseQuestionBankQueryReq req, HttpServletResponse response) { + List list = questionBankService.queryList(req); + ExcelUtil.exportExcel(list, "题库", HseQuestionBankVo.class, response); + } + + /** + * 获取题库详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:questionBank:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(questionBankService.queryById(id)); + } + + /** + * 新增题库 + */ + @SaCheckPermission("safety:questionBank:add") + @Log(title = "题库", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseQuestionBankCreateReq req, + HttpServletRequest request) { + return R.ok(questionBankService.insertByBo(req, request)); + } + + /** + * 修改题库 + */ + @SaCheckPermission("safety:questionBank:edit") + @Log(title = "题库", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseQuestionBankUpdateReq req) { + return toAjax(questionBankService.updateByBo(req)); + } + + /** + * 删除题库 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:questionBank:remove") + @Log(title = "题库", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(questionBankService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionUserAnswerController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionUserAnswerController.java new file mode 100644 index 0000000..c1ab0f8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionUserAnswerController.java @@ -0,0 +1,134 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerBatchDownloadFileReq; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerCreateReq; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerQueryReq; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerUpdateReq; +import org.dromara.safety.domain.vo.questionuseranswer.HseQuestionUserAnswerVo; +import org.dromara.safety.service.IHseQuestionUserAnswerService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 用户试卷存储 + * + * @author lilemy + * @date 2025-03-24 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/questionUserAnswer") +public class HseQuestionUserAnswerController extends BaseController { + + private final IHseQuestionUserAnswerService questionUserAnswerService; + + /** + * 查询用户试卷存储列表 + */ + @SaCheckPermission("safety:questionUserAnswer:list") + @GetMapping("/list") + public TableDataInfo list(HseQuestionUserAnswerQueryReq req, PageQuery pageQuery) { + return questionUserAnswerService.queryPageList(req, pageQuery); + } + + /** + * 导出用户试卷存储列表 + */ + @SaCheckPermission("safety:questionUserAnswer:export") + @Log(title = "用户试卷存储", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseQuestionUserAnswerQueryReq req, HttpServletResponse response) { + List list = questionUserAnswerService.queryList(req); + ExcelUtil.exportExcel(list, "用户试卷存储", HseQuestionUserAnswerVo.class, response); + } + + /** + * 批量下载用户试卷存储 + */ + @SaCheckPermission("safety:questionUserAnswer:export") + @Log(title = "用户试卷存储", businessType = BusinessType.EXPORT) + @RepeatSubmit() + @PostMapping("/exportFile") + public void exportFile(HseQuestionUserAnswerBatchDownloadFileReq req, + HttpServletResponse response) { + questionUserAnswerService.batchDownloadFile(req, response); + } + + /** + * 获取用户试卷存储详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:questionUserAnswer:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(questionUserAnswerService.queryById(id)); + } + + /** + * 新增用户试卷存储 + */ + @SaCheckPermission("safety:questionUserAnswer:add") + @Log(title = "用户试卷存储", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseQuestionUserAnswerCreateReq req) { + return R.ok(questionUserAnswerService.insertByBo(req)); + } + + /** + * 上传线下考试试卷存储 + */ + @SaCheckPermission("safety:questionUserAnswer:add") + @Log(title = "用户试卷存储", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/upload/zip") + public R batchUploadFileByZip(@RequestParam("file") MultipartFile multipartFile, + Long projectId) { + return R.ok(questionUserAnswerService.batchUploadFileByZip(multipartFile, projectId)); + } + + /** + * 修改用户试卷存储 + */ + @SaCheckPermission("safety:questionUserAnswer:edit") + @Log(title = "用户试卷存储", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseQuestionUserAnswerUpdateReq req) { + return toAjax(questionUserAnswerService.updateByBo(req)); + } + + /** + * 删除用户试卷存储 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:questionUserAnswer:remove") + @Log(title = "用户试卷存储", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(questionUserAnswerService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionsCategoryController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionsCategoryController.java new file mode 100644 index 0000000..18cad7c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionsCategoryController.java @@ -0,0 +1,108 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryCreateReq; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryQueryReq; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryUpdateReq; +import org.dromara.safety.domain.vo.questionscategory.HseQuestionsCategoryVo; +import org.dromara.safety.service.IHseQuestionsCategoryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 题库类别 + * + * @author lilemy + * @date 2025-04-15 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/questionsCategory") +public class HseQuestionsCategoryController extends BaseController { + + private final IHseQuestionsCategoryService questionsCategoryService; + + /** + * 查询题库类别列表 + */ + @SaCheckPermission("safety:questionsCategory:list") + @GetMapping("/list") + public TableDataInfo list(HseQuestionsCategoryQueryReq req, PageQuery pageQuery) { + return questionsCategoryService.queryPageList(req, pageQuery); + } + + /** + * 导出题库类别列表 + */ + @SaCheckPermission("safety:questionsCategory:export") + @Log(title = "题库类别", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseQuestionsCategoryQueryReq req, HttpServletResponse response) { + List list = questionsCategoryService.queryList(req); + ExcelUtil.exportExcel(list, "题库类别", HseQuestionsCategoryVo.class, response); + } + + /** + * 获取题库类别详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:questionsCategory:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(questionsCategoryService.queryById(id)); + } + + /** + * 新增题库类别 + */ + @SaCheckPermission("safety:questionsCategory:add") + @Log(title = "题库类别", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseQuestionsCategoryCreateReq req) { + return R.ok(questionsCategoryService.insertByBo(req)); + } + + /** + * 修改题库类别 + */ + @SaCheckPermission("safety:questionsCategory:edit") + @Log(title = "题库类别", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseQuestionsCategoryUpdateReq req) { + return toAjax(questionsCategoryService.updateByBo(req)); + } + + /** + * 删除题库类别 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:questionsCategory:remove") + @Log(title = "题库类别", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(questionsCategoryService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionsConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionsConfigController.java new file mode 100644 index 0000000..a02e79b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseQuestionsConfigController.java @@ -0,0 +1,108 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigCreateReq; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigQueryReq; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigUpdateReq; +import org.dromara.safety.domain.vo.questionsconfig.HseQuestionsConfigVo; +import org.dromara.safety.service.IHseQuestionsConfigService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 题库配置 + * + * @author lilemy + * @date 2025-03-24 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/questionsConfig") +public class HseQuestionsConfigController extends BaseController { + + private final IHseQuestionsConfigService questionsConfigService; + + /** + * 查询题库配置列表 + */ + @SaCheckPermission("safety:questionsConfig:list") + @GetMapping("/list") + public TableDataInfo list(HseQuestionsConfigQueryReq req, PageQuery pageQuery) { + return questionsConfigService.queryPageList(req, pageQuery); + } + + /** + * 导出题库配置列表 + */ + @SaCheckPermission("safety:questionsConfig:export") + @Log(title = "题库配置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseQuestionsConfigQueryReq req, HttpServletResponse response) { + List list = questionsConfigService.queryList(req); + ExcelUtil.exportExcel(list, "题库配置", HseQuestionsConfigVo.class, response); + } + + /** + * 获取题库配置详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:questionsConfig:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(questionsConfigService.queryById(id)); + } + + /** + * 新增题库配置 + */ + @SaCheckPermission("safety:questionsConfig:add") + @Log(title = "题库配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseQuestionsConfigCreateReq req) { + return R.ok(questionsConfigService.insertByBo(req)); + } + + /** + * 修改题库配置 + */ + @SaCheckPermission("safety:questionsConfig:edit") + @Log(title = "题库配置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseQuestionsConfigUpdateReq req) { + return toAjax(questionsConfigService.updateByBo(req)); + } + + /** + * 删除题库配置 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:questionsConfig:remove") + @Log(title = "题库配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(questionsConfigService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseRecognizeRecordController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseRecognizeRecordController.java new file mode 100644 index 0000000..3daaadf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseRecognizeRecordController.java @@ -0,0 +1,81 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordQueryReq; +import org.dromara.safety.domain.vo.recognizerecord.HseRecognizeRecordVo; +import org.dromara.safety.service.IHseRecognizeRecordService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 识别记录 + * + * @author lilemy + * @date 2025-06-24 + */ +@Validated +@RestController +@RequestMapping("/safety/recognizeRecord") +public class HseRecognizeRecordController extends BaseController { + + @Resource + private IHseRecognizeRecordService recognizeRecordService; + + /** + * 查询识别记录列表 + */ + @SaCheckPermission("safety:recognizeRecord:list") + @GetMapping("/list") + public TableDataInfo list(HseRecognizeRecordQueryReq req, PageQuery pageQuery) { + return recognizeRecordService.queryPageList(req, pageQuery); + } + + /** + * 导出识别记录列表 + */ + @SaCheckPermission("safety:recognizeRecord:export") + @Log(title = "识别记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseRecognizeRecordQueryReq req, HttpServletResponse response) { + List list = recognizeRecordService.queryList(req); + ExcelUtil.exportExcel(list, "识别记录", HseRecognizeRecordVo.class, response); + } + + /** + * 获取识别记录详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:recognizeRecord:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(recognizeRecordService.queryById(id)); + } + + /** + * 删除识别记录 + * + * @param id 主键 + */ + @SaCheckPermission("safety:recognizeRecord:remove") + @Log(title = "识别记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(recognizeRecordService.deleteById(id)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyInspectionController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyInspectionController.java new file mode 100644 index 0000000..6f333dc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyInspectionController.java @@ -0,0 +1,129 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionCreateReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionGisReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionQueryReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionUpdateReq; +import org.dromara.safety.domain.vo.safetyinspection.HseSafetyInspectionVo; +import org.dromara.safety.domain.vo.safetyinspection.HseSafetyInspectionListGisVo; +import org.dromara.safety.service.IHseSafetyInspectionService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 安全巡检工单 + * + * @author lilemy + * @date 2025-03-20 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/safetyInspection") +public class HseSafetyInspectionController extends BaseController { + + private final IHseSafetyInspectionService safetyInspectionService; + + /** + * 查询安全巡检工单列表 + */ + @SaCheckPermission("safety:safetyInspection:list") + @GetMapping("/list") + public TableDataInfo list(HseSafetyInspectionQueryReq req, PageQuery pageQuery) { + return safetyInspectionService.queryPageList(req, pageQuery); + } + + /** + * 导出安全巡检工单列表 + */ + @SaCheckPermission("safety:safetyInspection:export") + @Log(title = "安全巡检工单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseSafetyInspectionQueryReq req, HttpServletResponse response) { + List list = safetyInspectionService.queryList(req); + ExcelUtil.exportExcel(list, "安全巡检工单", HseSafetyInspectionVo.class, response); + } + + /** + * 根据主键导出安全巡检工单 + */ + @SaCheckPermission("safety:safetyInspection:export") + @Log(title = "安全巡检工单", businessType = BusinessType.EXPORT) + @PostMapping("/export/word") + public void exportWordById(@NotNull(message = "主键不能为空") Long id, + HttpServletResponse response) { + safetyInspectionService.exportWordById(id, response); + } + + /** + * 查询大屏安全信息 + */ + @GetMapping("/gis") + public R queryGisList(HseSafetyInspectionGisReq req) { + return R.ok(safetyInspectionService.queryGisList(req)); + } + + /** + * 获取安全巡检工单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:safetyInspection:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(safetyInspectionService.queryById(id)); + } + + /** + * 新增安全巡检工单 + */ + @SaCheckPermission("safety:safetyInspection:add") + @Log(title = "安全巡检工单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseSafetyInspectionCreateReq req) { + return R.ok(safetyInspectionService.insertByBo(req)); + } + + /** + * 修改安全巡检工单 + */ + @SaCheckPermission("safety:safetyInspection:edit") + @Log(title = "安全巡检工单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseSafetyInspectionUpdateReq req) { + return toAjax(safetyInspectionService.updateByBo(req)); + } + + /** + * 删除安全巡检工单 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:safetyInspection:remove") + @Log(title = "安全巡检工单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(safetyInspectionService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyLogController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyLogController.java new file mode 100644 index 0000000..48e1ace --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyLogController.java @@ -0,0 +1,108 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogCreateReq; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogQueryReq; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogUpdateReq; +import org.dromara.safety.domain.vo.safetylog.HseSafetyLogVo; +import org.dromara.safety.service.IHseSafetyLogService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 安全日志 + * + * @author lilemy + * @date 2025-03-20 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/safetyLog") +public class HseSafetyLogController extends BaseController { + + private final IHseSafetyLogService safetyLogService; + + /** + * 查询安全日志列表 + */ + @SaCheckPermission("safety:safetyLog:list") + @GetMapping("/list") + public TableDataInfo list(HseSafetyLogQueryReq req, PageQuery pageQuery) { + return safetyLogService.queryPageList(req, pageQuery); + } + + /** + * 导出安全日志列表 + */ + @SaCheckPermission("safety:safetyLog:export") + @Log(title = "安全日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseSafetyLogQueryReq req, HttpServletResponse response) { + List list = safetyLogService.queryList(req); + ExcelUtil.exportExcel(list, "安全日志", HseSafetyLogVo.class, response); + } + + /** + * 获取安全日志详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:safetyLog:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(safetyLogService.queryById(id)); + } + + /** + * 新增安全日志 + */ + @SaCheckPermission("safety:safetyLog:add") + @Log(title = "安全日志", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseSafetyLogCreateReq req) { + return R.ok(safetyLogService.insertByBo(req)); + } + + /** + * 修改安全日志 + */ + @SaCheckPermission("safety:safetyLog:edit") + @Log(title = "安全日志", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseSafetyLogUpdateReq req) { + return toAjax(safetyLogService.updateByBo(req)); + } + + /** + * 删除安全日志 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:safetyLog:remove") + @Log(title = "安全日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(safetyLogService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyWeeklyReportController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyWeeklyReportController.java new file mode 100644 index 0000000..9cc5d5f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseSafetyWeeklyReportController.java @@ -0,0 +1,108 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportCreateReq; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportQueryReq; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportUpdateReq; +import org.dromara.safety.domain.vo.safetyweeklyreport.HseSafetyWeeklyReportVo; +import org.dromara.safety.service.IHseSafetyWeeklyReportService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 安全周报 + * + * @author lilemy + * @date 2025-03-20 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/safetyWeeklyReport") +public class HseSafetyWeeklyReportController extends BaseController { + + private final IHseSafetyWeeklyReportService safetyWeeklyReportService; + + /** + * 查询安全周报列表 + */ + @SaCheckPermission("safety:safetyWeeklyReport:list") + @GetMapping("/list") + public TableDataInfo list(HseSafetyWeeklyReportQueryReq req, PageQuery pageQuery) { + return safetyWeeklyReportService.queryPageList(req, pageQuery); + } + + /** + * 导出安全周报列表 + */ + @SaCheckPermission("safety:safetyWeeklyReport:export") + @Log(title = "安全周报", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseSafetyWeeklyReportQueryReq req, HttpServletResponse response) { + List list = safetyWeeklyReportService.queryList(req); + ExcelUtil.exportExcel(list, "安全周报", HseSafetyWeeklyReportVo.class, response); + } + + /** + * 获取安全周报详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:safetyWeeklyReport:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(safetyWeeklyReportService.queryById(id)); + } + + /** + * 新增安全周报 + */ + @SaCheckPermission("safety:safetyWeeklyReport:add") + @Log(title = "安全周报", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseSafetyWeeklyReportCreateReq req) { + return R.ok(safetyWeeklyReportService.insertByBo(req)); + } + + /** + * 修改安全周报 + */ + @SaCheckPermission("safety:safetyWeeklyReport:edit") + @Log(title = "安全周报", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseSafetyWeeklyReportUpdateReq req) { + return toAjax(safetyWeeklyReportService.updateByBo(req)); + } + + /** + * 删除安全周报 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:safetyWeeklyReport:remove") + @Log(title = "安全周报", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(safetyWeeklyReportService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseTeamMeetingController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseTeamMeetingController.java new file mode 100644 index 0000000..681fc7b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseTeamMeetingController.java @@ -0,0 +1,108 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingCreateReq; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingQueryReq; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingUpdateReq; +import org.dromara.safety.domain.vo.teammeeting.HseTeamMeetingVo; +import org.dromara.safety.service.IHseTeamMeetingService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 站班会 + * + * @author lilemy + * @date 2025-03-19 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/safety/teamMeeting") +public class HseTeamMeetingController extends BaseController { + + private final IHseTeamMeetingService teamMeetingService; + + /** + * 查询站班会列表 + */ + @SaCheckPermission("safety:teamMeeting:list") + @GetMapping("/list") + public TableDataInfo list(HseTeamMeetingQueryReq req, PageQuery pageQuery) { + return teamMeetingService.queryPageList(req, pageQuery); + } + + /** + * 导出站班会列表 + */ + @SaCheckPermission("safety:teamMeeting:export") + @Log(title = "站班会", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseTeamMeetingQueryReq req, HttpServletResponse response) { + List list = teamMeetingService.queryList(req); + ExcelUtil.exportExcel(list, "站班会", HseTeamMeetingVo.class, response); + } + + /** + * 获取站班会详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:teamMeeting:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(teamMeetingService.queryById(id)); + } + + /** + * 新增站班会 + */ + @SaCheckPermission("safety:teamMeeting:add") + @Log(title = "站班会", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody HseTeamMeetingCreateReq req) { + return R.ok(teamMeetingService.insertByBo(req)); + } + + /** + * 修改站班会 + */ + @SaCheckPermission("safety:teamMeeting:edit") + @Log(title = "站班会", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody HseTeamMeetingUpdateReq req) { + return toAjax(teamMeetingService.updateByBo(req)); + } + + /** + * 删除站班会 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:teamMeeting:remove") + @Log(title = "站班会", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(teamMeetingService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseViolationLevelController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseViolationLevelController.java new file mode 100644 index 0000000..f7a60a9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseViolationLevelController.java @@ -0,0 +1,107 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelCreateReq; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelQueryReq; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelUpdateReq; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelByPostVo; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelVo; +import org.dromara.safety.service.IHseViolationLevelService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 违章等级 + * + * @author lilemy + * @date 2025-06-20 + */ +@Validated +@RestController +@RequestMapping("/safety/violationLevel") +public class HseViolationLevelController extends BaseController { + + @Resource + private IHseViolationLevelService hseViolationLevelService; + + /** + * 查询违章等级列表 + */ + @SaCheckPermission("safety:violationLevel:list") + @GetMapping("/list") + public TableDataInfo list(HseViolationLevelQueryReq req, PageQuery pageQuery) { + return hseViolationLevelService.queryPageList(req, pageQuery); + } + + /** + * 导出违章等级列表 + */ + @SaCheckPermission("safety:violationLevel:export") + @Log(title = "违章等级", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HseViolationLevelQueryReq req, HttpServletResponse response) { + List list = hseViolationLevelService.queryList(req); + ExcelUtil.exportExcel(list, "违章等级", HseViolationLevelVo.class, response); + } + + /** + * 获取违章等级详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:violationLevel:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(hseViolationLevelService.queryById(id)); + } + + /** + * 新增违章等级 + */ + @SaCheckPermission("safety:violationLevel:add") + @Log(title = "违章等级", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated @RequestBody HseViolationLevelCreateReq req) { + return R.ok(hseViolationLevelService.insertByBo(req)); + } + + /** + * 修改违章等级 + */ + @SaCheckPermission("safety:violationLevel:edit") + @Log(title = "违章等级", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated @RequestBody HseViolationLevelUpdateReq req) { + return toAjax(hseViolationLevelService.updateByBo(req)); + } + + /** + * 删除违章等级 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:violationLevel:remove") + @Log(title = "违章等级", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(hseViolationLevelService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseViolationRecordController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseViolationRecordController.java new file mode 100644 index 0000000..dcca219 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/controller/HseViolationRecordController.java @@ -0,0 +1,81 @@ +package org.dromara.safety.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateHandlerReq; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordQueryReq; +import org.dromara.safety.domain.vo.violationrecord.HseViolationRecordVo; +import org.dromara.safety.service.IHseViolationRecordService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 违规记录 + * + * @author lilemy + * @date 2025-07-22 + */ +@Validated +@RestController +@RequestMapping("/safety/violationRecord") +public class HseViolationRecordController extends BaseController { + + @Resource + private IHseViolationRecordService hseViolationRecordService; + + /** + * 查询违规记录列表 + */ + @SaCheckPermission("safety:violationRecord:list") + @GetMapping("/list") + public TableDataInfo list(HseViolationRecordQueryReq req, PageQuery pageQuery) { + return hseViolationRecordService.queryPageList(req, pageQuery); + } + + /** + * 获取违规记录详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("safety:violationRecord:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(hseViolationRecordService.queryById(id)); + } + + /** + * 新增违规记录处理人 + */ + @SaCheckPermission("safety:violationRecord:insertHandler") + @Log(title = "违规记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/handler") + public R insertHandler(@Validated @RequestBody HseViolationRecordCreateHandlerReq req) { + return toAjax(hseViolationRecordService.insertHandler(req)); + } + + /** + * 删除违规记录 + * + * @param ids 主键串 + */ + @SaCheckPermission("safety:violationRecord:remove") + @Log(title = "违规记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(hseViolationRecordService.deleteWithValidByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseDocumentSafetyMeeting.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseDocumentSafetyMeeting.java new file mode 100644 index 0000000..233017a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseDocumentSafetyMeeting.java @@ -0,0 +1,88 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 安全会议纪要对象 hse_document_safety_meeting + * + * @author lilemy + * @date 2025-04-14 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_document_safety_meeting") +public class HseDocumentSafetyMeeting extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件url + */ + private String fileUrl; + + /** + * 文件类型(1文件-2文件夹-3图片) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private Date deletedAt; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseKnowledgeDocument.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseKnowledgeDocument.java new file mode 100644 index 0000000..bb4b0d5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseKnowledgeDocument.java @@ -0,0 +1,87 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 安全知识库对象 hse_knowledge_document + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_knowledge_document") +public class HseKnowledgeDocument extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件访问路径 + */ + private String fileUrl; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private Date deletedAt; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionBank.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionBank.java new file mode 100644 index 0000000..8923acf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionBank.java @@ -0,0 +1,66 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 题库对象 hse_question_bank + * + * @author lilemy + * @date 2025-03-24 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_question_bank") +public class HseQuestionBank extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 题目类别 + */ + private Long categoryId; + + /** + * 题目类型 + */ + private String questionType; + + /** + * 题目内容 + */ + private String questionContent; + + /** + * 选项(以JSON数组形式存储) + */ + private String options; + + /** + * 正确答案 + */ + private String correctAnswer; + + /** + * 创建人设备类型 + */ + private String wxOrPc; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionUserAnswer.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionUserAnswer.java new file mode 100644 index 0000000..703377f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionUserAnswer.java @@ -0,0 +1,81 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 用户试卷存储对象 hse_question_user_answer + * + * @author lilemy + * @date 2025-03-24 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_question_user_answer") +public class HseQuestionUserAnswer extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户id + */ + private Long userId; + + /** + * 题库id列表 + */ + private String bankId; + + /** + * 答案列表 + */ + private String answer; + + /** + * 得分 + */ + private Long score; + + /** + * 考试时间(时间戳/秒) + */ + private Long examTime; + + /** + * 用时时间(时间戳/秒) + */ + private Long takeTime; + + /** + * 及格线/总分(格式:60,100) + */ + private String pass; + + /** + * 文件地址 + */ + private String file; + + /** + * 考试类型(1线上考试 2线下考试) + */ + private String examType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionsCategory.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionsCategory.java new file mode 100644 index 0000000..27a91ed --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionsCategory.java @@ -0,0 +1,50 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 题库类别对象 hse_questions_category + * + * @author lilemy + * @date 2025-04-15 + */ +@Data +@TableName("hse_questions_category") +public class HseQuestionsCategory implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 题库类别 + */ + private String categoryName; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionsConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionsConfig.java new file mode 100644 index 0000000..9ef41df --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseQuestionsConfig.java @@ -0,0 +1,79 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 题库配置对象 hse_questions_config + * + * @author lilemy + * @date 2025-03-24 + */ +@Data +@TableName("hse_questions_config") +public class HseQuestionsConfig implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 单选题(单位/道) + */ + private Long singleChoice; + + /** + * 单选分数 + */ + private Long singleScore; + + /** + * 多选题(单位/道) + */ + private Long multipleChoice; + + /** + * 多选分数 + */ + private Long multipleScore; + + /** + * 判断题(单位/道) + */ + private Long estimate; + + /** + * 判断分数 + */ + private Long estimateScore; + + /** + * 满分 + */ + private Long fullMark; + + /** + * 及格线 + */ + private Long passScore; + + /** + * 答题最大时间(单位/分钟) + */ + private Long answerTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseRecognizeRecord.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseRecognizeRecord.java new file mode 100644 index 0000000..70d99d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseRecognizeRecord.java @@ -0,0 +1,85 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 识别记录对象 hse_recognize_record + * + * @author lilemy + * @date 2025-06-24 + */ +@Data +@TableName("hse_recognize_record") +public class HseRecognizeRecord implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 识别类别(1无人机识别 2监控拍摄) + */ + private String recordCategory; + + /** + * 违章类型(多个逗号分隔) + */ + private String violationType; + + /** + * 图片路径 + */ + private String picture; + + /** + * 违规数量 + */ + private Integer num; + + /** + * 故障描述 + */ + private String description; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyInspection.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyInspection.java new file mode 100644 index 0000000..6e34a8f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyInspection.java @@ -0,0 +1,137 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 安全巡检工单对象 hse_safety_inspection + * + * @author lilemy + * @date 2025-03-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_safety_inspection") +public class HseSafetyInspection extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + + /** + * 父id(默认为0) + */ + private Long pid; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 检查类型 + */ + private String checkType; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 巡检结果 + */ + private String inspectionResult; + + /** + * 整改班组id + */ + private Long teamId; + + /** + * 整改人(班组长)id + */ + private Long correctorId; + + /** + * 整改期限 + */ + private Date rectificationDeadline; + + /** + * 是否回复(1回复 2不回复) + */ + private String isReply; + + /** + * 回复日期 + */ + private String replyDate; + + /** + * 工单状态(1通知 2整改 3复查) + */ + private String status; + + /** + * 问题隐患 + */ + private String hiddenDanger; + + /** + * 整改措施 + */ + private String measure; + + /** + * 复查情况 + */ + private String review; + + /** + * 复查状态(1通过 2未通过) + */ + private String reviewType; + + /** + * 检查时间 + */ + private Date checkTime; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 复查时间 + */ + private Date reviewTime; + + /** + * 检查附件 + */ + private String checkFile; + + /** + * 整改附件 + */ + private String rectificationFile; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyLog.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyLog.java new file mode 100644 index 0000000..6a83f70 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyLog.java @@ -0,0 +1,111 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 安全日志对象 hse_safety_log + * + * @author lilemy + * @date 2025-03-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_safety_log") +public class HseSafetyLog extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 发生日期 + */ + private String dateOfOccurrence; + + /** + * 最高气温 + */ + private Long airTemperatureMax; + + /** + * 最低气温 + */ + private Long airTemperatureMin; + + /** + * 气候 + */ + private String weather; + + /** + * 进展 + */ + private String progress; + + /** + * 作业内容 + */ + private String jobContent; + + /** + * 交底情况 + */ + private String discloseCondition; + + /** + * 活动情况 + */ + private String activityCondition; + + /** + * 检查情况 + */ + private String examineCondition; + + /** + * 实施情况 + */ + private String implementCondition; + + /** + * 安全检查情况 + */ + private String safetyInspectionCondition; + + /** + * 停工或加班情况 + */ + private String stoppageOrOvertime; + + /** + * 其他情况 + */ + private String otherCondition; + + /** + * 文件id列表 + */ + private String fileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyWeeklyReport.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyWeeklyReport.java new file mode 100644 index 0000000..527bf61 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseSafetyWeeklyReport.java @@ -0,0 +1,61 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 安全周报对象 hse_safety_weekly_report + * + * @author lilemy + * @date 2025-03-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_safety_weekly_report") +public class HseSafetyWeeklyReport extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 周期 + */ + private String week; + + /** + * 周期范围 + */ + private String scope; + + /** + * 周期范围结束 + */ + private String scopeEnd; + + /** + * 文件位置 + */ + private String path; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseTeamMeeting.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseTeamMeeting.java new file mode 100644 index 0000000..fddbb38 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseTeamMeeting.java @@ -0,0 +1,77 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 站班会对象 hse_team_meeting + * + * @author lilemy + * @date 2025-03-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_team_meeting") +public class HseTeamMeeting extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 开会时间 + */ + private Date meetingDate; + + /** + * 宣讲人 + */ + private Long compereId; + + /** + * 参与人id(多个用,号隔开) + */ + private String participantId; + + /** + * 班会内容 + */ + private String content; + + /** + * 班会图片(多个用,号隔开) + */ + private String picture; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationLevel.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationLevel.java new file mode 100644 index 0000000..830970e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationLevel.java @@ -0,0 +1,56 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 违章等级对象 hse_violation_level + * + * @author lilemy + * @date 2025-06-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_violation_level") +public class HseViolationLevel extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 违章等级 + */ + private String violationLevel; + + /** + * 颜色 + */ + private String color; + + /** + * 风险等级 + */ + private String riskType; + + /** + * 违章类型(多个逗号分隔) + */ + private String violationType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationLevelPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationLevelPost.java new file mode 100644 index 0000000..211b0ca --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationLevelPost.java @@ -0,0 +1,35 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 等级与岗位关联对象 hse_violation_level_post + * + * @author lilemy + * @date 2025-06-20 + */ +@Data +@TableName("hse_violation_level_post") +public class HseViolationLevelPost implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 等级 + */ + @TableId(type = IdType.INPUT) + private Long level; + + /** + * 岗位 + */ + private Long post; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationRecord.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationRecord.java new file mode 100644 index 0000000..443aca9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/HseViolationRecord.java @@ -0,0 +1,112 @@ +package org.dromara.safety.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 违规记录对象 hse_violation_record + * + * @author lilemy + * @date 2025-07-22 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("hse_violation_record") +public class HseViolationRecord extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 违章等级id + */ + private Long levelId; + + /** + * 识别记录id + */ + private Long recognizeId; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 违章时间 + */ + private Date violationTime; + + /** + * 违章处理人id + */ + private Long handlerId; + + /** + * 处理期限 + */ + private Date disposeDeadline; + + /** + * 处理时间 + */ + private Date disposeTime; + + /** + * 整改措施 + */ + private String measure; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 复查情况 + */ + private String review; + + /** + * 复查状态(1通过 2未通过) + */ + private String reviewType; + + /** + * 复查时间 + */ + private Date reviewTime; + + /** + * 处理流程类型(0仅通知 1通知整改复查) + */ + private String processType; + + /** + * 工单状态(1通知 2整改 3复查) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingCreateFileReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingCreateFileReq.java new file mode 100644 index 0000000..5b71b5d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingCreateFileReq.java @@ -0,0 +1,30 @@ +package org.dromara.safety.domain.dto.documentsafetymeeting; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/14 10:06 + */ +@Data +public class HseDocumentSafetyMeetingCreateFileReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4889729533450017719L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingCreateFolderReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingCreateFolderReq.java new file mode 100644 index 0000000..ad1027e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingCreateFolderReq.java @@ -0,0 +1,41 @@ +package org.dromara.safety.domain.dto.documentsafetymeeting; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/14 10:06 + */ +@Data +public class HseDocumentSafetyMeetingCreateFolderReq implements Serializable { + + @Serial + private static final long serialVersionUID = 486922166637112952L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + @NotNull(message = "文件名称不能为空") + private String fileName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingQueryReq.java new file mode 100644 index 0000000..f80cf8a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/documentsafetymeeting/HseDocumentSafetyMeetingQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.safety.domain.dto.documentsafetymeeting; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/14 10:04 + */ +@Data +public class HseDocumentSafetyMeetingQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5290567924829663119L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件类型(1文件-2文件夹-3图片) + */ + private String fileType; + + /** + * 不是文件类型(1文件-2文件夹-3图片) + */ + private String notFileType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileCreateReq.java new file mode 100644 index 0000000..52fa32a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileCreateReq.java @@ -0,0 +1,33 @@ +package org.dromara.safety.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 11:39 + */ +@Data +public class HseKnowledgeDocumentFileCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 4262046408641303686L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileQueryReq.java new file mode 100644 index 0000000..6adb971 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileQueryReq.java @@ -0,0 +1,32 @@ +package org.dromara.safety.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 14:43 + */ +@Data +public class HseKnowledgeDocumentFileQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2641241219631684277L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件夹id + */ + private Long folderId; + + /** + * 文件名 + */ + private String fileName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileUpdateReq.java new file mode 100644 index 0000000..d1012f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentFileUpdateReq.java @@ -0,0 +1,38 @@ +package org.dromara.safety.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 11:43 + */ +@Data +public class HseKnowledgeDocumentFileUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7715282474964511324L; + + /** + * 主键id + */ + private Long id; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentQueryReq.java new file mode 100644 index 0000000..55c4a66 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/knowledgedocument/HseKnowledgeDocumentQueryReq.java @@ -0,0 +1,27 @@ +package org.dromara.safety.domain.dto.knowledgedocument; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/26 11:16 + */ +@Data +public class HseKnowledgeDocumentQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1678465205213645248L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 文件名 + */ + private String fileName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankCreateReq.java new file mode 100644 index 0000000..14d4c90 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankCreateReq.java @@ -0,0 +1,48 @@ +package org.dromara.safety.domain.dto.questionbank; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/24 17:32 + */ +@Data +public class HseQuestionBankCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 9014952417764490638L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 题目类别 + */ + private Long categoryId; + + /** + * 题目类型 + */ + private String questionType; + + /** + * 题目内容 + */ + private String questionContent; + + /** + * 选项(以JSON数组形式存储) + */ + private List optionList; + + /** + * 正确答案 + */ + private String correctAnswer; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankQueryReq.java new file mode 100644 index 0000000..c37857c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankQueryReq.java @@ -0,0 +1,53 @@ +package org.dromara.safety.domain.dto.questionbank; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/24 17:33 + */ +@Data +public class HseQuestionBankQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8924454189341614745L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 题目类别 + */ + private Long categoryId; + + /** + * 题目类型 + */ + private String questionType; + + /** + * 题目内容 + */ + private String questionContent; + + /** + * 选项(以JSON数组形式存储) + */ + private List optionList; + + /** + * 正确答案 + */ + private String correctAnswer; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankUpdateReq.java new file mode 100644 index 0000000..64200a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionbank/HseQuestionBankUpdateReq.java @@ -0,0 +1,48 @@ +package org.dromara.safety.domain.dto.questionbank; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/24 17:33 + */ +@Data +public class HseQuestionBankUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 4537637385171186219L; + + /** + * 主键id + */ + private Long id; + + /** + * 题目类别 + */ + private Long categoryId; + + /** + * 题目类型 + */ + private String questionType; + + /** + * 题目内容 + */ + private String questionContent; + + /** + * 选项(以JSON数组形式存储) + */ + private List optionList; + + /** + * 正确答案 + */ + private String correctAnswer; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryCreateReq.java new file mode 100644 index 0000000..e324779 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryCreateReq.java @@ -0,0 +1,28 @@ +package org.dromara.safety.domain.dto.questionscategory; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/15 9:39 + */ +@Data +public class HseQuestionsCategoryCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -3517465472029929723L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 题库类别 + */ + private String categoryName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryQueryReq.java new file mode 100644 index 0000000..2fc50e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryQueryReq.java @@ -0,0 +1,28 @@ +package org.dromara.safety.domain.dto.questionscategory; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/15 9:39 + */ +@Data +public class HseQuestionsCategoryQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8543449238477998979L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 题库类别 + */ + private String categoryName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryUpdateReq.java new file mode 100644 index 0000000..4477a65 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionscategory/HseQuestionsCategoryUpdateReq.java @@ -0,0 +1,33 @@ +package org.dromara.safety.domain.dto.questionscategory; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/15 9:39 + */ +@Data +public class HseQuestionsCategoryUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6588543841396112020L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 题库类别 + */ + private String categoryName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigCreateReq.java new file mode 100644 index 0000000..11fd638 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigCreateReq.java @@ -0,0 +1,67 @@ +package org.dromara.safety.domain.dto.questionsconfig; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/24 17:34 + */ +@Data +public class HseQuestionsConfigCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6430325731025840429L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 单选题(单位/道) + */ + private Long singleChoice; + + /** + * 单选分数 + */ + private Long singleScore; + + /** + * 多选题(单位/道) + */ + private Long multipleChoice; + + /** + * 多选分数 + */ + private Long multipleScore; + + /** + * 判断题(单位/道) + */ + private Long estimate; + + /** + * 判断分数 + */ + private Long estimateScore; + + /** + * 满分 + */ + private Long fullMark; + + /** + * 及格线 + */ + private Long passScore; + + /** + * 答题最大时间(单位/分钟) + */ + private Long answerTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigQueryReq.java new file mode 100644 index 0000000..8523a3a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigQueryReq.java @@ -0,0 +1,72 @@ +package org.dromara.safety.domain.dto.questionsconfig; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/24 17:34 + */ +@Data +public class HseQuestionsConfigQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8187034953273515023L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 单选题(单位/道) + */ + private Long singleChoice; + + /** + * 单选分数 + */ + private Long singleScore; + + /** + * 多选题(单位/道) + */ + private Long multipleChoice; + + /** + * 多选分数 + */ + private Long multipleScore; + + /** + * 判断题(单位/道) + */ + private Long estimate; + + /** + * 判断分数 + */ + private Long estimateScore; + + /** + * 满分 + */ + private Long fullMark; + + /** + * 及格线 + */ + private Long passScore; + + /** + * 答题最大时间(单位/分钟) + */ + private Long answerTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigUpdateReq.java new file mode 100644 index 0000000..2ce1ad0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionsconfig/HseQuestionsConfigUpdateReq.java @@ -0,0 +1,67 @@ +package org.dromara.safety.domain.dto.questionsconfig; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/24 17:34 + */ +@Data +public class HseQuestionsConfigUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6861554491377407420L; + + /** + * 主键id + */ + private Long id; + + /** + * 单选题(单位/道) + */ + private Long singleChoice; + + /** + * 单选分数 + */ + private Long singleScore; + + /** + * 多选题(单位/道) + */ + private Long multipleChoice; + + /** + * 多选分数 + */ + private Long multipleScore; + + /** + * 判断题(单位/道) + */ + private Long estimate; + + /** + * 判断分数 + */ + private Long estimateScore; + + /** + * 满分 + */ + private Long fullMark; + + /** + * 及格线 + */ + private Long passScore; + + /** + * 答题最大时间(单位/分钟) + */ + private Long answerTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerBatchDownloadFileReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerBatchDownloadFileReq.java new file mode 100644 index 0000000..538ec20 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerBatchDownloadFileReq.java @@ -0,0 +1,24 @@ +package org.dromara.safety.domain.dto.questionuseranswer; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/15 16:35 + */ +@Data +public class HseQuestionUserAnswerBatchDownloadFileReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5011807834768249135L; + + /** + * 主键列表 + */ + private List idList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerCreateReq.java new file mode 100644 index 0000000..4b608ce --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.safety.domain.dto.questionuseranswer; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/24 17:35 + */ +@Data +public class HseQuestionUserAnswerCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -8893028317840090277L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户id + */ + private Long userId; + + /** + * 题库id列表 + */ + private List bankIdList; + + /** + * 答案列表 + */ + private List answerList; + + /** + * 得分 + */ + private Long score; + + /** + * 用时时间(时间戳/秒) + */ + private Long takeTime; + + /** + * 文件地址 + */ + private String file; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerQueryReq.java new file mode 100644 index 0000000..de8e731 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerQueryReq.java @@ -0,0 +1,33 @@ +package org.dromara.safety.domain.dto.questionuseranswer; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/24 17:35 + */ +@Data +public class HseQuestionUserAnswerQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -7056242109124074218L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户名 + */ + private String userName; + + /** + * 班组id + */ + private Long teamId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerUpdateReq.java new file mode 100644 index 0000000..8823934 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerUpdateReq.java @@ -0,0 +1,63 @@ +package org.dromara.safety.domain.dto.questionuseranswer; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/24 17:35 + */ +@Data +public class HseQuestionUserAnswerUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -588982799152215348L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户id + */ + private Long userId; + + /** + * 题库id列表 + */ + private List bankIdList; + + /** + * 答案列表 + */ + private List answerList; + + /** + * 得分 + */ + private Long score; + + /** + * 用时时间(时间戳/秒) + */ + private Long takeTime; + + /** + * 及格线/总分(格式:60,100) + */ + private String pass; + + /** + * 文件地址 + */ + private String file; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerUploadTemp.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerUploadTemp.java new file mode 100644 index 0000000..89ae587 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/questionuseranswer/HseQuestionUserAnswerUploadTemp.java @@ -0,0 +1,47 @@ +package org.dromara.safety.domain.dto.questionuseranswer; + +import lombok.Data; + +/** + * @author lilemy + * @date 2025/4/15 14:34 + */ +@Data +public class HseQuestionUserAnswerUploadTemp { + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户身份证 + */ + private String userIdCard; + + /** + * 用户姓名 + */ + private String userName; + + /** + * 满分 + */ + private Long fullScore; + + /** + * 得分 + */ + private Long score; + + /** + * 及格分数 + */ + private Long passScore; + + /** + * 文件地址 + */ + private String file; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/recognizerecord/HseRecognizeRecordCreateDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/recognizerecord/HseRecognizeRecordCreateDto.java new file mode 100644 index 0000000..27ea10d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/recognizerecord/HseRecognizeRecordCreateDto.java @@ -0,0 +1,55 @@ +package org.dromara.safety.domain.dto.recognizerecord; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.manager.recognizermanager.vo.RecognizeTargetVo; + +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/24 11:48 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HseRecognizeRecordCreateDto { + + /** + * 项目id + */ + private Long projectId; + + /** + * 设备序列号 + */ + private String deviceSerial; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 识别类别(1无人机识别 2监控拍摄) + */ + private String recordCategory; + + /** + * 图片路径 + */ + private String picture; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 目标信息 + */ + private List targets; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/recognizerecord/HseRecognizeRecordQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/recognizerecord/HseRecognizeRecordQueryReq.java new file mode 100644 index 0000000..e04ecc7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/recognizerecord/HseRecognizeRecordQueryReq.java @@ -0,0 +1,48 @@ +package org.dromara.safety.domain.dto.recognizerecord; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/6/24 11:05 + */ +@Data +public class HseRecognizeRecordQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8542182388042031320L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 识别类别(1无人机识别 2监控拍摄) + */ + private String recordCategory; + + /** + * 违章类型(多个逗号分隔) + */ + private String violationType; + + /** + * 故障描述 + */ + private String description; + + /** + * 创建时间 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionCreateReq.java new file mode 100644 index 0000000..c88b599 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionCreateReq.java @@ -0,0 +1,126 @@ +package org.dromara.safety.domain.dto.safetyinspection; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/19 11:00 + */ +@Data +public class HseSafetyInspectionCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5355703238184894846L; + + /** + * 父id(默认为0) + */ + private Long pid; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 检查类型 + */ + private String checkType; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 巡检结果 + */ + private String inspectionResult; + + /** + * 整改班组id + */ + private Long teamId; + + /** + * 整改人(班组长)id + */ + private Long correctorId; + + /** + * 整改期限 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date rectificationDeadline; + + /** + * 是否回复(1回复 2不回复) + */ + private String isReply; + + /** + * 回复日期 + */ + private String replyDate; + + /** + * 工单状态(1通知 2整改 3复查) + */ + private String status; + + /** + * 问题隐患 + */ + private String hiddenDanger; + + /** + * 整改措施 + */ + private String measure; + + /** + * 复查情况 + */ + private String review; + + /** + * 复查状态(1通过 2未通过) + */ + private String reviewType; + + /** + * 检查时间 + */ + private Date checkTime; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 复查时间 + */ + private Date reviewTime; + + /** + * 检查附件 + */ + private String checkFile; + + /** + * 整改附件 + */ + private String rectificationFile; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionGisReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionGisReq.java new file mode 100644 index 0000000..23f590a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionGisReq.java @@ -0,0 +1,30 @@ +package org.dromara.safety.domain.dto.safetyinspection; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/4/28 15:31 + */ +@Data +public class HseSafetyInspectionGisReq implements Serializable { + + @Serial + private static final long serialVersionUID = 873967698184867248L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 分页大小 + */ + private Integer pageSize = 20; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionQueryReq.java new file mode 100644 index 0000000..04ecf79 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionQueryReq.java @@ -0,0 +1,58 @@ +package org.dromara.safety.domain.dto.safetyinspection; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/19 11:01 + */ +@Data +public class HseSafetyInspectionQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8880866939746311233L; + + /** + * 父id(默认为0) + */ + private Long pid; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 检查类型 + */ + private String checkType; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 整改班组id + */ + private Long teamId; + + /** + * 整改人(班组长)id + */ + private Long correctorId; + + /** + * 工单状态(1通知 2整改 3复查) + */ + private String status; + + /** + * 复查状态(1通过 2未通过) + */ + private String reviewType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionUpdateReq.java new file mode 100644 index 0000000..1f4f274 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyinspection/HseSafetyInspectionUpdateReq.java @@ -0,0 +1,131 @@ +package org.dromara.safety.domain.dto.safetyinspection; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/3/19 11:01 + */ +@Data +public class HseSafetyInspectionUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5443601902997524139L; + + /** + * 主键ID + */ + private Long id; + + /** + * 父id(默认为0) + */ + private Long pid; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 检查类型 + */ + private String checkType; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 巡检结果 + */ + private String inspectionResult; + + /** + * 整改班组id + */ + private Long teamId; + + /** + * 整改人(班组长)id + */ + private Long correctorId; + + /** + * 整改期限 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date rectificationDeadline; + + /** + * 是否回复(1回复 2不回复) + */ + private String isReply; + + /** + * 回复日期 + */ + private String replyDate; + + /** + * 工单状态(1通知 2整改 3复查) + */ + private String status; + + /** + * 问题隐患 + */ + private String hiddenDanger; + + /** + * 整改措施 + */ + private String measure; + + /** + * 复查情况 + */ + private String review; + + /** + * 复查状态(1通过 2未通过) + */ + private String reviewType; + + /** + * 检查时间 + */ + private Date checkTime; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 复查时间 + */ + private Date reviewTime; + + /** + * 检查附件 + */ + private String checkFile; + + /** + * 整改附件 + */ + private String rectificationFile; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogCreateReq.java new file mode 100644 index 0000000..01cd2c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogCreateReq.java @@ -0,0 +1,98 @@ +package org.dromara.safety.domain.dto.safetylog; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/20 14:40 + */ +@Data +public class HseSafetyLogCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 7902209238488203624L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 发生日期 + */ + private String dateOfOccurrence; + + /** + * 最高气温 + */ + private Long airTemperatureMax; + + /** + * 最低气温 + */ + private Long airTemperatureMin; + + /** + * 气候 + */ + private String weather; + + /** + * 进展 + */ + private String progress; + + /** + * 作业内容 + */ + private String jobContent; + + /** + * 交底情况 + */ + private String discloseCondition; + + /** + * 活动情况 + */ + private String activityCondition; + + /** + * 检查情况 + */ + private String examineCondition; + + /** + * 实施情况 + */ + private String implementCondition; + + /** + * 安全检查情况 + */ + private String safetyInspectionCondition; + + /** + * 停工或加班情况 + */ + private String stoppageOrOvertime; + + /** + * 其他情况 + */ + private String otherCondition; + + /** + * 文件id列表 + */ + private String fileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogQueryReq.java new file mode 100644 index 0000000..a3210af --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.safety.domain.dto.safetylog; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/20 14:40 + */ +@Data +public class HseSafetyLogQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 2954315254418593105L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 发生日期 + */ + private String dateOfOccurrence; + + /** + * 创建人 + */ + private String creatorName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogUpdateReq.java new file mode 100644 index 0000000..a4f8ca5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetylog/HseSafetyLogUpdateReq.java @@ -0,0 +1,103 @@ +package org.dromara.safety.domain.dto.safetylog; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/20 14:40 + */ +@Data +public class HseSafetyLogUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8109768478468736455L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 发生日期 + */ + private String dateOfOccurrence; + + /** + * 最高气温 + */ + private Long airTemperatureMax; + + /** + * 最低气温 + */ + private Long airTemperatureMin; + + /** + * 气候 + */ + private String weather; + + /** + * 进展 + */ + private String progress; + + /** + * 作业内容 + */ + private String jobContent; + + /** + * 交底情况 + */ + private String discloseCondition; + + /** + * 活动情况 + */ + private String activityCondition; + + /** + * 检查情况 + */ + private String examineCondition; + + /** + * 实施情况 + */ + private String implementCondition; + + /** + * 安全检查情况 + */ + private String safetyInspectionCondition; + + /** + * 停工或加班情况 + */ + private String stoppageOrOvertime; + + /** + * 其他情况 + */ + private String otherCondition; + + /** + * 文件id列表 + */ + private String fileId; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportCreateReq.java new file mode 100644 index 0000000..208d980 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportCreateReq.java @@ -0,0 +1,47 @@ +package org.dromara.safety.domain.dto.safetyweeklyreport; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/20 15:18 + */ +@Data +public class HseSafetyWeeklyReportCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5473182951365487135L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 周期 + */ + private String week; + + /** + * 周期范围 + */ + private String scope; + + /** + * 周期范围结束 + */ + private String scopeEnd; + + /** + * 文件位置 + */ + private String path; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportQueryReq.java new file mode 100644 index 0000000..cf32cda --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportQueryReq.java @@ -0,0 +1,44 @@ +package org.dromara.safety.domain.dto.safetyweeklyreport; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/20 15:18 + */ +@Data +public class HseSafetyWeeklyReportQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -6673067596591751334L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 周期 + */ + private String week; + + /** + * 周期范围 + */ + private List scopeDate; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportUpdateReq.java new file mode 100644 index 0000000..739725f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/safetyweeklyreport/HseSafetyWeeklyReportUpdateReq.java @@ -0,0 +1,48 @@ +package org.dromara.safety.domain.dto.safetyweeklyreport; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/3/20 15:18 + */ +@Data +public class HseSafetyWeeklyReportUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -2130234917426422988L; + + /** + * 主键id + */ + private Long id; + + /** + * 周期 + */ + private String week; + + /** + * 周期范围 + */ + private String scope; + + /** + * 周期范围结束 + */ + private String scopeEnd; + + /** + * 文件位置 + */ + private String path; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingCreateReq.java new file mode 100644 index 0000000..2ed4026 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingCreateReq.java @@ -0,0 +1,67 @@ +package org.dromara.safety.domain.dto.teammeeting; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/19 11:00 + */ +@Data +public class HseTeamMeetingCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = 5355703238184894846L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 开会时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date meetingDate; + + /** + * 宣讲人 + */ + private Long compereId; + + /** + * 参与人id(多个用,号隔开) + */ + private List participantIdList; + + /** + * 班会内容 + */ + private String content; + + /** + * 班会图片(多个用,号隔开) + */ + private String picture; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingQueryReq.java new file mode 100644 index 0000000..f576a42 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingQueryReq.java @@ -0,0 +1,67 @@ +package org.dromara.safety.domain.dto.teammeeting; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/19 11:01 + */ +@Data +public class HseTeamMeetingQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 8880866939746311233L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 开会时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date meetingDate; + + /** + * 宣讲人 + */ + private Long compereId; + + /** + * 参与人id(多个用,号隔开) + */ + private List participantIdList; + + /** + * 班会内容 + */ + private String content; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingUpdateReq.java new file mode 100644 index 0000000..547fa06 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/teammeeting/HseTeamMeetingUpdateReq.java @@ -0,0 +1,72 @@ +package org.dromara.safety.domain.dto.teammeeting; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/3/19 11:01 + */ +@Data +public class HseTeamMeetingUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5443601902997524139L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 班组id + */ + private Long teamId; + + /** + * 分包公司id + */ + private Long contractorId; + + /** + * 开会时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date meetingDate; + + /** + * 宣讲人 + */ + private Long compereId; + + /** + * 参与人id(多个用,号隔开) + */ + private List participantIdList; + + /** + * 班会内容 + */ + private String content; + + /** + * 班会图片(多个用,号隔开) + */ + private String picture; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelCreateReq.java new file mode 100644 index 0000000..672b643 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelCreateReq.java @@ -0,0 +1,54 @@ +package org.dromara.safety.domain.dto.violationlevel; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/20 11:17 + */ +@Data +public class HseViolationLevelCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -4225755294412571262L; + + /** + * 项目id + */ + @NotNull(message = "项目id不能为空") + private Long projectId; + + /** + * 违章等级 + */ + @NotNull(message = "违章等级不能为空") + private String violationLevel; + + /** + * 颜色 + */ + private String color; + + /** + * 风险等级 + */ + private String riskType; + + /** + * 岗位 + */ + @NotNull(message = "岗位不能为空") + private List postIdList; + + /** + * 违章类型(多个逗号分隔) + */ + @NotNull(message = "违章类型不能为空") + private String violationType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelQueryReq.java new file mode 100644 index 0000000..4d7dc31 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelQueryReq.java @@ -0,0 +1,38 @@ +package org.dromara.safety.domain.dto.violationlevel; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/20 11:17 + */ +@Data +public class HseViolationLevelQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = -988722207116292047L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 违章等级 + */ + private String violationLevel; + + /** + * 风险等级 + */ + private String riskType; + + /** + * 违章类型(多个逗号分隔) + */ + private String violationType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelUpdateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelUpdateReq.java new file mode 100644 index 0000000..574955c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationlevel/HseViolationLevelUpdateReq.java @@ -0,0 +1,51 @@ +package org.dromara.safety.domain.dto.violationlevel; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/20 11:18 + */ +@Data +public class HseViolationLevelUpdateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5859829053886378192L; + + /** + * 主键id + */ + @NotNull(message = "主键id不能为空") + private Long id; + + /** + * 违章等级 + */ + private String violationLevel; + + /** + * 颜色 + */ + private String color; + + /** + * 风险等级 + */ + private String riskType; + + /** + * 岗位 + */ + private List postIdList; + + /** + * 违章类型(多个逗号分隔) + */ + private String violationType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordCreateDto.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordCreateDto.java new file mode 100644 index 0000000..9ef557f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordCreateDto.java @@ -0,0 +1,44 @@ +package org.dromara.safety.domain.dto.violationrecord; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/7/22 14:28 + */ +@Data +public class HseViolationRecordCreateDto implements Serializable { + + @Serial + private static final long serialVersionUID = 5895177891570353747L; + + /** + * 项目id + */ + private Long projectId; + + /** + * 识别记录id + */ + private Long recognizeId; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 违章时间 + */ + private Date violationTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordCreateHandlerReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordCreateHandlerReq.java new file mode 100644 index 0000000..a3c0129 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordCreateHandlerReq.java @@ -0,0 +1,49 @@ +package org.dromara.safety.domain.dto.violationrecord; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.Future; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/7/22 11:07 + */ +@Data +public class HseViolationRecordCreateHandlerReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5274907523390625095L; + + /** + * 主键id + */ + @NotNull(message = "id不能为空") + private Long id; + + /** + * 违章处理人id + */ + @NotNull(message = "处理人不能为空") + private Long handlerId; + + /** + * 处理期限 + */ + @NotNull(message = "处理期限不能为空") + @Future(message = "处理期限不能小于当前时间") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + private Date disposeDeadline; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordQueryReq.java new file mode 100644 index 0000000..3d91338 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/dto/violationrecord/HseViolationRecordQueryReq.java @@ -0,0 +1,41 @@ +package org.dromara.safety.domain.dto.violationrecord; + +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/7/22 11:06 + */ +@Data +public class HseViolationRecordQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 1084576574388146447L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 违章时间 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date violationTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseRecordCategoryEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseRecordCategoryEnum.java new file mode 100644 index 0000000..0dd0e7c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseRecordCategoryEnum.java @@ -0,0 +1,24 @@ +package org.dromara.safety.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/6/24 14:37 + */ +@Getter +public enum HseRecordCategoryEnum { + + DRONE("无人机识别", "1"), + MONITOR("监控设备识别", "2"); + + private final String text; + + private final String value; + + HseRecordCategoryEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyExamTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyExamTypeEnum.java new file mode 100644 index 0000000..5f20209 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyExamTypeEnum.java @@ -0,0 +1,24 @@ +package org.dromara.safety.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/15 14:56 + */ +@Getter +public enum HseSafetyExamTypeEnum { + + ONLINE("线上考试", "1"), + OFFLINE("线下考试", "2"); + + private final String text; + + private final String value; + + HseSafetyExamTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyInspectionReviewTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyInspectionReviewTypeEnum.java new file mode 100644 index 0000000..a3106ae --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyInspectionReviewTypeEnum.java @@ -0,0 +1,24 @@ +package org.dromara.safety.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/28 15:49 + */ +@Getter +public enum HseSafetyInspectionReviewTypeEnum { + + PASS("通过", "1"), + UNPASS("未通过", "2"); + + private final String text; + + private final String value; + + HseSafetyInspectionReviewTypeEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyInspectionStatusEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyInspectionStatusEnum.java new file mode 100644 index 0000000..0da1675 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/enums/HseSafetyInspectionStatusEnum.java @@ -0,0 +1,25 @@ +package org.dromara.safety.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/4/28 15:47 + */ +@Getter +public enum HseSafetyInspectionStatusEnum { + + INFORM("通知", "1"), + RECTIFICATION("整改", "2"), + REVIEW("复查", "3"); + + private final String text; + + private final String value; + + HseSafetyInspectionStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/documentsafetymeeting/HseDocumentSafetyMeetingRecycleBinVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/documentsafetymeeting/HseDocumentSafetyMeetingRecycleBinVo.java new file mode 100644 index 0000000..c96428f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/documentsafetymeeting/HseDocumentSafetyMeetingRecycleBinVo.java @@ -0,0 +1,74 @@ +package org.dromara.safety.domain.vo.documentsafetymeeting; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/14 17:44 + */ +@Data +public class HseDocumentSafetyMeetingRecycleBinVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1302984678621164410L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件url + */ + private String fileUrl; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private Date deletedAt; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/documentsafetymeeting/HseDocumentSafetyMeetingVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/documentsafetymeeting/HseDocumentSafetyMeetingVo.java new file mode 100644 index 0000000..d40dde7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/documentsafetymeeting/HseDocumentSafetyMeetingVo.java @@ -0,0 +1,74 @@ +package org.dromara.safety.domain.vo.documentsafetymeeting; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.safety.domain.HseDocumentSafetyMeeting; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 安全会议纪要视图对象 hse_document_safety_meeting + * + * @author lilemy + * @date 2025-04-14 + */ +@Data +@AutoMapper(target = HseDocumentSafetyMeeting.class) +public class HseDocumentSafetyMeetingVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件url + */ + private String fileUrl; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/knowledgedocument/HseKnowledgeDocumentVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/knowledgedocument/HseKnowledgeDocumentVo.java new file mode 100644 index 0000000..23fa6cb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/knowledgedocument/HseKnowledgeDocumentVo.java @@ -0,0 +1,85 @@ +package org.dromara.safety.domain.vo.knowledgedocument; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.safety.domain.HseKnowledgeDocument; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 安全知识库视图对象 hse_knowledge_document + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@AutoMapper(target = HseKnowledgeDocument.class) +public class HseKnowledgeDocumentVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 父级(0代表顶级) + */ + private Long pid; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件路径 + */ + private String filePath; + + /** + * 文件访问路径 + */ + private String fileUrl; + + /** + * 文件类型(1文件夹 2文件 3图片) + */ + private String fileType; + + /** + * 文件后缀 + */ + private String fileSuffix; + + /** + * 状态(0正常 1删除) + */ + private String fileStatus; + + /** + * 原文件名 + */ + private String originalName; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionbank/HseQuestionBankVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionbank/HseQuestionBankVo.java new file mode 100644 index 0000000..68d8c22 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionbank/HseQuestionBankVo.java @@ -0,0 +1,84 @@ +package org.dromara.safety.domain.vo.questionbank; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.safety.domain.HseQuestionBank; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 题库视图对象 hse_question_bank + * + * @author lilemy + * @date 2025-03-24 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseQuestionBank.class) +public class HseQuestionBankVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 题目类别id + */ + private Long categoryId; + + /** + * 题目类别名称 + */ + @ExcelProperty(value = "题目类别名称") + private String categoryName; + + /** + * 题目类型 + */ + @ExcelProperty(value = "题目类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "safety_question_type") + private String questionType; + + /** + * 题目内容 + */ + @ExcelProperty(value = "题目内容") + private String questionContent; + + /** + * 选项(以JSON数组形式存储) + */ + @ExcelProperty(value = "选项") + private List optionList; + + /** + * 正确答案 + */ + @ExcelProperty(value = "正确答案") + private String correctAnswer; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionscategory/HseQuestionsCategoryVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionscategory/HseQuestionsCategoryVo.java new file mode 100644 index 0000000..a9ee070 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionscategory/HseQuestionsCategoryVo.java @@ -0,0 +1,39 @@ +package org.dromara.safety.domain.vo.questionscategory; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.safety.domain.HseQuestionsCategory; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 题库类别视图对象 hse_questions_category + * + * @author lilemy + * @date 2025-04-15 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseQuestionsCategory.class) +public class HseQuestionsCategoryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 题库类别 + */ + @ExcelProperty(value = "题库类别") + private String categoryName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionsconfig/HseQuestionsConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionsconfig/HseQuestionsConfigVo.java new file mode 100644 index 0000000..58d832d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionsconfig/HseQuestionsConfigVo.java @@ -0,0 +1,94 @@ +package org.dromara.safety.domain.vo.questionsconfig; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.safety.domain.HseQuestionsConfig; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 题库配置视图对象 hse_questions_config + * + * @author lilemy + * @date 2025-03-24 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseQuestionsConfig.class) +public class HseQuestionsConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 单选题(单位/道) + */ + @ExcelProperty(value = "单选题") + private Long singleChoice; + + /** + * 单选分数 + */ + @ExcelProperty(value = "单选分数") + private Long singleScore; + + /** + * 多选题(单位/道) + */ + @ExcelProperty(value = "多选题") + private Long multipleChoice; + + /** + * 多选分数 + */ + @ExcelProperty(value = "多选分数") + private Long multipleScore; + + /** + * 判断题(单位/道) + */ + @ExcelProperty(value = "判断题") + private Long estimate; + + /** + * 判断分数 + */ + @ExcelProperty(value = "判断分数") + private Long estimateScore; + + /** + * 满分 + */ + @ExcelProperty(value = "满分") + private Long fullMark; + + /** + * 及格线 + */ + @ExcelProperty(value = "及格线") + private Long passScore; + + /** + * 答题最大时间(单位/分钟) + */ + @ExcelProperty(value = "答题最大时间") + private Long answerTime; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionuseranswer/HseQuestionUserAnswerVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionuseranswer/HseQuestionUserAnswerVo.java new file mode 100644 index 0000000..f8ee52d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/questionuseranswer/HseQuestionUserAnswerVo.java @@ -0,0 +1,113 @@ +package org.dromara.safety.domain.vo.questionuseranswer; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.safety.domain.HseQuestionUserAnswer; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 用户试卷存储视图对象 hse_question_user_answer + * + * @author lilemy + * @date 2025-03-24 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseQuestionUserAnswer.class) +public class HseQuestionUserAnswerVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 用户名称 + */ + @ExcelProperty(value = "用户名称") + private String userName; + + /** + * 题库id列表 + */ + @ExcelProperty(value = "题库id列表") + private List bankIdList; + + /** + * 答案列表 + */ + @ExcelProperty(value = "答案列表") + private List answerList; + + /** + * 得分 + */ + @ExcelProperty(value = "得分") + private Long score; + + /** + * 考试时间(时间戳/秒) + */ + @ExcelProperty(value = "考试时间") + private Long examTime; + + /** + * 用时时间(时间戳/秒) + */ + @ExcelProperty(value = "用时时间") + private Long takeTime; + + /** + * 及格线/总分(格式:60,100) + */ + @ExcelProperty(value = "及格线/总分") + private String pass; + + /** + * 文件地址 + */ + @ExcelProperty(value = "文件地址") + private String file; + + /** + * 文件地址列表 + */ + private List fileUrl; + + /** + * 考试类型 + */ + @ExcelProperty(value = "考试类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_exam_type") + private String examType; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/recognizerecord/HseRecognizeRecordVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/recognizerecord/HseRecognizeRecordVo.java new file mode 100644 index 0000000..0e0e177 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/recognizerecord/HseRecognizeRecordVo.java @@ -0,0 +1,87 @@ +package org.dromara.safety.domain.vo.recognizerecord; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableId; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.safety.domain.HseRecognizeRecord; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 识别记录视图对象 hse_recognize_record + * + * @author lilemy + * @date 2025-06-24 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseRecognizeRecord.class) +public class HseRecognizeRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 设备序列号 + */ + @ExcelProperty(value = "设备序列号") + private String deviceSerial; + + /** + * 设备名称 + */ + @ExcelProperty(value = "设备名称") + private String deviceName; + + /** + * 识别类别(1无人机识别 2监控拍摄) + */ + @ExcelProperty(value = "识别类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=无人机识别,2=监控拍摄") + private String recordCategory; + + /** + * 违章类型(多个逗号分隔) + */ + @ExcelProperty(value = "违章类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "violation_level_type") + private String violationType; + + /** + * 图片路径 + */ + @ExcelProperty(value = "图片路径") + private String picture; + + /** + * 故障描述 + */ + @ExcelProperty(value = "故障描述") + private String description; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyinspection/HseSafetyInspectionListGisVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyinspection/HseSafetyInspectionListGisVo.java new file mode 100644 index 0000000..415e140 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyinspection/HseSafetyInspectionListGisVo.java @@ -0,0 +1,45 @@ +package org.dromara.safety.domain.vo.safetyinspection; + +import lombok.Data; +import org.dromara.safety.domain.vo.teammeeting.HseTeamMeetingGis; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * @author lilemy + * @date 2025/4/28 15:26 + */ +@Data +public class HseSafetyInspectionListGisVo implements Serializable { + + @Serial + private static final long serialVersionUID = -8788573264526273230L; + + /** + * 站班会列表 + */ + private List teamMeetingList; + + /** + * 站班会总数 + */ + private Long teamMeetingCount; + + /** + * 安全巡检总数 + */ + private Long safetyInspectionCount; + + /** + * 整改情况总数 + */ + private Long correctSituationCount; + + /** + * 整改情况百分比 + */ + private String correctSituation; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyinspection/HseSafetyInspectionVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyinspection/HseSafetyInspectionVo.java new file mode 100644 index 0000000..7ce69d3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyinspection/HseSafetyInspectionVo.java @@ -0,0 +1,193 @@ +package org.dromara.safety.domain.vo.safetyinspection; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.safety.domain.HseSafetyInspection; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 安全巡检工单视图对象 hse_safety_inspection + * + * @author lilemy + * @date 2025-03-20 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseSafetyInspection.class) +public class HseSafetyInspectionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 父id(默认为0) + */ + @ExcelProperty(value = "父id") + private Long pid; + + /** + * 项目ID + */ + @ExcelProperty(value = "项目ID") + private Long projectId; + + /** + * 检查类型 + */ + @ExcelProperty(value = "检查类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "safety_inspection_check_type") + private String checkType; + + /** + * 违章类型 + */ + @ExcelProperty(value = "违章类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "safety_inspection_violation_type") + private String violationType; + + /** + * 巡检结果 + */ + @ExcelProperty(value = "巡检结果") + private String inspectionResult; + + /** + * 整改班组id + */ + @ExcelProperty(value = "整改班组id") + private Long teamId; + + /** + * 整改班组名字 + */ + private String teamName; + + /** + * 整改人(班组长)id + */ + @ExcelProperty(value = "整改人") + private Long correctorId; + + /** + * 整改人(班组长)名字 + */ + private String correctorName; + + /** + * 整改期限 + */ + @ExcelProperty(value = "整改期限") + private Date rectificationDeadline; + + /** + * 是否回复(1回复 2不回复) + */ + @ExcelProperty(value = "是否回复", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "reply_type") + private String isReply; + + /** + * 回复日期 + */ + @ExcelProperty(value = "回复日期") + private String replyDate; + + /** + * 工单状态(1通知 2整改 3复查) + */ + @ExcelProperty(value = "工单状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "safety_inspection_type") + private String status; + + /** + * 问题隐患 + */ + @ExcelProperty(value = "问题隐患") + private String hiddenDanger; + + /** + * 整改措施 + */ + @ExcelProperty(value = "整改措施") + private String measure; + + /** + * 复查情况 + */ + @ExcelProperty(value = "复查情况") + private String review; + + /** + * 复查状态(1通过 2未通过) + */ + @ExcelProperty(value = "复查状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "review_type") + private String reviewType; + + /** + * 检查时间 + */ + @ExcelProperty(value = "检查时间") + private Date checkTime; + + /** + * 整改时间 + */ + @ExcelProperty(value = "整改时间") + private Date rectificationTime; + + /** + * 复查时间 + */ + @ExcelProperty(value = "复查时间") + private Date reviewTime; + + /** + * 检查附件 + */ + @ExcelProperty(value = "检查附件") + private String checkFile; + + /** + * 整改附件 + */ + @ExcelProperty(value = "整改附件") + private String rectificationFile; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 创建人id + */ + private Long creatorId; + + /** + * 创建人名字 + */ + private String creatorName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetylog/HseSafetyLogVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetylog/HseSafetyLogVo.java new file mode 100644 index 0000000..8c31c0b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetylog/HseSafetyLogVo.java @@ -0,0 +1,144 @@ +package org.dromara.safety.domain.vo.safetylog; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.core.domain.vo.IdAndNameVO; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.safety.domain.HseSafetyLog; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 安全日志视图对象 hse_safety_log + * + * @author lilemy + * @date 2025-03-20 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseSafetyLog.class) +public class HseSafetyLogVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 发生日期 + */ + @ExcelProperty(value = "发生日期") + private String dateOfOccurrence; + + /** + * 最高气温 + */ + @ExcelProperty(value = "最高气温") + private Long airTemperatureMax; + + /** + * 最低气温 + */ + @ExcelProperty(value = "最低气温") + private Long airTemperatureMin; + + /** + * 气候 + */ + @ExcelProperty(value = "气候", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "weather_type") + private String weather; + + /** + * 进展 + */ + @ExcelProperty(value = "进展") + private String progress; + + /** + * 作业内容 + */ + @ExcelProperty(value = "作业内容") + private String jobContent; + + /** + * 交底情况 + */ + @ExcelProperty(value = "交底情况") + private String discloseCondition; + + /** + * 活动情况 + */ + @ExcelProperty(value = "活动情况") + private String activityCondition; + + /** + * 检查情况 + */ + @ExcelProperty(value = "检查情况") + private String examineCondition; + + /** + * 实施情况 + */ + @ExcelProperty(value = "实施情况") + private String implementCondition; + + /** + * 安全检查情况 + */ + @ExcelProperty(value = "安全检查情况") + private String safetyInspectionCondition; + + /** + * 停工或加班情况 + */ + @ExcelProperty(value = "停工或加班情况") + private String stoppageOrOvertime; + + /** + * 其他情况 + */ + @ExcelProperty(value = "其他情况") + private String otherCondition; + + /** + * 文件id列表 + */ + @ExcelProperty(value = "文件id列表") + private String fileId; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建人 + */ + private IdAndNameVO creator; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyweeklyreport/HseSafetyWeeklyReportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyweeklyreport/HseSafetyWeeklyReportVo.java new file mode 100644 index 0000000..28bc997 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/safetyweeklyreport/HseSafetyWeeklyReportVo.java @@ -0,0 +1,81 @@ +package org.dromara.safety.domain.vo.safetyweeklyreport; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.safety.domain.HseSafetyWeeklyReport; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 安全周报视图对象 hse_safety_weekly_report + * + * @author lilemy + * @date 2025-03-20 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseSafetyWeeklyReport.class) +public class HseSafetyWeeklyReportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 周期 + */ + @ExcelProperty(value = "周期") + private String week; + + /** + * 周期范围 + */ + @ExcelProperty(value = "周期范围") + private String scope; + + /** + * 周期范围结束 + */ + @ExcelProperty(value = "周期范围结束") + private String scopeEnd; + + /** + * 文件位置 + */ + @ExcelProperty(value = "文件位置") + private String path; + + /** + * 文件位置 + */ + private String pathUrl; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/teammeeting/HseTeamMeetingGis.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/teammeeting/HseTeamMeetingGis.java new file mode 100644 index 0000000..942ce47 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/teammeeting/HseTeamMeetingGis.java @@ -0,0 +1,42 @@ +package org.dromara.safety.domain.vo.teammeeting; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author lilemy + * @date 2025/4/28 15:27 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HseTeamMeetingGis { + + /** + * 主键id + */ + private Long id; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 名称 + */ + private String name; + + /** + * 开会时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd", + timezone = "GMT+8") + private Date meetingDate; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/teammeeting/HseTeamMeetingVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/teammeeting/HseTeamMeetingVo.java new file mode 100644 index 0000000..7d993a8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/teammeeting/HseTeamMeetingVo.java @@ -0,0 +1,123 @@ +package org.dromara.safety.domain.vo.teammeeting; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.core.domain.vo.IdAndNameVO; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.safety.domain.HseTeamMeeting; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 站班会视图对象 hse_team_meeting + * + * @author lilemy + * @date 2025-03-19 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseTeamMeeting.class) +public class HseTeamMeetingVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 班组id + */ + @ExcelProperty(value = "班组id") + private Long teamId; + + /** + * 班组名称 + */ + private String teamName; + + /** + * 分包公司id + */ + @ExcelProperty(value = "分包公司id") + private Long contractorId; + + /** + * 分包公司 + */ + private String contractorName; + + /** + * 开会时间 + */ + @ExcelProperty(value = "开会时间") + private Date meetingDate; + + /** + * 宣讲人 + */ + @ExcelProperty(value = "宣讲人") + private Long compereId; + + /** + * 宣讲人 + */ + private String compereName; + + /** + * 参与人id(多个用,号隔开) + */ + @ExcelProperty(value = "参与人id", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "多=个用,号隔开") + private String participantId; + + /** + * 参与人列表 + */ + private List participantList; + + /** + * 班会内容 + */ + @ExcelProperty(value = "班会内容") + private String content; + + /** + * 班会图片(多个用,号隔开) + */ + @ExcelProperty(value = "班会图片") + private String picture; + + /** + * 班会图片列表 + */ + private List pictureUrlList; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevel/HseViolationLevelByPostVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevel/HseViolationLevelByPostVo.java new file mode 100644 index 0000000..d770a99 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevel/HseViolationLevelByPostVo.java @@ -0,0 +1,61 @@ +package org.dromara.safety.domain.vo.violationlevel; + +import lombok.Data; +import org.dromara.system.domain.vo.SysPostVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/20 14:22 + */ +@Data +public class HseViolationLevelByPostVo implements Serializable { + + @Serial + private static final long serialVersionUID = -5927532440663249467L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 违章等级 + */ + private String violationLevel; + + /** + * 颜色 + */ + private String color; + + /** + * 风险等级 + */ + private String riskType; + + /** + * 违章类型(多个逗号分隔) + */ + private String violationType; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 岗位 + */ + private List postList; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevel/HseViolationLevelVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevel/HseViolationLevelVo.java new file mode 100644 index 0000000..48fbe66 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevel/HseViolationLevelVo.java @@ -0,0 +1,74 @@ +package org.dromara.safety.domain.vo.violationlevel; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.safety.domain.HseViolationLevel; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 违章等级视图对象 hse_violation_level + * + * @author lilemy + * @date 2025-06-20 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseViolationLevel.class) +public class HseViolationLevelVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 项目id + */ + @ExcelProperty(value = "项目id") + private Long projectId; + + /** + * 违章等级 + */ + @ExcelProperty(value = "违章等级") + private String violationLevel; + + /** + * 颜色 + */ + @ExcelProperty(value = "颜色") + private String color; + + /** + * 风险等级 + */ + @ExcelProperty(value = "风险等级", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "risk_level_type") + private String riskType; + + /** + * 违章类型(多个逗号分隔) + */ + @ExcelProperty(value = "违章类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "violation_level_type") + private String violationType; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevelpost/HseViolationLevelPostVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevelpost/HseViolationLevelPostVo.java new file mode 100644 index 0000000..f340a7a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationlevelpost/HseViolationLevelPostVo.java @@ -0,0 +1,39 @@ +package org.dromara.safety.domain.vo.violationlevelpost; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.safety.domain.HseViolationLevelPost; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 等级与岗位关联视图对象 hse_violation_level_post + * + * @author lilemy + * @date 2025-06-20 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = HseViolationLevelPost.class) +public class HseViolationLevelPostVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 等级 + */ + @ExcelProperty(value = "等级") + private Long level; + + /** + * 岗位 + */ + @ExcelProperty(value = "岗位") + private Long post; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationrecord/HseViolationRecordVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationrecord/HseViolationRecordVo.java new file mode 100644 index 0000000..27c08b5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/domain/vo/violationrecord/HseViolationRecordVo.java @@ -0,0 +1,145 @@ +package org.dromara.safety.domain.vo.violationrecord; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.safety.domain.HseViolationRecord; +import org.dromara.safety.domain.vo.recognizerecord.HseRecognizeRecordVo; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelVo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 违规记录视图对象 hse_violation_record + * + * @author lilemy + * @date 2025-07-22 + */ +@Data +@AutoMapper(target = HseViolationRecord.class) +public class HseViolationRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Long id; + + /** + * 项目id + */ + private Long projectId; + + /** + * 违章等级id + */ + private Long levelId; + + /** + * 违章等级 + */ + private HseViolationLevelVo levelVo; + + /** + * 识别记录id + */ + private Long recognizeId; + + /** + * 识别记录 + */ + private HseRecognizeRecordVo recognizeVo; + + /** + * 违章类型 + */ + private String violationType; + + /** + * 违章时间 + */ + private Date violationTime; + + /** + * 违章处理人id + */ + private Long handlerId; + + /** + * 违章处理人名称 + */ + private String handlerName; + + /** + * 处理期限 + */ + private Date disposeDeadline; + + /** + * 处理时间 + */ + private Date disposeTime; + + /** + * 整改措施 + */ + private String measure; + + /** + * 整改时间 + */ + private Date rectificationTime; + + /** + * 复查情况 + */ + private String review; + + /** + * 复查状态(1通过 2未通过) + */ + private String reviewType; + + /** + * 复查时间 + */ + private Date reviewTime; + + /** + * 处理流程类型(0仅通知 1通知整改复查) + */ + private String processType; + + /** + * 工单状态(1通知 2整改 3复查) + */ + private String status; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 创建人名字 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseDocumentSafetyMeetingMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseDocumentSafetyMeetingMapper.java new file mode 100644 index 0000000..33ed899 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseDocumentSafetyMeetingMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseDocumentSafetyMeeting; +import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 安全会议纪要Mapper接口 + * + * @author lilemy + * @date 2025-04-14 + */ +public interface HseDocumentSafetyMeetingMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseKnowledgeDocumentMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseKnowledgeDocumentMapper.java new file mode 100644 index 0000000..830d2e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseKnowledgeDocumentMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseKnowledgeDocument; +import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 安全知识库Mapper接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface HseKnowledgeDocumentMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionBankMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionBankMapper.java new file mode 100644 index 0000000..a9620b8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionBankMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseQuestionBank; +import org.dromara.safety.domain.vo.questionbank.HseQuestionBankVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 题库Mapper接口 + * + * @author lilemy + * @date 2025-03-24 + */ +public interface HseQuestionBankMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionUserAnswerMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionUserAnswerMapper.java new file mode 100644 index 0000000..ad0f56b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionUserAnswerMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseQuestionUserAnswer; +import org.dromara.safety.domain.vo.questionuseranswer.HseQuestionUserAnswerVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 用户试卷存储Mapper接口 + * + * @author lilemy + * @date 2025-03-24 + */ +public interface HseQuestionUserAnswerMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionsCategoryMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionsCategoryMapper.java new file mode 100644 index 0000000..a948300 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionsCategoryMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseQuestionsCategory; +import org.dromara.safety.domain.vo.questionscategory.HseQuestionsCategoryVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 题库类别Mapper接口 + * + * @author lilemy + * @date 2025-04-15 + */ +public interface HseQuestionsCategoryMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionsConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionsConfigMapper.java new file mode 100644 index 0000000..3d4f00c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseQuestionsConfigMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseQuestionsConfig; +import org.dromara.safety.domain.vo.questionsconfig.HseQuestionsConfigVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 题库配置Mapper接口 + * + * @author lilemy + * @date 2025-03-24 + */ +public interface HseQuestionsConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseRecognizeRecordMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseRecognizeRecordMapper.java new file mode 100644 index 0000000..94eb6b6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseRecognizeRecordMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.safety.domain.HseRecognizeRecord; +import org.dromara.safety.domain.vo.recognizerecord.HseRecognizeRecordVo; + +/** + * 识别记录Mapper接口 + * + * @author lilemy + * @date 2025-06-24 + */ +public interface HseRecognizeRecordMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyInspectionMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyInspectionMapper.java new file mode 100644 index 0000000..8df86a8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyInspectionMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseSafetyInspection; +import org.dromara.safety.domain.vo.safetyinspection.HseSafetyInspectionVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 安全巡检工单Mapper接口 + * + * @author lilemy + * @date 2025-03-20 + */ +public interface HseSafetyInspectionMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyLogMapper.java new file mode 100644 index 0000000..2c3a2e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyLogMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseSafetyLog; +import org.dromara.safety.domain.vo.safetylog.HseSafetyLogVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 安全日志Mapper接口 + * + * @author lilemy + * @date 2025-03-20 + */ +public interface HseSafetyLogMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyWeeklyReportMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyWeeklyReportMapper.java new file mode 100644 index 0000000..aa186a7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseSafetyWeeklyReportMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseSafetyWeeklyReport; +import org.dromara.safety.domain.vo.safetyweeklyreport.HseSafetyWeeklyReportVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 安全周报Mapper接口 + * + * @author lilemy + * @date 2025-03-20 + */ +public interface HseSafetyWeeklyReportMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseTeamMeetingMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseTeamMeetingMapper.java new file mode 100644 index 0000000..ed7160f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseTeamMeetingMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.safety.domain.HseTeamMeeting; +import org.dromara.safety.domain.vo.teammeeting.HseTeamMeetingVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 站班会Mapper接口 + * + * @author lilemy + * @date 2025-03-19 + */ +public interface HseTeamMeetingMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationLevelMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationLevelMapper.java new file mode 100644 index 0000000..a9bfd5a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationLevelMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.safety.domain.HseViolationLevel; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelVo; + +/** + * 违章等级Mapper接口 + * + * @author lilemy + * @date 2025-06-20 + */ +public interface HseViolationLevelMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationLevelPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationLevelPostMapper.java new file mode 100644 index 0000000..c1d35bb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationLevelPostMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.safety.domain.HseViolationLevelPost; +import org.dromara.safety.domain.vo.violationlevelpost.HseViolationLevelPostVo; + +/** + * 等级与岗位关联Mapper接口 + * + * @author lilemy + * @date 2025-06-20 + */ +public interface HseViolationLevelPostMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationRecordMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationRecordMapper.java new file mode 100644 index 0000000..263e502 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/mapper/HseViolationRecordMapper.java @@ -0,0 +1,15 @@ +package org.dromara.safety.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.safety.domain.HseViolationRecord; +import org.dromara.safety.domain.vo.violationrecord.HseViolationRecordVo; + +/** + * 违规记录Mapper接口 + * + * @author lilemy + * @date 2025-07-22 + */ +public interface HseViolationRecordMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseDocumentSafetyMeetingService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseDocumentSafetyMeetingService.java new file mode 100644 index 0000000..41028ca --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseDocumentSafetyMeetingService.java @@ -0,0 +1,125 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseDocumentSafetyMeeting; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFileReq; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFolderReq; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingQueryReq; +import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingRecycleBinVo; +import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; + +/** + * 安全会议纪要Service接口 + * + * @author lilemy + * @date 2025-04-14 + */ +public interface IHseDocumentSafetyMeetingService extends IService { + + /** + * 查询安全会议纪要 + * + * @param id 主键 + * @return 安全会议纪要 + */ + HseDocumentSafetyMeetingVo queryById(Long id); + + /** + * 分页查询安全会议纪要列表 + * + * @param req 查询条件 + * @return 安全会议纪要分页列表 + */ + List queryList(HseDocumentSafetyMeetingQueryReq req); + + /** + * 分页查询安全会议纪要回收站列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全会议纪要分页列表 + */ + TableDataInfo queryRecycleBinPageList(HseDocumentSafetyMeetingQueryReq req, PageQuery pageQuery); + + /** + * 新增安全会议纪要文件夹 + * + * @param req 文件夹创建请求 + * @return 是否新增成功 + */ + Long insertByFolder(HseDocumentSafetyMeetingCreateFolderReq req); + + /** + * 新增安全会议纪要文件 + * + * @param file 文件 + * @param req 文件上传请求 + * @return 是否新增成功 + */ + Long insertByFile(MultipartFile file, HseDocumentSafetyMeetingCreateFileReq req); + + /** + * 批量恢复安全会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean recoveryBatchById(Collection ids); + + /** + * 批量删除安全会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteWithRecycleBin(Collection ids); + + /** + * 彻底批量删除安全会议纪要 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean completelyDelete(Collection ids); + + /** + * 获取安全会议纪要视图对象 + * + * @param documentSafetyMeeting 安全会议纪要对象 + * @return 安全会议纪要视图对象 + */ + HseDocumentSafetyMeetingVo getVo(HseDocumentSafetyMeeting documentSafetyMeeting); + + /** + * 获取安全会议纪要查询条件封装 + * + * @param req 安全会议纪要查询条件 + * @return 安全会议纪要查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseDocumentSafetyMeetingQueryReq req); + + /** + * 获取安全会议纪要分页对象视图 + * + * @param documentSafetyMeetingPage 安全会议纪要分页对象 + * @return 安全会议纪要分页对象视图 + */ + Page getVoPage(Page documentSafetyMeetingPage); + + /** + * 递归查询所有的文件和文件夹以及文件夹下的子文件夹的id + * + * @param ids 主键集合 + * @return 整合所有的id集合 + */ + List getAllChildIdList(Collection ids); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseKnowledgeDocumentService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseKnowledgeDocumentService.java new file mode 100644 index 0000000..22bd594 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseKnowledgeDocumentService.java @@ -0,0 +1,152 @@ +package org.dromara.safety.service; + +import cn.hutool.core.lang.tree.Tree; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseKnowledgeDocument; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileCreateReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileQueryReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentQueryReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileUpdateReq; +import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; + +/** + * 安全知识库Service接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface IHseKnowledgeDocumentService extends IService { + + /** + * 查询安全知识库 + * + * @param id 主键 + * @return 安全知识库 + */ + HseKnowledgeDocumentVo queryById(Long id); + + /** + * 查询安全知识库文件夹树列表 + * + * @param req 查询参数 + * @return 安全知识库文件夹树列表 + */ + List> queryFolderTreeList(HseKnowledgeDocumentQueryReq req); + + /** + * 查询文件夹下的安全知识库文件分页列表 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 安全知识库文件列表 + */ + TableDataInfo queryFilePageByFolderId(HseKnowledgeDocumentFileQueryReq req, PageQuery pageQuery); + + /** + * 查询文件夹下的安全知识库文件列表 + * + * @param folderId 文件夹id + * @return 安全知识库文件列表 + */ + List queryFileListByFolderId(Long folderId); + + /** + * 查询回收站中的文件 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 回收站中的文件 + */ + TableDataInfo queryRecycleBinPageList(HseKnowledgeDocumentQueryReq req, PageQuery pageQuery); + + /** + * 新增安全知识库文件 + * + * @param file 文件 + * @param req 安全知识库 + * @return 是否新增成功 + */ + Boolean insertFile(MultipartFile file, HseKnowledgeDocumentFileCreateReq req); + + /** + * 新增安全知识库文件夹 + * + * @param projectId 项目id + * @return 是否新增成功 + */ + Boolean insertFolderByTemplate(Long projectId); + + /** + * 修改安全知识库文件 + * + * @param req 安全知识库 + * @return 是否修改成功 + */ + Boolean updateFile(HseKnowledgeDocumentFileUpdateReq req); + + /** + * 删除安全知识库文件信息 + * + * @param id 待删除文件的主键 + * @return 是否删除成功 + */ + Boolean deleteFileById(Long id); + + /** + * 批量删除安全知识库回收站文件信息 + * + * @param ids 待删除文件主键集合 + * @return 是否删除成功 + */ + Boolean deleteRecycleBinFileBatchByIds(Collection ids); + + /** + * 批量恢复安全会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean recoveryBatchById(Collection ids); + + /** + * 构建前端所需要下拉树结构 + * + * @param documentList 文档列表 + * @return 下拉树结构列表 + */ + List> buildTreeSelect(List documentList); + + /** + * 构建文档封装对象 + * + * @param document 文档 + * @return 文档封装对象 + */ + HseKnowledgeDocumentVo getVo(HseKnowledgeDocument document); + + /** + * 获取文档对象视图 + * + * @param documentPage 文档对象 + * @return 文档对象视图 + */ + Page getVoPage(Page documentPage); + + /** + * 畅写在线文件修改 + * + * @param id 文档id + * @param request 请求 + * @param response 响应 + */ + void singleFileUploads(Long id, HttpServletRequest request, HttpServletResponse response); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionBankService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionBankService.java new file mode 100644 index 0000000..c660aee --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionBankService.java @@ -0,0 +1,99 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletRequest; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseQuestionBank; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankCreateReq; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankQueryReq; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankUpdateReq; +import org.dromara.safety.domain.vo.questionbank.HseQuestionBankVo; + +import java.util.Collection; +import java.util.List; + +/** + * 题库Service接口 + * + * @author lilemy + * @date 2025-03-24 + */ +public interface IHseQuestionBankService extends IService { + + /** + * 查询题库 + * + * @param id 主键 + * @return 题库 + */ + HseQuestionBankVo queryById(Long id); + + /** + * 分页查询题库列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 题库分页列表 + */ + TableDataInfo queryPageList(HseQuestionBankQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的题库列表 + * + * @param req 查询条件 + * @return 题库列表 + */ + List queryList(HseQuestionBankQueryReq req); + + /** + * 新增题库 + * + * @param req 题库 + * @return 是否新增成功 + */ + Long insertByBo(HseQuestionBankCreateReq req, HttpServletRequest request); + + /** + * 修改题库 + * + * @param req 题库 + * @return 是否修改成功 + */ + Boolean updateByBo(HseQuestionBankUpdateReq req); + + /** + * 校验并批量删除题库信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取题库视图对象 + * + * @param questionBank 题库对象 + * @return 题库视图对象 + */ + HseQuestionBankVo getVo(HseQuestionBank questionBank); + + /** + * 获取题库查询条件封装 + * + * @param req 题库查询条件 + * @return 题库查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseQuestionBankQueryReq req); + + /** + * 获取题库分页对象视图 + * + * @param questionBankPage 题库分页对象 + * @return 题库分页对象视图 + */ + Page getVoPage(Page questionBankPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionUserAnswerService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionUserAnswerService.java new file mode 100644 index 0000000..4559d2d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionUserAnswerService.java @@ -0,0 +1,119 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseQuestionUserAnswer; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerBatchDownloadFileReq; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerCreateReq; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerQueryReq; +import org.dromara.safety.domain.dto.questionuseranswer.HseQuestionUserAnswerUpdateReq; +import org.dromara.safety.domain.vo.questionuseranswer.HseQuestionUserAnswerVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; + +/** + * 用户试卷存储Service接口 + * + * @author lilemy + * @date 2025-03-24 + */ +public interface IHseQuestionUserAnswerService extends IService { + + /** + * 查询用户试卷存储 + * + * @param id 主键 + * @return 用户试卷存储 + */ + HseQuestionUserAnswerVo queryById(Long id); + + /** + * 分页查询用户试卷存储列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 用户试卷存储分页列表 + */ + TableDataInfo queryPageList(HseQuestionUserAnswerQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的用户试卷存储列表 + * + * @param req 查询条件 + * @return 用户试卷存储列表 + */ + List queryList(HseQuestionUserAnswerQueryReq req); + + /** + * 新增用户试卷存储 + * + * @param req 用户试卷存储 + * @return 新增用户试卷存储id + */ + Long insertByBo(HseQuestionUserAnswerCreateReq req); + + /** + * 通过zip文件批量上传用户试卷存储 + * + * @param multipartFile zip文件 + * @param projectId 项目id + * @return 是否上传成功 + */ + Boolean batchUploadFileByZip(MultipartFile multipartFile, Long projectId); + + /** + * 修改用户试卷存储 + * + * @param req 用户试卷存储 + * @return 是否修改成功 + */ + Boolean updateByBo(HseQuestionUserAnswerUpdateReq req); + + /** + * 校验并批量删除用户试卷存储信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取用户试卷存储视图对象 + * + * @param questionUserAnswer 用户试卷存储对象 + * @return 用户试卷存储视图对象 + */ + HseQuestionUserAnswerVo getVo(HseQuestionUserAnswer questionUserAnswer); + + /** + * 获取用户试卷存储查询条件封装 + * + * @param req 用户试卷存储查询条件 + * @return 用户试卷存储查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseQuestionUserAnswerQueryReq req); + + /** + * 获取用户试卷存储分页对象视图 + * + * @param questionUserAnswerPage 用户试卷存储分页对象 + * @return 用户试卷存储分页对象视图 + */ + Page getVoPage(Page questionUserAnswerPage); + + /** + * 批量下载用户试卷存储文件 + * + * @param req 用户试卷存储文件下载请求 + * @param response 设置响应头和向客户端发送文件内容 + */ + void batchDownloadFile(HseQuestionUserAnswerBatchDownloadFileReq req, HttpServletResponse response); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionsCategoryService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionsCategoryService.java new file mode 100644 index 0000000..726df89 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionsCategoryService.java @@ -0,0 +1,99 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseQuestionsCategory; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryCreateReq; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryQueryReq; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryUpdateReq; +import org.dromara.safety.domain.vo.questionscategory.HseQuestionsCategoryVo; + +import java.util.Collection; +import java.util.List; + +/** + * 题库类别Service接口 + * + * @author lilemy + * @date 2025-04-15 + */ +public interface IHseQuestionsCategoryService extends IService { + + /** + * 查询题库类别 + * + * @param id 主键 + * @return 题库类别 + */ + HseQuestionsCategoryVo queryById(Long id); + + /** + * 分页查询题库类别列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 题库类别分页列表 + */ + TableDataInfo queryPageList(HseQuestionsCategoryQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的题库类别列表 + * + * @param req 查询条件 + * @return 题库类别列表 + */ + List queryList(HseQuestionsCategoryQueryReq req); + + /** + * 新增题库类别 + * + * @param req 题库类别 + * @return 新增题库类别组件 + */ + Long insertByBo(HseQuestionsCategoryCreateReq req); + + /** + * 修改题库类别 + * + * @param req 题库类别 + * @return 是否修改成功 + */ + Boolean updateByBo(HseQuestionsCategoryUpdateReq req); + + /** + * 校验并批量删除题库类别信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取题库类别视图对象 + * + * @param questionsCategory 题库类别对象 + * @return 题库类别视图对象 + */ + HseQuestionsCategoryVo getVo(HseQuestionsCategory questionsCategory); + + /** + * 获取题库类别查询条件封装 + * + * @param req 题库类别查询条件 + * @return 题库类别查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseQuestionsCategoryQueryReq req); + + /** + * 获取题库类别分页对象视图 + * + * @param questionsCategoryPage 题库类别分页对象 + * @return 题库类别分页对象视图 + */ + Page getVoPage(Page questionsCategoryPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionsConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionsConfigService.java new file mode 100644 index 0000000..bae4af3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseQuestionsConfigService.java @@ -0,0 +1,98 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseQuestionsConfig; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigCreateReq; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigQueryReq; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigUpdateReq; +import org.dromara.safety.domain.vo.questionsconfig.HseQuestionsConfigVo; + +import java.util.Collection; +import java.util.List; + +/** + * 题库配置Service接口 + * + * @author lilemy + * @date 2025-03-24 + */ +public interface IHseQuestionsConfigService extends IService { + + /** + * 查询题库配置 + * + * @param id 主键 + * @return 题库配置 + */ + HseQuestionsConfigVo queryById(Long id); + + /** + * 分页查询题库配置列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 题库配置分页列表 + */ + TableDataInfo queryPageList(HseQuestionsConfigQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的题库配置列表 + * + * @param req 查询条件 + * @return 题库配置列表 + */ + List queryList(HseQuestionsConfigQueryReq req); + + /** + * 新增题库配置 + * + * @param req 题库配置 + * @return 新增配置id + */ + Long insertByBo(HseQuestionsConfigCreateReq req); + + /** + * 修改题库配置 + * + * @param req 题库配置 + * @return 是否修改成功 + */ + Boolean updateByBo(HseQuestionsConfigUpdateReq req); + + /** + * 校验并批量删除题库配置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取题库配置视图对象 + * + * @param questionsConfig 题库配置对象 + * @return 题库配置视图对象 + */ + HseQuestionsConfigVo getVo(HseQuestionsConfig questionsConfig); + + /** + * 获取题库配置查询条件封装 + * + * @param req 题库配置查询条件 + * @return 题库配置查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseQuestionsConfigQueryReq req); + + /** + * 获取题库配置分页对象视图 + * + * @param questionsConfigPage 题库配置分页对象 + * @return 题库配置分页对象视图 + */ + Page getVoPage(Page questionsConfigPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseRecognizeRecordService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseRecognizeRecordService.java new file mode 100644 index 0000000..d6a20ea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseRecognizeRecordService.java @@ -0,0 +1,87 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseRecognizeRecord; +import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordCreateDto; +import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordQueryReq; +import org.dromara.safety.domain.vo.recognizerecord.HseRecognizeRecordVo; + +import java.util.List; + +/** + * 识别记录Service接口 + * + * @author lilemy + * @date 2025-06-24 + */ +public interface IHseRecognizeRecordService extends IService { + + /** + * 查询识别记录 + * + * @param id 主键 + * @return 识别记录 + */ + HseRecognizeRecordVo queryById(Long id); + + /** + * 分页查询识别记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 识别记录分页列表 + */ + TableDataInfo queryPageList(HseRecognizeRecordQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的识别记录列表 + * + * @param req 查询条件 + * @return 识别记录列表 + */ + List queryList(HseRecognizeRecordQueryReq req); + + /** + * 创建识别记录(摄像头) + * + * @param recordList 识别记录列表 + */ + void saveByMonitor(List recordList); + + /** + * 删除识别记录信息 + * + * @param id 待删除的主键 + * @return 是否删除成功 + */ + Boolean deleteById(Long id); + + /** + * 获取识别记录视图对象 + * + * @param recognizeRecord 识别记录对象 + * @return 识别记录视图对象 + */ + HseRecognizeRecordVo getVo(HseRecognizeRecord recognizeRecord); + + /** + * 获取识别记录查询条件封装 + * + * @param req 识别记录查询条件 + * @return 识别记录查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseRecognizeRecordQueryReq req); + + /** + * 获取识别记录分页对象视图 + * + * @param recognizeRecordPage 识别记录分页对象 + * @return 识别记录分页对象视图 + */ + Page getVoPage(Page recognizeRecordPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyInspectionService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyInspectionService.java new file mode 100644 index 0000000..ce733f0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyInspectionService.java @@ -0,0 +1,118 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseSafetyInspection; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionCreateReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionGisReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionQueryReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionUpdateReq; +import org.dromara.safety.domain.vo.safetyinspection.HseSafetyInspectionVo; +import org.dromara.safety.domain.vo.safetyinspection.HseSafetyInspectionListGisVo; + +import java.util.Collection; +import java.util.List; + +/** + * 安全巡检工单Service接口 + * + * @author lilemy + * @date 2025-03-20 + */ +public interface IHseSafetyInspectionService extends IService { + + /** + * 查询安全巡检工单 + * + * @param id 主键 + * @return 安全巡检工单 + */ + HseSafetyInspectionVo queryById(Long id); + + /** + * 分页查询安全巡检工单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全巡检工单分页列表 + */ + TableDataInfo queryPageList(HseSafetyInspectionQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的安全巡检工单列表 + * + * @param req 查询条件 + * @return 安全巡检工单列表 + */ + List queryList(HseSafetyInspectionQueryReq req); + + /** + * 查询大屏安全信息 + * + * @param req 查询条件 + * @return 安全信息 + */ + HseSafetyInspectionListGisVo queryGisList(HseSafetyInspectionGisReq req); + + /** + * 新增安全巡检工单 + * + * @param req 安全巡检工单 + * @return 是否新增成功 + */ + Long insertByBo(HseSafetyInspectionCreateReq req); + + /** + * 修改安全巡检工单 + * + * @param req 安全巡检工单 + * @return 是否修改成功 + */ + Boolean updateByBo(HseSafetyInspectionUpdateReq req); + + /** + * 校验并批量删除安全巡检工单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取安全巡检工单视图对象 + * + * @param safetyInspection 安全巡检工单对象 + * @return 安全巡检工单视图对象 + */ + HseSafetyInspectionVo getVo(HseSafetyInspection safetyInspection); + + /** + * 获取安全巡检工单查询条件封装 + * + * @param req 安全巡检工单查询条件 + * @return 安全巡检工单查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseSafetyInspectionQueryReq req); + + /** + * 获取安全巡检工单分页对象视图 + * + * @param safetyInspectionPage 安全巡检工单分页对象 + * @return 安全巡检工单分页对象视图 + */ + Page getVoPage(Page safetyInspectionPage); + + /** + * 根据id导出word + * + * @param id 主键 + * @param response 响应 + */ + void exportWordById(Long id, HttpServletResponse response); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyLogService.java new file mode 100644 index 0000000..9b77850 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyLogService.java @@ -0,0 +1,98 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseSafetyLog; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogCreateReq; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogQueryReq; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogUpdateReq; +import org.dromara.safety.domain.vo.safetylog.HseSafetyLogVo; + +import java.util.Collection; +import java.util.List; + +/** + * 安全日志Service接口 + * + * @author lilemy + * @date 2025-03-20 + */ +public interface IHseSafetyLogService extends IService { + + /** + * 查询安全日志 + * + * @param id 主键 + * @return 安全日志 + */ + HseSafetyLogVo queryById(Long id); + + /** + * 分页查询安全日志列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全日志分页列表 + */ + TableDataInfo queryPageList(HseSafetyLogQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的安全日志列表 + * + * @param req 查询条件 + * @return 安全日志列表 + */ + List queryList(HseSafetyLogQueryReq req); + + /** + * 新增安全日志 + * + * @param req 安全日志 + * @return 新增id + */ + Long insertByBo(HseSafetyLogCreateReq req); + + /** + * 修改安全日志 + * + * @param req 安全日志 + * @return 是否修改成功 + */ + Boolean updateByBo(HseSafetyLogUpdateReq req); + + /** + * 校验并批量删除安全日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取安全日志视图对象 + * + * @param safetyLog 安全日志对象 + * @return 安全日志视图对象 + */ + HseSafetyLogVo getVo(HseSafetyLog safetyLog); + + /** + * 获取安全日志查询条件封装 + * + * @param req 安全日志查询条件 + * @return 安全日志查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseSafetyLogQueryReq req); + + /** + * 获取安全日志分页对象视图 + * + * @param safetyLogPage 安全日志分页对象 + * @return 安全日志分页对象视图 + */ + Page getVoPage(Page safetyLogPage); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyWeeklyReportService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyWeeklyReportService.java new file mode 100644 index 0000000..b7b40c3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseSafetyWeeklyReportService.java @@ -0,0 +1,99 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseSafetyWeeklyReport; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportCreateReq; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportQueryReq; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportUpdateReq; +import org.dromara.safety.domain.vo.safetyweeklyreport.HseSafetyWeeklyReportVo; + +import java.util.Collection; +import java.util.List; + +/** + * 安全周报Service接口 + * + * @author lilemy + * @date 2025-03-20 + */ +public interface IHseSafetyWeeklyReportService extends IService { + + /** + * 查询安全周报 + * + * @param id 主键 + * @return 安全周报 + */ + HseSafetyWeeklyReportVo queryById(Long id); + + /** + * 分页查询安全周报列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全周报分页列表 + */ + TableDataInfo queryPageList(HseSafetyWeeklyReportQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的安全周报列表 + * + * @param req 查询条件 + * @return 安全周报列表 + */ + List queryList(HseSafetyWeeklyReportQueryReq req); + + /** + * 新增安全周报 + * + * @param req 安全周报 + * @return 是否新增成功 + */ + Long insertByBo(HseSafetyWeeklyReportCreateReq req); + + /** + * 修改安全周报 + * + * @param req 安全周报 + * @return 是否修改成功 + */ + Boolean updateByBo(HseSafetyWeeklyReportUpdateReq req); + + /** + * 校验并批量删除安全周报信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取安全周报视图对象 + * + * @param safetyWeeklyReport 安全周报对象 + * @return 安全周报视图对象 + */ + HseSafetyWeeklyReportVo getVo(HseSafetyWeeklyReport safetyWeeklyReport); + + /** + * 获取安全周报查询条件封装 + * + * @param req 安全周报查询条件 + * @return 安全周报查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseSafetyWeeklyReportQueryReq req); + + /** + * 获取安全周报分页对象视图 + * + * @param safetyWeeklyReportPage 安全周报分页对象 + * @return 安全周报分页对象视图 + */ + Page getVoPage(Page safetyWeeklyReportPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseTeamMeetingService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseTeamMeetingService.java new file mode 100644 index 0000000..6997b66 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseTeamMeetingService.java @@ -0,0 +1,99 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseTeamMeeting; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingCreateReq; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingQueryReq; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingUpdateReq; +import org.dromara.safety.domain.vo.teammeeting.HseTeamMeetingVo; + +import java.util.Collection; +import java.util.List; + +/** + * 站班会Service接口 + * + * @author lilemy + * @date 2025-03-19 + */ +public interface IHseTeamMeetingService extends IService { + + /** + * 查询站班会 + * + * @param id 主键 + * @return 站班会 + */ + HseTeamMeetingVo queryById(Long id); + + /** + * 分页查询站班会列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 站班会分页列表 + */ + TableDataInfo queryPageList(HseTeamMeetingQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的站班会列表 + * + * @param req 查询条件 + * @return 站班会列表 + */ + List queryList(HseTeamMeetingQueryReq req); + + /** + * 新增站班会 + * + * @param req 站班会 + * @return 新增站班会d + */ + Long insertByBo(HseTeamMeetingCreateReq req); + + /** + * 修改站班会 + * + * @param req 站班会 + * @return 是否修改成功 + */ + Boolean updateByBo(HseTeamMeetingUpdateReq req); + + /** + * 校验并批量删除站班会信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取站班会视图对象 + * + * @param teamMeeting 站班会对象 + * @return 站班会视图对象 + */ + HseTeamMeetingVo getVo(HseTeamMeeting teamMeeting); + + /** + * 获取站班会查询条件封装 + * + * @param req 站班会查询条件 + * @return 站班会查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseTeamMeetingQueryReq req); + + /** + * 获取站班会分页对象视图 + * + * @param teamMeetingPage 站班会分页对象 + * @return 站班会分页对象视图 + */ + Page getVoPage(Page teamMeetingPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationLevelPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationLevelPostService.java new file mode 100644 index 0000000..59d3c02 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationLevelPostService.java @@ -0,0 +1,13 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.safety.domain.HseViolationLevelPost; + +/** + * 等级与岗位关联Service接口 + * + * @author lilemy + * @date 2025-06-20 + */ +public interface IHseViolationLevelPostService extends IService { +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationLevelService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationLevelService.java new file mode 100644 index 0000000..5dd2459 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationLevelService.java @@ -0,0 +1,108 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseViolationLevel; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelCreateReq; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelQueryReq; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelUpdateReq; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelByPostVo; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelVo; + +import java.util.Collection; +import java.util.List; + +/** + * 违章等级Service接口 + * + * @author lilemy + * @date 2025-06-20 + */ +public interface IHseViolationLevelService extends IService { + + /** + * 查询违章等级 + * + * @param id 主键 + * @return 违章等级 + */ + HseViolationLevelByPostVo queryById(Long id); + + /** + * 分页查询违章等级列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 违章等级分页列表 + */ + TableDataInfo queryPageList(HseViolationLevelQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的违章等级列表 + * + * @param req 查询条件 + * @return 违章等级列表 + */ + List queryList(HseViolationLevelQueryReq req); + + /** + * 新增违章等级 + * + * @param req 违章等级 + * @return 新增违章等级主键id + */ + Long insertByBo(HseViolationLevelCreateReq req); + + /** + * 修改违章等级 + * + * @param req 违章等级 + * @return 是否修改成功 + */ + Boolean updateByBo(HseViolationLevelUpdateReq req); + + /** + * 校验并批量删除违章等级信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取违章等级视图对象 + * + * @param violationLevel 违章等级对象 + * @return 违章等级视图对象 + */ + HseViolationLevelByPostVo getByPostVo(HseViolationLevel violationLevel); + + /** + * 获取违章等级视图对象 + * + * @param violationLevel 违章等级对象 + * @return 违章等级视图对象 + */ + HseViolationLevelVo getVo(HseViolationLevel violationLevel); + + /** + * 获取违章等级查询条件封装 + * + * @param req 违章等级查询条件 + * @return 违章等级查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseViolationLevelQueryReq req); + + /** + * 获取违章等级分页对象视图 + * + * @param violationLevelPage 违章等级分页对象 + * @return 违章等级分页对象视图 + */ + Page getVoPage(Page violationLevelPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationRecordService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationRecordService.java new file mode 100644 index 0000000..f9e2735 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/IHseViolationRecordService.java @@ -0,0 +1,97 @@ +package org.dromara.safety.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.safety.domain.HseViolationRecord; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateDto; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateHandlerReq; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordQueryReq; +import org.dromara.safety.domain.vo.violationrecord.HseViolationRecordVo; + +import java.util.Collection; +import java.util.List; + +/** + * 违规记录Service接口 + * + * @author lilemy + * @date 2025-07-22 + */ +public interface IHseViolationRecordService extends IService { + + /** + * 查询违规记录 + * + * @param id 主键 + * @return 违规记录 + */ + HseViolationRecordVo queryById(Long id); + + /** + * 分页查询违规记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 违规记录分页列表 + */ + TableDataInfo queryPageList(HseViolationRecordQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的违规记录列表 + * + * @param req 查询条件 + * @return 违规记录列表 + */ + List queryList(HseViolationRecordQueryReq req); + + /** + * 新增违规记录信息 + * + * @param dto 违规记录信息 + */ + void insertByMonitor(List dto); + + /** + * 新增违章处理人 + * + * @param req 违章处理人 + * @return 是否新增成功 + */ + Boolean insertHandler(HseViolationRecordCreateHandlerReq req); + + /** + * 批量删除违规记录信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids); + + /** + * 获取违规记录视图对象 + * + * @param violationRecord 违规记录对象 + * @return 违规记录视图对象 + */ + HseViolationRecordVo getVo(HseViolationRecord violationRecord); + + /** + * 获取违规记录查询条件封装 + * + * @param req 违规记录查询条件 + * @return 违规记录查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(HseViolationRecordQueryReq req); + + /** + * 获取违规记录分页对象视图 + * + * @param violationRecordPage 违规记录分页对象 + * @return 违规记录分页对象视图 + */ + Page getVoPage(Page violationRecordPage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseDocumentSafetyMeetingServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseDocumentSafetyMeetingServiceImpl.java new file mode 100644 index 0000000..7afc206 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseDocumentSafetyMeetingServiceImpl.java @@ -0,0 +1,454 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.constant.HseDocumentSafetyMeetingConstant; +import org.dromara.safety.domain.HseDocumentSafetyMeeting; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFileReq; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFolderReq; +import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingQueryReq; +import org.dromara.common.enums.DocumentStatusEnum; +import org.dromara.common.enums.DocumentTypeEnum; +import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingRecycleBinVo; +import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingVo; +import org.dromara.safety.mapper.HseDocumentSafetyMeetingMapper; +import org.dromara.safety.service.IHseDocumentSafetyMeetingService; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 安全会议纪要Service业务层处理 + * + * @author lilemy + * @date 2025-04-14 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl + implements IHseDocumentSafetyMeetingService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + /** + * 查询安全会议纪要 + * + * @param id 主键 + * @return 安全会议纪要 + */ + @Override + public HseDocumentSafetyMeetingVo queryById(Long id) { + HseDocumentSafetyMeeting documentSafetyMeeting = this.getById(id); + if (documentSafetyMeeting == null) { + throw new ServiceException("安全会议纪要信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(documentSafetyMeeting); + } + + /** + * 分页查询安全会议纪要列表 + * + * @param req 查询条件 + * @return 安全会议纪要分页列表 + */ + @Override + public List queryList(HseDocumentSafetyMeetingQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + // 排除已经删除的文件 + lqw.eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.NORMAL.getValue()); + List result = this.list(lqw); + return result.stream().map(this::getVo).toList(); + } + + /** + * 分页查询安全会议纪要回收站列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全会议纪要分页列表 + */ + @Override + public TableDataInfo queryRecycleBinPageList(HseDocumentSafetyMeetingQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + lqw.eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.DELETE.getValue()); + Page result = this.page(pageQuery.build(), lqw); + List documentSafetyMeetingList = result.getRecords(); + // 添加分页信息 + Page documentSafetyMeetingVoPage = new Page<>( + result.getCurrent(), + result.getSize(), + result.getTotal()); + if (CollUtil.isEmpty(documentSafetyMeetingList)) { + return TableDataInfo.build(documentSafetyMeetingVoPage); + } + // 对象列表 => 封装对象列表 + List list = documentSafetyMeetingList.stream().map(documentSafetyMeeting -> { + HseDocumentSafetyMeetingRecycleBinVo resp = new HseDocumentSafetyMeetingRecycleBinVo(); + BeanUtils.copyProperties(documentSafetyMeeting, resp); + return resp; + }).toList(); + documentSafetyMeetingVoPage.setRecords(list); + return TableDataInfo.build(documentSafetyMeetingVoPage); + } + + /** + * 新增安全会议纪要文件夹 + * + * @param req 文件夹创建请求 + * @return 是否新增成功 + */ + @Override + public Long insertByFolder(HseDocumentSafetyMeetingCreateFolderReq req) { + if (req == null) { + throw new ServiceException("文件夹创建请求不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(req.getFileName())) { + throw new ServiceException("文件夹名称不能为空", HttpStatus.BAD_REQUEST); + } + HseDocumentSafetyMeeting documentSafetyMeeting = new HseDocumentSafetyMeeting(); + BeanUtils.copyProperties(req, documentSafetyMeeting); + Long pid = req.getPid(); + String filePath; + if (pid != null && pid != 0) { + HseDocumentSafetyMeeting pDocumentSafetyMeeting = this.getById(pid); + // 判断父级目录是否存在 + validParentFolder(pDocumentSafetyMeeting, req.getProjectId()); + filePath = pDocumentSafetyMeeting.getFilePath() + "/" + req.getFileName(); + } else { + filePath = HseDocumentSafetyMeetingConstant.getTopFolderPrefix(req.getProjectId()) + req.getFileName(); + } + // 填充默认值 + documentSafetyMeeting.setFilePath(filePath); + documentSafetyMeeting.setFileType(DocumentTypeEnum.FOLDER.getValue()); + boolean save = this.save(documentSafetyMeeting); + if (!save) { + throw new ServiceException("新增目录失败,数据库异常", HttpStatus.ERROR); + } + return documentSafetyMeeting.getId(); + } + + /** + * 新增安全会议纪要文件 + * + * @param req 文件上传请求 + * @return 是否新增成功 + */ + @Override + public Long insertByFile(MultipartFile file, HseDocumentSafetyMeetingCreateFileReq req) { + // 数据校验 + if (ObjectUtils.isEmpty(file)) { + throw new ServiceException("文件不能为空", HttpStatus.BAD_REQUEST); + } + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); + } + // 拼接文件名 + String originalFilename = file.getOriginalFilename(); + String suffix = FileUtil.getSuffix(originalFilename); + String uuid = IdUtil.fastSimpleUUID(); + String date = DateUtils.getDate(); + String fileName = String.format("%s_%s.%s", date, uuid, suffix); + // 拼接文件路径 + Long pid = req.getPid(); + String filePath; + if (pid != null && pid != 0) { + HseDocumentSafetyMeeting pDocumentSafetyMeeting = this.getById(pid); + // 判断父级目录是否存在 + validParentFolder(pDocumentSafetyMeeting, projectId); + filePath = pDocumentSafetyMeeting.getFilePath() + "/" + fileName; + } else { + filePath = HseDocumentSafetyMeetingConstant.getTopFolderPrefix(projectId) + fileName; + } + // 上传文件 + SysOssUploadVo ossUploadVo = ossService.uploadWithNoSave(file, filePath); + // 保存文件信息 + HseDocumentSafetyMeeting documentSafetyMeeting = new HseDocumentSafetyMeeting(); + documentSafetyMeeting.setFilePath(filePath); + documentSafetyMeeting.setFileUrl(ossUploadVo.getOssId()); + documentSafetyMeeting.setFileSuffix(suffix); + // 判断文件类型 + if (HseDocumentSafetyMeetingConstant.PICTURE_SUFFIX_LIST.contains(suffix)) { + documentSafetyMeeting.setFileType(DocumentTypeEnum.PICTURE.getValue()); + } else { + documentSafetyMeeting.setFileType(DocumentTypeEnum.FILE.getValue()); + } + documentSafetyMeeting.setFileName(ossUploadVo.getFileName()); + documentSafetyMeeting.setOriginalName(originalFilename); + documentSafetyMeeting.setProjectId(projectId); + documentSafetyMeeting.setPid(pid); + boolean save = this.save(documentSafetyMeeting); + if (!save) { + throw new ServiceException("新增文件失败,数据库异常", HttpStatus.ERROR); + } + // 返回主键 + return documentSafetyMeeting.getId(); + } + + /** + * 批量恢复安全会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean recoveryBatchById(Collection ids) { + List allParentIdsRecursively = getAllParentIdsRecursively(ids); + // 需要更新状态的文件集合 + allParentIdsRecursively.addAll(ids); + List updateList = allParentIdsRecursively.stream().map(id -> { + HseDocumentSafetyMeeting documentSafetyMeeting = new HseDocumentSafetyMeeting(); + documentSafetyMeeting.setId(id); + documentSafetyMeeting.setFileStatus(DocumentStatusEnum.NORMAL.getValue()); + return documentSafetyMeeting; + }).toList(); + boolean result = this.updateBatchById(updateList); + if (!result) { + throw new ServiceException("恢复文件失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + private List getAllParentIdsRecursively(Collection ids) { + // 使用 list() 方法批量查询当前 id 列表对应的实体数据 + List fileList = this.lambdaQuery() + .in(HseDocumentSafetyMeeting::getId, ids) + .eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.DELETE.getValue()) + .list(); + // 通过 stream 流过滤出非 0 的父 id,并去重 + List parentIdList = fileList.stream() + .map(HseDocumentSafetyMeeting::getPid) + .filter(pid -> pid != 0) + .distinct() + .collect(Collectors.toList()); + // 如果父 id 列表为空,说明递归终止,返回空列表 + if (parentIdList.isEmpty()) { + return new ArrayList<>(); + } + // 递归查询父 id 列表对应的上级父 id + List higherParentIds = getAllParentIdsRecursively(parentIdList); + // 将当前层的父 id 和上级递归得到的父 id 合并 + List allParentIds = new ArrayList<>(); + allParentIds.addAll(parentIdList); + allParentIds.addAll(higherParentIds); + // 返回合并后去重的结果 + return allParentIds.stream().distinct().collect(Collectors.toList()); + } + + + /** + * 校验父级目录是否存在 + * + * @param pDocumentSafetyMeeting 父级目录 + * @param projectId 当前项目id + */ + private void validParentFolder(HseDocumentSafetyMeeting pDocumentSafetyMeeting, Long projectId) { + // 判断父级目录是否存在 + if (pDocumentSafetyMeeting == null) { + throw new ServiceException("父级目录不存在", HttpStatus.NOT_FOUND); + } + // 判断父级目录是否是文件夹 + if (DocumentTypeEnum.FILE.getValue().equals(pDocumentSafetyMeeting.getFileType())) { + throw new ServiceException("父级目录不是文件夹", HttpStatus.BAD_REQUEST); + } + // 判断是否为同一个项目 + if (!pDocumentSafetyMeeting.getProjectId().equals(projectId)) { + throw new ServiceException("父级目录不属于当前项目", HttpStatus.BAD_REQUEST); + } + } + + /** + * 批量删除安全会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithRecycleBin(Collection ids) { + // 获取所有需要删除的元素 + List allChildIdList = this.getAllChildIdList(ids); + if (CollUtil.isEmpty(allChildIdList)) { + return true; + } + // 批量修改状态为已删除 + List documentSafetyMeetingList = allChildIdList.stream().map(id -> { + HseDocumentSafetyMeeting documentSafetyMeeting = new HseDocumentSafetyMeeting(); + documentSafetyMeeting.setId(id); + documentSafetyMeeting.setDeletedAt(new Date()); + documentSafetyMeeting.setFileStatus(DocumentStatusEnum.DELETE.getValue()); + return documentSafetyMeeting; + }).toList(); + // 批量修改 + boolean result = this.updateBatchById(documentSafetyMeetingList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 彻底批量删除安全会议纪要 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean completelyDelete(Collection ids) { + // 获取所有需要删除的元素 + List allChildIdList = this.getAllChildIdList(ids); + if (CollUtil.isEmpty(allChildIdList)) { + return true; + } + boolean result = this.removeBatchByIds(allChildIdList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + // todo 删除oss文件 + + return true; + } + + /** + * 获取安全会议纪要视图对象 + * + * @param documentSafetyMeeting 安全会议纪要对象 + * @return 安全会议纪要视图对象 + */ + @Override + public HseDocumentSafetyMeetingVo getVo(HseDocumentSafetyMeeting documentSafetyMeeting) { + // 对象转封装类 + HseDocumentSafetyMeetingVo documentSafetyMeetingVo = new HseDocumentSafetyMeetingVo(); + if (documentSafetyMeeting == null) { + return documentSafetyMeetingVo; + } + BeanUtils.copyProperties(documentSafetyMeeting, documentSafetyMeetingVo); + return documentSafetyMeetingVo; + } + + /** + * 获取安全会议纪要查询条件封装 + * + * @param req 安全会议纪要查询条件 + * @return 安全会议纪要查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseDocumentSafetyMeetingQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + Long pid = req.getPid(); + String fileType = req.getFileType(); + String notFileType = req.getNotFileType(); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseDocumentSafetyMeeting::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(pid), HseDocumentSafetyMeeting::getPid, pid); + lqw.eq(StringUtils.isNotBlank(fileType), HseDocumentSafetyMeeting::getFileType, fileType); + // 不等于 + lqw.ne(StringUtils.isNotBlank(notFileType), HseDocumentSafetyMeeting::getFileType, notFileType); + return lqw; + } + + /** + * 获取安全会议纪要分页对象视图 + * + * @param documentSafetyMeetingPage 安全会议纪要分页对象 + * @return 安全会议纪要分页对象视图 + */ + @Override + public Page getVoPage(Page documentSafetyMeetingPage) { + // 获取安全会议纪要列表 + List documentSafetyMeetingList = documentSafetyMeetingPage.getRecords(); + // 添加分页信息 + Page documentSafetyMeetingVoPage = new Page<>( + documentSafetyMeetingPage.getCurrent(), + documentSafetyMeetingPage.getSize(), + documentSafetyMeetingPage.getTotal()); + if (CollUtil.isEmpty(documentSafetyMeetingList)) { + return documentSafetyMeetingVoPage; + } + // 对象列表 => 封装对象列表 + List documentSafetyMeetingVoList = documentSafetyMeetingList + .stream().map(this::getVo).toList(); + documentSafetyMeetingVoPage.setRecords(documentSafetyMeetingVoList); + return documentSafetyMeetingVoPage; + } + + /** + * 递归查询所有的文件和文件夹以及文件夹下的子文件夹的id + * + * @param ids 主键集合 + * @return 整合所有的id集合 + */ + @Override + public List getAllChildIdList(Collection ids) { + List idList = new ArrayList<>(); + for (Long id : ids) { + // 将当前id加入集合 + idList.add(id); + // 查询当前记录(判断是否为文件夹) + HseDocumentSafetyMeeting record = this.getById(id); + if (record != null && DocumentTypeEnum.FOLDER.getValue().equals(record.getFileType())) { + // 如果是文件夹,递归查询子节点 + getChildIds(id, idList); + } + } + return idList; + } + + /** + * 递归查询给定父级id下所有子文件和子文件夹的id + * + * @param parentId 父级文件夹id + * @param ids 存放id的集合(递归过程中不断添加) + */ + private void getChildIds(Long parentId, List ids) { + // 条件查询,查询pid为parentId的记录 + List childList = this.lambdaQuery() + .eq(HseDocumentSafetyMeeting::getPid, parentId) + .eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.NORMAL.getValue()) + .list(); + // 遍历所有子记录 + for (HseDocumentSafetyMeeting child : childList) { + ids.add(child.getId()); + // 如果子节点是文件夹,继续递归 + if (DocumentTypeEnum.FOLDER.getValue().equals(child.getFileType())) { + getChildIds(child.getId(), ids); + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseKnowledgeDocumentServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseKnowledgeDocumentServiceImpl.java new file mode 100644 index 0000000..ef1233b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseKnowledgeDocumentServiceImpl.java @@ -0,0 +1,516 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.enums.DocumentStatusEnum; +import org.dromara.common.enums.DocumentTypeEnum; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.constant.HseKnowledgeDocumentConstant; +import org.dromara.safety.domain.HseKnowledgeDocument; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileCreateReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileQueryReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentQueryReq; +import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileUpdateReq; +import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo; +import org.dromara.safety.mapper.HseKnowledgeDocumentMapper; +import org.dromara.safety.service.IHseKnowledgeDocumentService; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 安全知识库Service业务层处理 + * + * @author lilemy + * @date 2025-06-25 + */ +@Slf4j +@Service +public class HseKnowledgeDocumentServiceImpl extends ServiceImpl + implements IHseKnowledgeDocumentService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + /** + * 查询安全知识库 + * + * @param id 主键 + * @return 安全知识库 + */ + @Override + public HseKnowledgeDocumentVo queryById(Long id) { + HseKnowledgeDocument entity = this.getById(id); + if (entity == null) { + throw new ServiceException("安全知识库文件或文件夹不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(entity); + } + + /** + * 查询安全知识库列表 + * + * @param req 查询参数 + * @return 安全知识库列表 + */ + @Override + public List> queryFolderTreeList(HseKnowledgeDocumentQueryReq req) { + Long projectId = req.getProjectId(); + List folderList = this.lambdaQuery() + .eq(HseKnowledgeDocument::getProjectId, projectId) + .eq(HseKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue()) + .eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue()) + .list(); + return this.buildTreeSelect(folderList); + } + + /** + * 查询文件夹下的安全知识库文件列表 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 安全知识库文件列表 + */ + @Override + public TableDataInfo queryFilePageByFolderId(HseKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long folderId = req.getFolderId(); + if (folderId != null) { + HseKnowledgeDocument folder = this.getById(folderId); + if (folder == null) { + throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND); + } + if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) { + throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST); + } + lqw.eq(HseKnowledgeDocument::getPid, folderId); + } + lqw.eq(ObjectUtils.isNotEmpty(req.getProjectId()), HseKnowledgeDocument::getProjectId, req.getProjectId()); + lqw.ne(HseKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue()); + lqw.eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue()); + lqw.like(StringUtils.isNotBlank(req.getFileName()), HseKnowledgeDocument::getFileName, req.getFileName()); + Page documentPage = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(documentPage)); + } + + /** + * 查询文件夹下的安全知识库文件列表 + * + * @param folderId 文件夹id + * @return 安全知识库文件列表 + */ + @Override + public List queryFileListByFolderId(Long folderId) { + HseKnowledgeDocument folder = this.getById(folderId); + if (folder == null) { + throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND); + } + if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) { + throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST); + } + List list = this.lambdaQuery() + .eq(HseKnowledgeDocument::getPid, folderId) + .ne(HseKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue()) + .eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue()) + .list(); + return list.stream().map(this::getVo).toList(); + } + + /** + * 查询回收站中的文件 + * + * @param req 查询参数 + * @param pageQuery 分页参数 + * @return 回收站中的文件 + */ + @Override + public TableDataInfo queryRecycleBinPageList(HseKnowledgeDocumentQueryReq req, PageQuery pageQuery) { + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(HseKnowledgeDocument::getProjectId, projectId); + lqw.eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue()); + lqw.like(StringUtils.isNotBlank(req.getFileName()), HseKnowledgeDocument::getFileName, req.getFileName()); + lqw.orderByDesc(HseKnowledgeDocument::getDeletedAt); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 新增安全知识库文件 + * + * @param req 安全知识库 + * @return 是否新增成功 + */ + @Override + public Boolean insertFile(MultipartFile file, HseKnowledgeDocumentFileCreateReq req) { + // 数据校验 + if (ObjectUtils.isEmpty(file)) { + throw new ServiceException("文件不能为空", HttpStatus.BAD_REQUEST); + } + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); + } + // 拼接文件名 + String originalFilename = file.getOriginalFilename(); + String suffix = FileUtil.getSuffix(originalFilename); + if (StringUtils.isBlank(suffix)) { + throw new ServiceException("文件格式错误", HttpStatus.BAD_REQUEST); + } + String uuid = IdUtil.fastSimpleUUID(); + String date = DateUtils.getDate(); + String fileName = String.format("%s_%s.%s", date, uuid, suffix); + // 拼接文件路径 + Long pid = req.getPid(); + if (pid == null || pid == 0) { + throw new ServiceException("不能在根目录上传文件", HttpStatus.BAD_REQUEST); + } + HseKnowledgeDocument pHseKnowledgeDocument = this.getById(pid); + // 校验父级目录 + validParentFolder(pHseKnowledgeDocument, projectId); + String filePath = pHseKnowledgeDocument.getFilePath() + "/" + fileName; + // 上传文件 + SysOssUploadVo ossUploadVo = ossService.uploadWithNoSave(file, filePath); + // 保存文件信息 + HseKnowledgeDocument knowledgeDocument = new HseKnowledgeDocument(); + knowledgeDocument.setFilePath(filePath); + knowledgeDocument.setFileUrl(ossUploadVo.getUrl()); + knowledgeDocument.setFileSuffix(suffix); + if (HseKnowledgeDocumentConstant.PICTURE_SUFFIX_LIST.contains(suffix)) { + knowledgeDocument.setFileType(DocumentTypeEnum.PICTURE.getValue()); + } else { + knowledgeDocument.setFileType(DocumentTypeEnum.FILE.getValue()); + } + knowledgeDocument.setFileName(FileUtil.getPrefix(originalFilename)); + knowledgeDocument.setOriginalName(originalFilename); + knowledgeDocument.setProjectId(projectId); + knowledgeDocument.setPid(pid); + boolean save = this.save(knowledgeDocument); + if (!save) { + throw new ServiceException("新增文件失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 新增安全知识库文件夹 + * + * @param projectId 项目id + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertFolderByTemplate(Long projectId) { + // 创建顶级目录 + String prefix = HseKnowledgeDocumentConstant.getTopFolderPrefix(projectId); + String topPath = prefix + HseKnowledgeDocumentConstant.TOP_FOLDER_NAME; + HseKnowledgeDocument topFolder = new HseKnowledgeDocument(); + topFolder.setProjectId(projectId); + topFolder.setPid(0L); + topFolder.setFileName(HseKnowledgeDocumentConstant.TOP_FOLDER_NAME); + topFolder.setFilePath(topPath); + topFolder.setFileType(DocumentTypeEnum.FOLDER.getValue()); + boolean save = this.save(topFolder); + if (!save) { + throw new ServiceException("新增顶级目录失败,数据库异常", HttpStatus.ERROR); + } + // 创建二级目录 + Long pid = topFolder.getId(); + List documents = HseKnowledgeDocumentConstant.SECOND_LEVEL_FOLDER_NAME.stream().map(name -> { + HseKnowledgeDocument folder = new HseKnowledgeDocument(); + String path = topPath + "/" + name; + folder.setProjectId(projectId); + folder.setPid(pid); + folder.setFileName(name); + folder.setFilePath(path); + folder.setFileType(DocumentTypeEnum.FOLDER.getValue()); + return folder; + }).toList(); + return this.saveBatch(documents); + } + + /** + * 修改安全知识库文件 + * + * @param req 安全知识库 + * @return 是否修改成功 + */ + @Override + public Boolean updateFile(HseKnowledgeDocumentFileUpdateReq req) { + Long id = req.getId(); + HseKnowledgeDocument oldDocument = this.getById(id); + if (oldDocument == null) { + throw new ServiceException("修改安全知识库文件失败,数据不存在", HttpStatus.NOT_FOUND); + } + HseKnowledgeDocument document = new HseKnowledgeDocument(); + BeanUtils.copyProperties(req, document); + boolean result = this.updateById(document); + if (!result) { + throw new ServiceException("修改安全知识库文件失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 删除安全知识库文件信息 + * + * @param id 待删除文件的主键 + * @return 是否删除成功 + */ + @Override + public Boolean deleteFileById(Long id) { + HseKnowledgeDocument document = this.getById(id); + if (document == null) { + throw new ServiceException("文件不存在", HttpStatus.ERROR); + } + if (!document.getFileStatus().equals(DocumentStatusEnum.NORMAL.getValue())) { + throw new ServiceException("文件已删除", HttpStatus.ERROR); + } + if (document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) { + throw new ServiceException("文件夹不能删除", HttpStatus.ERROR); + } + HseKnowledgeDocument deleteDocument = new HseKnowledgeDocument(); + deleteDocument.setId(document.getId()); + deleteDocument.setDeletedAt(new Date()); + deleteDocument.setFileStatus(DocumentStatusEnum.DELETE.getValue()); + return this.updateById(deleteDocument); + } + + /** + * 批量删除安全知识库回收站文件信息 + * + * @param ids 待删除文件主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteRecycleBinFileBatchByIds(Collection ids) { + Long userId = LoginHelper.getUserId(); + List documentList = this.listByIds(ids); + if (CollUtil.isEmpty(documentList)) { + throw new ServiceException("文件不存在", HttpStatus.ERROR); + } + Set projectIdList = documentList.stream().map(HseKnowledgeDocument::getProjectId).collect(Collectors.toSet()); + projectService.validAuth(projectIdList, userId); + boolean result = this.removeBatchByIds(ids); + if (!result) { + throw new ServiceException("文件删除失败", HttpStatus.ERROR); + } + // 删除oss文件 + OssClient storage = OssFactory.instance(); + for (HseKnowledgeDocument document : documentList) { + if (!document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) { + storage.delete(document.getFileUrl()); + } + } + return true; + } + + /** + * 批量恢复安全会议纪要信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean recoveryBatchById(Collection ids) { + List allParentIdsRecursively = getAllParentIdsRecursively(ids); + // 需要更新状态的文件集合 + allParentIdsRecursively.addAll(ids); + List updateList = allParentIdsRecursively.stream().map(id -> { + HseKnowledgeDocument documentSafetyMeeting = new HseKnowledgeDocument(); + documentSafetyMeeting.setId(id); + documentSafetyMeeting.setFileStatus(DocumentStatusEnum.NORMAL.getValue()); + return documentSafetyMeeting; + }).toList(); + boolean result = this.updateBatchById(updateList); + if (!result) { + throw new ServiceException("恢复文件失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param documentList 文档列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildTreeSelect(List documentList) { + if (CollUtil.isEmpty(documentList)) { + return CollUtil.newArrayList(); + } + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (HseKnowledgeDocument d : documentList) { + Long parentId = d.getPid(); + HseKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId)); + if (ObjectUtil.isNull(document)) { + List> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) -> + tree.setId(knowledgeDocument.getId()) + .setParentId(knowledgeDocument.getPid()) + .setName(knowledgeDocument.getFileName())); + Tree tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId())); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 构建文档封装对象 + * + * @param document 文档 + * @return 文档封装对象 + */ + @Override + public HseKnowledgeDocumentVo getVo(HseKnowledgeDocument document) { + HseKnowledgeDocumentVo vo = new HseKnowledgeDocumentVo(); + if (document == null) { + return vo; + } + BeanUtils.copyProperties(document, vo); + return vo; + } + + /** + * 获取文档对象视图 + * + * @param documentPage 文档对象 + * @return 文档对象视图 + */ + @Override + public Page getVoPage(Page documentPage) { + List documentList = documentPage.getRecords(); + Page documentVoPage = new Page<>( + documentPage.getCurrent(), + documentPage.getSize(), + documentPage.getTotal()); + if (CollUtil.isEmpty(documentList)) { + return documentVoPage; + } + List documentVoList = documentList.stream().map(entity -> { + HseKnowledgeDocumentVo documentVo = new HseKnowledgeDocumentVo(); + BeanUtils.copyProperties(entity, documentVo); + return documentVo; + }).toList(); + documentVoPage.setRecords(documentVoList); + return documentVoPage; + } + + /** + * 畅写在线文件修改 + * + * @param request 请求 + * @param response 响应 + */ + @Override + public void singleFileUploads(Long id, HttpServletRequest request, HttpServletResponse response) { + try { + PrintWriter writer = response.getWriter(); + Scanner scanner = new Scanner(request.getInputStream(), "GBK").useDelimiter("\\A"); + String body = scanner.hasNext() ? scanner.next() : ""; + JSONObject jsonObj = JSONUtil.parseObj(body); + if (jsonObj.getInt("status") == 2 || jsonObj.getInt("status") == 6) { + String downloadUri = (String) jsonObj.get("url"); + HseKnowledgeDocument document = this.getById(id); + String filePath = document.getFilePath(); + ossService.uploadFileUrlWithNoSave(downloadUri, filePath); + } else if (jsonObj.getInt("status") == 3 || jsonObj.getInt("status") == 7) { + writer.write("{\"error\":-1}"); + } + writer.write("{\"error\":0}"); + } catch (IOException e) { + throw new ServiceException("安全知识库在线修改文件失败," + e); + } + } + + /** + * 校验父级目录是否存在 + * + * @param knowledgeDocument 父级目录 + * @param projectId 当前项目id + */ + private void validParentFolder(HseKnowledgeDocument knowledgeDocument, Long projectId) { + // 判断父级目录是否存在 + if (knowledgeDocument == null) { + throw new ServiceException("父级目录不存在", HttpStatus.NOT_FOUND); + } + // 判断父级目录是否是文件夹 + if (!DocumentTypeEnum.FOLDER.getValue().equals(knowledgeDocument.getFileType())) { + throw new ServiceException("父级目录不是文件夹", HttpStatus.BAD_REQUEST); + } + // 判断是否为同一个项目 + if (!knowledgeDocument.getProjectId().equals(projectId)) { + throw new ServiceException("父级目录不属于当前项目", HttpStatus.BAD_REQUEST); + } + } + + /** + * 递归查询所有父级 id + * + * @param ids id 列表 + * @return 父级 id 列表 + */ + private List getAllParentIdsRecursively(Collection ids) { + // 使用 list() 方法批量查询当前 id 列表对应的实体数据 + List fileList = this.lambdaQuery() + .in(HseKnowledgeDocument::getId, ids) + .eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue()) + .list(); + // 通过 stream 流过滤出非 0 的父 id,并去重 + List parentIdList = fileList.stream() + .map(HseKnowledgeDocument::getPid) + .filter(pid -> pid != 0) + .distinct() + .collect(Collectors.toList()); + // 如果父 id 列表为空,说明递归终止,返回空列表 + if (parentIdList.isEmpty()) { + return new ArrayList<>(); + } + // 递归查询父 id 列表对应的上级父 id + List higherParentIds = getAllParentIdsRecursively(parentIdList); + // 将当前层的父 id 和上级递归得到的父 id 合并 + List allParentIds = new ArrayList<>(); + allParentIds.addAll(parentIdList); + allParentIds.addAll(higherParentIds); + // 返回合并后去重的结果 + return allParentIds.stream().distinct().collect(Collectors.toList()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionBankServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionBankServiceImpl.java new file mode 100644 index 0000000..b9b37ed --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionBankServiceImpl.java @@ -0,0 +1,295 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.dto.UserOnlineDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.domain.HseQuestionBank; +import org.dromara.safety.domain.HseQuestionsCategory; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankCreateReq; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankQueryReq; +import org.dromara.safety.domain.dto.questionbank.HseQuestionBankUpdateReq; +import org.dromara.safety.domain.vo.questionbank.HseQuestionBankVo; +import org.dromara.safety.mapper.HseQuestionBankMapper; +import org.dromara.safety.service.IHseQuestionBankService; +import org.dromara.safety.service.IHseQuestionsCategoryService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 题库Service业务层处理 + * + * @author lilemy + * @date 2025-03-24 + */ +@Service +public class HseQuestionBankServiceImpl extends ServiceImpl + implements IHseQuestionBankService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IHseQuestionsCategoryService questionsCategoryService; + + /** + * 查询题库 + * + * @param id 主键 + * @return 题库 + */ + @Override + public HseQuestionBankVo queryById(Long id) { + HseQuestionBank questionBank = this.getById(id); + if (questionBank == null) { + throw new ServiceException("题库信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(questionBank); + } + + /** + * 分页查询题库列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 题库分页列表 + */ + @Override + public TableDataInfo queryPageList(HseQuestionBankQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的题库列表 + * + * @param req 查询条件 + * @return 题库列表 + */ + @Override + public List queryList(HseQuestionBankQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增题库 + * + * @param req 题库 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(HseQuestionBankCreateReq req, HttpServletRequest request) { + // 将实体类和 DTO 进行转换 + HseQuestionBank questionBank = new HseQuestionBank(); + BeanUtils.copyProperties(req, questionBank); + // 获取当前登录设备 + String token = request.getHeader("authorization"); + UserOnlineDTO userOnlineDTO = RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token); + questionBank.setWxOrPc(userOnlineDTO.getDeviceType()); + // 数据校验 + validEntityBeforeSave(questionBank, true); + // 写入数据库 + boolean save = this.save(questionBank); + if (!save) { + throw new ServiceException("新增题库失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return questionBank.getId(); + } + + /** + * 修改题库 + * + * @param req 题库 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseQuestionBankUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseQuestionBank questionBank = new HseQuestionBank(); + BeanUtils.copyProperties(req, questionBank); + // 数据校验 + validEntityBeforeSave(questionBank, false); + // 判断是否存在 + HseQuestionBank oldQuestionBank = this.getById(questionBank.getId()); + if (oldQuestionBank == null) { + throw new ServiceException("修改题库失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(questionBank); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseQuestionBank entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long categoryId = entity.getCategoryId(); + String questionType = entity.getQuestionType(); + String questionContent = entity.getQuestionContent(); + Long projectId = entity.getProjectId(); + if (create) { + if (categoryId == null) { + throw new ServiceException("分类类型不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(questionType)) { + throw new ServiceException("题目类型不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(questionContent)) { + throw new ServiceException("题目内容不能为空", HttpStatus.BAD_REQUEST); + } + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.NOT_FOUND); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (categoryId != null && questionsCategoryService.getById(categoryId) == null) { + throw new ServiceException("对应题目分类类型不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除题库信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List questionBankList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = questionBankList.stream().map(HseQuestionBank::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取题库视图对象 + * + * @param questionBank 题库对象 + * @return 题库视图对象 + */ + @Override + public HseQuestionBankVo getVo(HseQuestionBank questionBank) { + // 对象转封装类 + HseQuestionBankVo questionBankVo = new HseQuestionBankVo(); + if (questionBank == null) { + return questionBankVo; + } + BeanUtils.copyProperties(questionBank, questionBankVo); + // 获取题目分类名称 + Long categoryId = questionBank.getCategoryId(); + HseQuestionsCategory category = questionsCategoryService.getById(categoryId); + if (category != null) { + questionBankVo.setCategoryName(category.getCategoryName()); + } + return questionBankVo; + } + + /** + * 获取题库查询条件封装 + * + * @param req 题库查询条件 + * @return 题库查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseQuestionBankQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + Long categoryId = req.getCategoryId(); + String questionType = req.getQuestionType(); + String questionContent = req.getQuestionContent(); + List optionList = req.getOptionList(); + String correctAnswer = req.getCorrectAnswer(); + // JSON 数组查询 + if (CollUtil.isNotEmpty(optionList)) { + for (String option : optionList) { + lqw.like(HseQuestionBank::getOptions, "\"" + option + "\""); + } + } + // 模糊查询 + lqw.like(StringUtils.isNotBlank(questionContent), HseQuestionBank::getQuestionContent, questionContent); + lqw.like(StringUtils.isNotBlank(correctAnswer), HseQuestionBank::getCorrectAnswer, correctAnswer); + // 精准查询 + lqw.eq(ObjectUtils.isNotEmpty(id), HseQuestionBank::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseQuestionBank::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(categoryId), HseQuestionBank::getCategoryId, categoryId); + lqw.eq(StringUtils.isNotBlank(questionType), HseQuestionBank::getQuestionType, questionType); + return lqw; + } + + /** + * 获取题库分页对象视图 + * + * @param questionBankPage 题库分页对象 + * @return 题库分页对象视图 + */ + @Override + public Page getVoPage(Page questionBankPage) { + // 获取分页数据 + List questionBankList = questionBankPage.getRecords(); + // 添加分页信息 + Page questionBankVoPage = new Page<>( + questionBankPage.getCurrent(), + questionBankPage.getSize(), + questionBankPage.getTotal() + ); + if (CollUtil.isEmpty(questionBankList)) { + return questionBankVoPage; + } + // 关联查询题目分类信息 + Set categoryIdList = questionBankList.stream().map(HseQuestionBank::getCategoryId) + .collect(Collectors.toSet()); + Map> questionCategoryMap = questionsCategoryService.listByIds(categoryIdList) + .stream().collect(Collectors.groupingBy(HseQuestionsCategory::getId)); + // 对象列表 => 封装对象列表 + List questionBankVoList = questionBankList.stream().map(questionBank -> { + HseQuestionBankVo questionBankVo = new HseQuestionBankVo(); + BeanUtils.copyProperties(questionBank, questionBankVo); + // 获取题目分类名称 + Long categoryId = questionBank.getCategoryId(); + String categoryName = null; + if (questionCategoryMap.containsKey(categoryId)) { + HseQuestionsCategory category = questionCategoryMap.get(categoryId).get(0); + categoryName = category.getCategoryName(); + } + questionBankVo.setCategoryName(categoryName); + // 返回封装对象 + return questionBankVo; + }).toList(); + questionBankVoPage.setRecords(questionBankVoList); + return questionBankVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionUserAnswerServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionUserAnswerServiceImpl.java new file mode 100644 index 0000000..d5fa7d4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionUserAnswerServiceImpl.java @@ -0,0 +1,590 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.ZipUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.exception.OssException; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.project.domain.BusProjectTeamMember; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusProjectTeamMemberService; +import org.dromara.safety.domain.HseQuestionUserAnswer; +import org.dromara.safety.domain.enums.HseSafetyExamTypeEnum; +import org.dromara.safety.domain.dto.questionuseranswer.*; +import org.dromara.safety.domain.vo.questionuseranswer.HseQuestionUserAnswerVo; +import org.dromara.safety.mapper.HseQuestionUserAnswerMapper; +import org.dromara.safety.service.IHseQuestionUserAnswerService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 用户试卷存储Service业务层处理 + * + * @author lilemy + * @date 2025-03-24 + */ +@Slf4j +@Service +public class HseQuestionUserAnswerServiceImpl extends ServiceImpl + implements IHseQuestionUserAnswerService { + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysOssService ossService; + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private IBusProjectTeamMemberService projectTeamMemberService; + + /** + * 查询用户试卷存储 + * + * @param id 主键 + * @return 用户试卷存储 + */ + @Override + public HseQuestionUserAnswerVo queryById(Long id) { + HseQuestionUserAnswer questionUserAnswer = this.getById(id); + if (questionUserAnswer == null) { + throw new ServiceException("用户试卷存储信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(questionUserAnswer); + } + + /** + * 分页查询用户试卷存储列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 用户试卷存储分页列表 + */ + @Override + public TableDataInfo queryPageList(HseQuestionUserAnswerQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的用户试卷存储列表 + * + * @param req 查询条件 + * @return 用户试卷存储列表 + */ + @Override + public List queryList(HseQuestionUserAnswerQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增用户试卷存储 + * + * @param req 用户试卷存储 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(HseQuestionUserAnswerCreateReq req) { + // 将实体类和 DTO 进行转换 + HseQuestionUserAnswer questionUserAnswer = new HseQuestionUserAnswer(); + BeanUtils.copyProperties(req, questionUserAnswer); + List bankIdList = req.getBankIdList(); + if (CollUtil.isNotEmpty(bankIdList)) { + String bankIdStr = JSONUtil.toJsonStr(bankIdList); + questionUserAnswer.setBankId(bankIdStr); + } + List answerList = req.getAnswerList(); + if (CollUtil.isNotEmpty(answerList)) { + String answerStr = JSONUtil.toJsonStr(answerList); + questionUserAnswer.setAnswer(answerStr); + } + // 数据校验 + validEntityBeforeSave(questionUserAnswer, true); + // 写入数据库 + boolean save = this.save(questionUserAnswer); + if (!save) { + throw new ServiceException("新增用户试卷存储失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return questionUserAnswer.getId(); + } + + /** + * 通过zip文件批量上传用户试卷存储 + * + * @param multipartFile zip文件 + * @return 是否上传成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean batchUploadFileByZip(MultipartFile multipartFile, Long projectId) { + // 1. 校验 + String originalFilename = multipartFile.getOriginalFilename(); + if (originalFilename == null) { + throw new ServiceException("文件名不存在", HttpStatus.BAD_REQUEST); + } + // 校验是否为压缩包zip格式 + String suffix = FileUtil.getSuffix(originalFilename); + if (!suffix.equals("zip")) { + throw new ServiceException("请上传zip格式的压缩文件", HttpStatus.BAD_REQUEST); + } + // 2. 临时存储文件路径 + // 2.1 压缩包临时文件路径 + File tempZipFile = null; + String randomStr = RandomUtil.randomString(16); + String tempZipFilePath = randomStr + "-" + originalFilename; + // 2.2 解压后的文件夹路径 + File destDir = null; + String basePath = "unzip_path"; + String destDirPath = String.format("%s/%s/%s/%s", basePath, DateUtils.getDate(), projectId, randomStr); + // 3. 构建临时存储对象 + List tempList = new ArrayList<>(); + try { + // 4. 创建临时文件 + tempZipFile = File.createTempFile(tempZipFilePath, null); + multipartFile.transferTo(tempZipFile); + // 5. 解压 zip + destDir = new File(destDirPath); + ZipUtil.unzip(tempZipFile, destDir); + // 4. 遍历最外层文件夹 + File[] userFolders = destDir.listFiles(); + if (userFolders != null) { + for (File userFolder : userFolders) { + if (userFolder.isDirectory()) { + // 5. 获取文件名,格式为 姓名-身份证-满分-得分-及格分,例如 小明-500106200101011234-100-61-60 + String userFolderName = userFolder.getName(); + String[] userParts = userFolderName.split("-"); + // 6. 继续遍历获取每个用户子文件夹里的文件 + File[] docFolders = userFolder.listFiles(); + String fileIdStr = null; + if (docFolders != null) { + // 6.1 遍历文件 + List fileIdList = new ArrayList<>(); + for (File docFolder : docFolders) { + if (docFolder.isFile()) { + // 6.2 上传文件 + SysOssVo upload = ossService.upload(docFolder); + if (upload != null) { + fileIdList.add(upload.getOssId()); + } + } + } + // 6.3 跳过空文件 + if (fileIdList.isEmpty()) { + continue; + } + fileIdStr = fileIdList.stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); + } + // 7. 创建临时对象 + HseQuestionUserAnswerUploadTemp temp = new HseQuestionUserAnswerUploadTemp(); + temp.setProjectId(projectId); + temp.setUserName(userParts[0]); + temp.setUserIdCard(userParts[1]); + temp.setFullScore(Long.parseLong(userParts[2])); + temp.setScore(Long.parseLong(userParts[3])); + temp.setPassScore(Long.parseLong(userParts[4])); + temp.setFile(fileIdStr); + tempList.add(temp); + } + } + } + } catch (Exception e) { + throw new ServiceException("文件上传失败", HttpStatus.ERROR); + } finally { + if (tempZipFile != null) { + // 删除临时文件 + boolean delete = tempZipFile.delete(); + if (!delete) { + log.error("临时文件删除失败,路径:{}", tempZipFilePath); + } + } + if (destDir != null) { + Path dirPath = Paths.get(basePath); + try { + FileUtils.deleteDirectory(dirPath); + } catch (IOException e) { + log.error("解压文件删除失败,路径:{}", destDirPath, e); + } + } + } + // 8. 遍历临时对象,进行存储 + if (CollUtil.isEmpty(tempList)) { + return true; + } + // 8.1 获取用户身份证列表 + Set idCardList = tempList.stream().map(HseQuestionUserAnswerUploadTemp::getUserIdCard) + .collect(Collectors.toSet()); + // 8.2 根据用户身份证列表查询用户信息 + Map> userIdMap = constructionUserService.lambdaQuery() + .in(SubConstructionUser::getSfzNumber, idCardList).list() + .stream().collect(Collectors.groupingBy(SubConstructionUser::getSfzNumber)); + // 8.3 遍历临时对象,构造用户试卷存储对象 + List questionUserAnswerList = tempList.stream().map(temp -> { + HseQuestionUserAnswer questionUserAnswer = new HseQuestionUserAnswer(); + // 8.4 获取对应用户id + String userIdCard = temp.getUserIdCard(); + Long userId = null; + if (userIdMap.containsKey(userIdCard)) { + SubConstructionUser constructionUser = userIdMap.get(userIdCard).get(0); + userId = constructionUser.getId(); + } + // 8.5 判断用户是否存在 + if (userId == null) { + String userName = temp.getUserName(); + String message = String.format("用户[%s:%s]不存在", userName, userIdCard); + throw new ServiceException(message, HttpStatus.NOT_FOUND); + } + questionUserAnswer.setUserId(userId); + // 8.6 设置其他属性 + questionUserAnswer.setProjectId(temp.getProjectId()); + questionUserAnswer.setScore(temp.getScore()); + String pass = String.format("%s,%s", temp.getPassScore(), temp.getFullScore()); + questionUserAnswer.setPass(pass); + questionUserAnswer.setFile(temp.getFile()); + questionUserAnswer.setExamType(HseSafetyExamTypeEnum.OFFLINE.getValue()); + return questionUserAnswer; + }).toList(); + // 9. 保存 + boolean result = this.saveBatch(questionUserAnswerList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 修改用户试卷存储 + * + * @param req 用户试卷存储 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseQuestionUserAnswerUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseQuestionUserAnswer questionUserAnswer = new HseQuestionUserAnswer(); + BeanUtils.copyProperties(req, questionUserAnswer); + List bankIdList = req.getBankIdList(); + if (CollUtil.isNotEmpty(bankIdList)) { + String bankIdStr = JSONUtil.toJsonStr(bankIdList); + questionUserAnswer.setBankId(bankIdStr); + } + List answerList = req.getAnswerList(); + if (CollUtil.isNotEmpty(answerList)) { + String answerStr = JSONUtil.toJsonStr(answerList); + questionUserAnswer.setAnswer(answerStr); + } + // 数据校验 + validEntityBeforeSave(questionUserAnswer, false); + // 判断是否存在 + HseQuestionUserAnswer oldQuestionUserAnswer = this.getById(questionUserAnswer.getId()); + if (oldQuestionUserAnswer == null) { + throw new ServiceException("修改用户试卷存储失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(questionUserAnswer); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseQuestionUserAnswer entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除用户试卷存储信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List questionUserAnswerList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = questionUserAnswerList.stream().map(HseQuestionUserAnswer::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取用户试卷存储视图对象 + * + * @param questionUserAnswer 用户试卷存储对象 + * @return 用户试卷存储视图对象 + */ + @Override + public HseQuestionUserAnswerVo getVo(HseQuestionUserAnswer questionUserAnswer) { + // 对象转封装类 + HseQuestionUserAnswerVo questionUserAnswerVo = new HseQuestionUserAnswerVo(); + if (questionUserAnswer == null) { + return questionUserAnswerVo; + } + BeanUtils.copyProperties(questionUserAnswer, questionUserAnswerVo); + // 获取用户试卷题库列表 + String bankId = questionUserAnswer.getBankId(); + if (StringUtils.isNotBlank(bankId)) { + questionUserAnswerVo.setBankIdList(JSONUtil.toList(bankId, Long.class)); + } + // 获取用户试卷答案列表 + String answer = questionUserAnswer.getAnswer(); + if (StringUtils.isNotBlank(answer)) { + questionUserAnswerVo.setAnswerList(JSONUtil.toList(answer, String.class)); + } + // 获取用户姓名 + Long userId = questionUserAnswer.getUserId(); + if (userId != null) { + SubConstructionUser constructionUser = constructionUserService.getById(userId); + questionUserAnswerVo.setUserName(constructionUser.getUserName()); + } + // 获取用户试卷文件地址 + String file = questionUserAnswer.getFile(); + if (StringUtils.isNotBlank(file)) { + List fileIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList(); + List fileUrlList = ossService.listByIds(fileIdList).stream().map(SysOssVo::getUrl).toList(); + questionUserAnswerVo.setFileUrl(fileUrlList); + } + return questionUserAnswerVo; + } + + /** + * 获取用户试卷存储查询条件封装 + * + * @param req 用户试卷存储查询条件 + * @return 用户试卷存储查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseQuestionUserAnswerQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String userName = req.getUserName(); + Long teamId = req.getTeamId(); + // 联表查询 + if (StringUtils.isNotBlank(userName)) { + List constructionUserList = constructionUserService.lambdaQuery() + .select(SubConstructionUser::getId) + .like(SubConstructionUser::getUserName, userName) + .list(); + if (CollUtil.isNotEmpty(constructionUserList)) { + List userIdList = constructionUserList.stream().map(SubConstructionUser::getId).toList(); + lqw.in(HseQuestionUserAnswer::getUserId, userIdList); + } else { + lqw.eq(HseQuestionUserAnswer::getUserId, null); + } + } + if (ObjectUtils.isNotEmpty(teamId)) { + List projectTeamMemberList = projectTeamMemberService.lambdaQuery() + .select(BusProjectTeamMember::getMemberId) + .eq(BusProjectTeamMember::getTeamId, teamId) + .list(); + if (CollUtil.isNotEmpty(projectTeamMemberList)) { + List userIdList = projectTeamMemberList.stream().map(BusProjectTeamMember::getMemberId).toList(); + lqw.in(HseQuestionUserAnswer::getUserId, userIdList); + } else { + lqw.eq(HseQuestionUserAnswer::getUserId, null); + } + } + // 精准查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseQuestionUserAnswer::getProjectId, projectId); + return lqw; + } + + /** + * 获取用户试卷存储分页对象视图 + * + * @param questionUserAnswerPage 用户试卷存储分页对象 + * @return 用户试卷存储分页对象视图 + */ + @Override + public Page getVoPage(Page questionUserAnswerPage) { + // 获取分页数据 + List questionUserAnswerList = questionUserAnswerPage.getRecords(); + // 添加分页信息 + Page questionUserAnswerVoPage = new Page<>( + questionUserAnswerPage.getCurrent(), + questionUserAnswerPage.getSize(), + questionUserAnswerPage.getTotal() + ); + if (CollUtil.isEmpty(questionUserAnswerList)) { + return questionUserAnswerVoPage; + } + // 获取用户名 + Set userIdList = questionUserAnswerList.stream().map(HseQuestionUserAnswer::getUserId).collect(Collectors.toSet()); + List constructionUserList = constructionUserService.lambdaQuery() + .select(SubConstructionUser::getId, SubConstructionUser::getUserName) + .in(SubConstructionUser::getId, userIdList) + .list(); + Map userNameMap = constructionUserList.stream() + .collect(Collectors.toMap(SubConstructionUser::getId, SubConstructionUser::getUserName)); + // 获取用户文件 + Set fileIdList = questionUserAnswerList.stream().map(HseQuestionUserAnswer::getFile).filter(StringUtils::isNotBlank) + .flatMap(fileId -> Arrays.stream(fileId.split(",")).map(Long::parseLong)).collect(Collectors.toSet()); + Map> ossMap = ossService.listByIds(fileIdList) + .stream().collect(Collectors.groupingBy(SysOssVo::getOssId)); + // 对象列表 => 封装对象列表 + List questionUserAnswerVoList = questionUserAnswerList.stream().map(questionUserAnswer -> { + HseQuestionUserAnswerVo questionUserAnswerVo = new HseQuestionUserAnswerVo(); + BeanUtils.copyProperties(questionUserAnswer, questionUserAnswerVo); + // 获取获取用户名 + Long userId = questionUserAnswer.getUserId(); + if (userId != null) { + questionUserAnswerVo.setUserName(userNameMap.get(userId)); + } + // 获取用户文件 + String file = questionUserAnswer.getFile(); + if (StringUtils.isNotBlank(file)) { + List ossIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList(); + List fileUrlList = ossIdList.stream().map(ossId -> { + String url = ""; + if (ossMap.containsKey(ossId)) { + url = ossMap.get(ossId).get(0).getUrl(); + } + return url; + }).toList(); + questionUserAnswerVo.setFileUrl(fileUrlList); + } + // 获取用户试卷题库列表 + String bankId = questionUserAnswer.getBankId(); + if (StringUtils.isNotBlank(bankId)) { + questionUserAnswerVo.setBankIdList(JSONUtil.toList(bankId, Long.class)); + } + // 获取用户试卷答案列表 + String answer = questionUserAnswer.getAnswer(); + if (StringUtils.isNotBlank(answer)) { + questionUserAnswerVo.setAnswerList(JSONUtil.toList(answer, String.class)); + } + return questionUserAnswerVo; + }).toList(); + questionUserAnswerVoPage.setRecords(questionUserAnswerVoList); + return questionUserAnswerVoPage; + } + + /** + * 批量下载用户试卷存储文件 + * + * @param req 用户试卷存储文件下载请求 + * @param response 设置响应头和向客户端发送文件内容 + */ + @Override + public void batchDownloadFile(HseQuestionUserAnswerBatchDownloadFileReq req, HttpServletResponse response) { + // 获取用户试卷存储文件 + List idList = req.getIdList(); + if (CollUtil.isEmpty(idList)) { + return; + } + List questionUserAnswerList = lambdaQuery() + .in(HseQuestionUserAnswer::getId, idList) + .list(); + if (CollUtil.isEmpty(questionUserAnswerList)) { + return; + } + // 查询对应施工人员信息 + Set userIdSet = questionUserAnswerList.stream().map(HseQuestionUserAnswer::getUserId).collect(Collectors.toSet()); + Map> userMap = constructionUserService.lambdaQuery() + .select(SubConstructionUser::getId, SubConstructionUser::getUserName) + .in(SubConstructionUser::getId, userIdSet).list() + .stream().collect(Collectors.groupingBy(SubConstructionUser::getId)); + if (CollUtil.isEmpty(userMap)) { + return; + } + // 设置响应头 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + // 遍历所有用户文件 + for (HseQuestionUserAnswer questionUserAnswer : questionUserAnswerList) { + String file = questionUserAnswer.getFile(); + if (StringUtils.isBlank(file)) { + continue; + } + Long userId = questionUserAnswer.getUserId(); + SubConstructionUser constructionUser = userMap.get(userId).get(0); + String userFolder = constructionUser.getUserName() + "-" + constructionUser.getId() + "/"; + // 写入个人文件夹条目 + zos.putNextEntry(new ZipEntry(userFolder)); + zos.closeEntry(); + List ossIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + // 遍历用户文件 + for (SysOssVo ossVo : ossVoList) { + // 获取文件输入流 + OssClient storage = OssFactory.instance(ossVo.getService()); + String path = ossVo.getUrl(); + try (InputStream is = storage.getObjectContent(path)) { + // 从路径中提取文件名(可以根据业务规则调整) + String fileName = userFolder + "/" + ossVo.getOriginalName(); + zos.putNextEntry(new ZipEntry(fileName)); + byte[] buffer = new byte[4096]; + int len; + while ((len = is.read(buffer)) != -1) { + zos.write(buffer, 0, len); + } + zos.closeEntry(); + } catch (IOException e) { + // 针对单个文件处理异常,可以选择记录日志或终止处理 + throw new OssException("处理文件[" + path + "]失败,错误信息: " + e.getMessage()); + } + } + } + zos.finish(); + } catch (IOException e) { + throw new OssException("生成ZIP文件失败,错误信息: " + e.getMessage()); + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionsCategoryServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionsCategoryServiceImpl.java new file mode 100644 index 0000000..6cbc93a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionsCategoryServiceImpl.java @@ -0,0 +1,225 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.domain.HseQuestionsCategory; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryCreateReq; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryQueryReq; +import org.dromara.safety.domain.dto.questionscategory.HseQuestionsCategoryUpdateReq; +import org.dromara.safety.domain.vo.questionscategory.HseQuestionsCategoryVo; +import org.dromara.safety.mapper.HseQuestionsCategoryMapper; +import org.dromara.safety.service.IHseQuestionsCategoryService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 题库类别Service业务层处理 + * + * @author lilemy + * @date 2025-04-15 + */ +@Service +public class HseQuestionsCategoryServiceImpl extends ServiceImpl + implements IHseQuestionsCategoryService { + + @Resource + private IBusProjectService projectService; + + /** + * 查询题库类别 + * + * @param id 主键 + * @return 题库类别 + */ + @Override + public HseQuestionsCategoryVo queryById(Long id) { + HseQuestionsCategory questionsCategory = this.getById(id); + if (questionsCategory == null) { + throw new ServiceException("题库类别信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(questionsCategory); + } + + /** + * 分页查询题库类别列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 题库类别分页列表 + */ + @Override + public TableDataInfo queryPageList(HseQuestionsCategoryQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的题库类别列表 + * + * @param req 查询条件 + * @return 题库类别列表 + */ + @Override + public List queryList(HseQuestionsCategoryQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增题库类别 + * + * @param req 题库类别 + * @return 新增题库类别主键 + */ + @Override + public Long insertByBo(HseQuestionsCategoryCreateReq req) { + // 将实体类和 DTO 进行转换 + HseQuestionsCategory questionsCategory = new HseQuestionsCategory(); + BeanUtils.copyProperties(req, questionsCategory); + // 数据校验 + validEntityBeforeSave(questionsCategory, true); + // 写入数据库 + boolean save = this.save(questionsCategory); + if (!save) { + throw new ServiceException("新增题库类别失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return questionsCategory.getId(); + } + + /** + * 修改题库类别 + * + * @param req 题库类别 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseQuestionsCategoryUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseQuestionsCategory questionsCategory = new HseQuestionsCategory(); + BeanUtils.copyProperties(req, questionsCategory); + // 数据校验 + validEntityBeforeSave(questionsCategory, false); + // 判断是否存在 + HseQuestionsCategory oldQuestionsCategory = this.getById(questionsCategory.getId()); + if (oldQuestionsCategory == null) { + throw new ServiceException("修改题库类别失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(questionsCategory); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseQuestionsCategory entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除题库类别信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List questionsCategoryList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = questionsCategoryList.stream().map(HseQuestionsCategory::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取题库类别视图对象 + * + * @param questionsCategory 题库类别对象 + * @return 题库类别视图对象 + */ + @Override + public HseQuestionsCategoryVo getVo(HseQuestionsCategory questionsCategory) { + // 对象转封装类 + HseQuestionsCategoryVo questionsCategoryVo = new HseQuestionsCategoryVo(); + if (questionsCategory == null) { + return questionsCategoryVo; + } + BeanUtils.copyProperties(questionsCategory, questionsCategoryVo); + return questionsCategoryVo; + } + + /** + * 获取题库类别查询条件封装 + * + * @param req 题库类别查询条件 + * @return 题库类别查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseQuestionsCategoryQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long projectId = req.getProjectId(); + String categoryName = req.getCategoryName(); + // 模糊查询 + lqw.like(StringUtils.isNotBlank(categoryName), HseQuestionsCategory::getCategoryName, categoryName); + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseQuestionsCategory::getProjectId, projectId); + return lqw; + } + + /** + * 获取题库类别分页对象视图 + * + * @param questionsCategoryPage 题库类别分页对象 + * @return 题库类别分页对象视图 + */ + @Override + public Page getVoPage(Page questionsCategoryPage) { + // 获取分页数据 + List questionsCategoryList = questionsCategoryPage.getRecords(); + // 添加分页信息 + Page questionsCategoryVoPage = new Page<>( + questionsCategoryPage.getCurrent(), + questionsCategoryPage.getSize(), + questionsCategoryPage.getTotal() + ); + if (CollUtil.isEmpty(questionsCategoryList)) { + return questionsCategoryVoPage; + } + // 对象列表 => 封装对象列表 + List questionsCategoryVoList = questionsCategoryList.stream().map(this::getVo).toList(); + questionsCategoryVoPage.setRecords(questionsCategoryVoList); + return questionsCategoryVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionsConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionsConfigServiceImpl.java new file mode 100644 index 0000000..d8e1891 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseQuestionsConfigServiceImpl.java @@ -0,0 +1,241 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.domain.HseQuestionsConfig; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigCreateReq; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigQueryReq; +import org.dromara.safety.domain.dto.questionsconfig.HseQuestionsConfigUpdateReq; +import org.dromara.safety.domain.vo.questionsconfig.HseQuestionsConfigVo; +import org.dromara.safety.mapper.HseQuestionsConfigMapper; +import org.dromara.safety.service.IHseQuestionsConfigService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 题库配置Service业务层处理 + * + * @author lilemy + * @date 2025-03-24 + */ +@Service +public class HseQuestionsConfigServiceImpl extends ServiceImpl + implements IHseQuestionsConfigService { + + @Resource + private IBusProjectService projectService; + + /** + * 查询题库配置 + * + * @param id 主键 + * @return 题库配置 + */ + @Override + public HseQuestionsConfigVo queryById(Long id) { + HseQuestionsConfig questionsConfig = this.getById(id); + if (questionsConfig == null) { + throw new ServiceException("题库配置信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(questionsConfig); + } + + /** + * 分页查询题库配置列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 题库配置分页列表 + */ + @Override + public TableDataInfo queryPageList(HseQuestionsConfigQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的题库配置列表 + * + * @param req 查询条件 + * @return 题库配置列表 + */ + @Override + public List queryList(HseQuestionsConfigQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增题库配置 + * + * @param req 题库配置 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(HseQuestionsConfigCreateReq req) { + // 将实体类和 DTO 进行转换 + HseQuestionsConfig questionsConfig = new HseQuestionsConfig(); + BeanUtils.copyProperties(req, questionsConfig); + // 数据校验 + validEntityBeforeSave(questionsConfig, true); + // 写入数据库 + boolean save = this.save(questionsConfig); + if (!save) { + throw new ServiceException("新增题库配置失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return questionsConfig.getId(); + } + + /** + * 修改题库配置 + * + * @param req 题库配置 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseQuestionsConfigUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseQuestionsConfig questionsConfig = new HseQuestionsConfig(); + BeanUtils.copyProperties(req, questionsConfig); + // 数据校验 + validEntityBeforeSave(questionsConfig, false); + // 判断是否存在 + HseQuestionsConfig oldQuestionsConfig = this.getById(questionsConfig.getId()); + if (oldQuestionsConfig == null) { + throw new ServiceException("修改题库配置失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(questionsConfig); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseQuestionsConfig entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除题库配置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List questionsConfigList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = questionsConfigList.stream().map(HseQuestionsConfig::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取题库配置视图对象 + * + * @param questionsConfig 题库配置对象 + * @return 题库配置视图对象 + */ + @Override + public HseQuestionsConfigVo getVo(HseQuestionsConfig questionsConfig) { + // 对象转封装类 + HseQuestionsConfigVo questionsConfigVo = new HseQuestionsConfigVo(); + if (questionsConfig == null) { + return questionsConfigVo; + } + BeanUtils.copyProperties(questionsConfig, questionsConfigVo); + return questionsConfigVo; + } + + /** + * 获取题库配置查询条件封装 + * + * @param req 题库配置查询条件 + * @return 题库配置查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseQuestionsConfigQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + Long singleChoice = req.getSingleChoice(); + Long singleScore = req.getSingleScore(); + Long multipleChoice = req.getMultipleChoice(); + Long multipleScore = req.getMultipleScore(); + Long estimate = req.getEstimate(); + Long estimateScore = req.getEstimateScore(); + Long fullMark = req.getFullMark(); + Long passScore = req.getPassScore(); + Long answerTime = req.getAnswerTime(); + // 精准查询 + lqw.eq(ObjectUtils.isNotEmpty(id), HseQuestionsConfig::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseQuestionsConfig::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(singleChoice), HseQuestionsConfig::getSingleChoice, singleChoice); + lqw.eq(ObjectUtils.isNotEmpty(singleScore), HseQuestionsConfig::getSingleScore, singleScore); + lqw.eq(ObjectUtils.isNotEmpty(multipleChoice), HseQuestionsConfig::getMultipleChoice, multipleChoice); + lqw.eq(ObjectUtils.isNotEmpty(multipleScore), HseQuestionsConfig::getMultipleScore, multipleScore); + lqw.eq(ObjectUtils.isNotEmpty(estimate), HseQuestionsConfig::getEstimate, estimate); + lqw.eq(ObjectUtils.isNotEmpty(estimateScore), HseQuestionsConfig::getEstimateScore, estimateScore); + lqw.eq(ObjectUtils.isNotEmpty(fullMark), HseQuestionsConfig::getFullMark, fullMark); + lqw.eq(ObjectUtils.isNotEmpty(passScore), HseQuestionsConfig::getPassScore, passScore); + lqw.eq(ObjectUtils.isNotEmpty(answerTime), HseQuestionsConfig::getAnswerTime, answerTime); + return lqw; + } + + /** + * 获取题库配置分页对象视图 + * + * @param questionsConfigPage 题库配置分页对象 + * @return 题库配置分页对象视图 + */ + @Override + public Page getVoPage(Page questionsConfigPage) { + // 获取分页数据 + List questionsConfigList = questionsConfigPage.getRecords(); + // 添加分页信息 + Page questionsConfigVoPage = new Page<>( + questionsConfigPage.getCurrent(), + questionsConfigPage.getSize(), + questionsConfigPage.getTotal() + ); + if (CollUtil.isEmpty(questionsConfigList)) { + return questionsConfigVoPage; + } + // 对象列表 => 封装对象列表 + List questionsConfigVoList = questionsConfigList.stream().map(this::getVo).toList(); + questionsConfigVoPage.setRecords(questionsConfigVoList); + return questionsConfigVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseRecognizeRecordServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseRecognizeRecordServiceImpl.java new file mode 100644 index 0000000..e848962 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseRecognizeRecordServiceImpl.java @@ -0,0 +1,244 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.manager.recognizermanager.enums.RecognizerTypeEnum; +import org.dromara.manager.recognizermanager.vo.RecognizeTargetVo; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.domain.HseRecognizeRecord; +import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordCreateDto; +import org.dromara.safety.domain.dto.recognizerecord.HseRecognizeRecordQueryReq; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateDto; +import org.dromara.safety.domain.vo.recognizerecord.HseRecognizeRecordVo; +import org.dromara.safety.mapper.HseRecognizeRecordMapper; +import org.dromara.safety.service.IHseRecognizeRecordService; +import org.dromara.safety.service.IHseViolationRecordService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +/** + * 识别记录Service业务层处理 + * + * @author lilemy + * @date 2025-06-24 + */ +@Service +public class HseRecognizeRecordServiceImpl extends ServiceImpl + implements IHseRecognizeRecordService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IHseViolationRecordService violationRecordService; + + /** + * 查询识别记录 + * + * @param id 主键 + * @return 识别记录 + */ + @Override + public HseRecognizeRecordVo queryById(Long id) { + HseRecognizeRecord recognizeRecord = this.getById(id); + if (recognizeRecord == null) { + throw new ServiceException("识别记录信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(recognizeRecord); + } + + /** + * 分页查询识别记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 识别记录分页列表 + */ + @Override + public TableDataInfo queryPageList(HseRecognizeRecordQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的识别记录列表 + * + * @param req 查询条件 + * @return 识别记录列表 + */ + @Override + public List queryList(HseRecognizeRecordQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 创建识别记录(摄像头) + * + * @param recordList 识别记录列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void saveByMonitor(List recordList) { + List entityList = new ArrayList<>(); + for (HseRecognizeRecordCreateDto record : recordList) { + HseRecognizeRecord entity = new HseRecognizeRecord(); + entity.setDeviceSerial(record.getDeviceSerial()); + entity.setDeviceName(record.getDeviceName()); + entity.setRecordCategory(record.getRecordCategory()); + entity.setPicture(record.getPicture()); + entity.setCreateTime(record.getCreateTime()); + Long projectId = record.getProjectId(); + if (projectId == null) { + entity.setRemark("该摄像头暂未分配到项目中"); + } + List targets = record.getTargets(); + List codeList = targets.stream() + .map(RecognizeTargetVo::getType).distinct() + .map(RecognizerTypeEnum::fromValue).filter(Objects::nonNull) + .map(RecognizerTypeEnum::getCode).filter(Objects::nonNull) + .toList(); + String codeStr = String.join(",", codeList); + entity.setViolationType(codeStr); + entity.setNum(targets.size()); + entityList.add(entity); + } + if (CollUtil.isNotEmpty(entityList)) { + boolean result = this.saveBatch(entityList); + if (!result) { + throw new ServiceException("保存识别记录失败"); + } + List violationRecordList = new ArrayList<>(); + for (HseRecognizeRecord entity : entityList) { + HseViolationRecordCreateDto violationRecord = new HseViolationRecordCreateDto(); + if (entity.getProjectId() != null) { + violationRecord.setProjectId(entity.getProjectId()); + violationRecord.setRecognizeId(entity.getId()); + violationRecord.setViolationType(entity.getViolationType()); + violationRecord.setViolationTime(entity.getCreateTime()); + violationRecordList.add(violationRecord); + } + } + if (CollUtil.isNotEmpty(violationRecordList)) { + violationRecordService.insertByMonitor(violationRecordList); + } + } + } + + /** + * 校验并批量删除识别记录信息 + * + * @param id 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + public Boolean deleteById(Long id) { + Long userId = LoginHelper.getUserId(); + HseRecognizeRecord recognizeRecord = this.getById(id); + Long projectId = recognizeRecord.getProjectId(); + projectService.validAuth(projectId, userId); + return this.removeById(id); + } + + /** + * 获取识别记录视图对象 + * + * @param recognizeRecord 识别记录对象 + * @return 识别记录视图对象 + */ + @Override + public HseRecognizeRecordVo getVo(HseRecognizeRecord recognizeRecord) { + HseRecognizeRecordVo recognizeRecordVo = new HseRecognizeRecordVo(); + if (recognizeRecord == null) { + return recognizeRecordVo; + } + BeanUtils.copyProperties(recognizeRecord, recognizeRecordVo); + return recognizeRecordVo; + } + + /** + * 获取识别记录查询条件封装 + * + * @param req 识别记录查询条件 + * @return 识别记录查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseRecognizeRecordQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long projectId = req.getProjectId(); + String recordCategory = req.getRecordCategory(); + String violationType = req.getViolationType(); + String description = req.getDescription(); + Date createTime = req.getCreateTime(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseRecognizeRecord::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(recordCategory), HseRecognizeRecord::getRecordCategory, recordCategory); + if (StringUtils.isNotBlank(violationType)) { + lqw.likeRight(HseRecognizeRecord::getViolationType, violationType + ",") + .or() + .likeLeft(HseRecognizeRecord::getViolationType, "," + violationType) + .or() + .like(HseRecognizeRecord::getViolationType, "," + violationType + ",") + .or() + .eq(HseRecognizeRecord::getViolationType, violationType); + } + lqw.like(StringUtils.isNotBlank(description), HseRecognizeRecord::getDescription, description); + if (createTime != null) { + // 构造当天的起始和结束时间 + LocalDate localDate = createTime.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + LocalDateTime startOfDay = localDate.atStartOfDay(); + LocalDateTime startOfNextDay = localDate.plusDays(1).atStartOfDay(); + Date start = Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()); + Date end = Date.from(startOfNextDay.atZone(ZoneId.systemDefault()).toInstant()); + lqw.ge(HseRecognizeRecord::getCreateTime, start) + .lt(HseRecognizeRecord::getCreateTime, end); + } + return lqw; + } + + /** + * 获取识别记录分页对象视图 + * + * @param recognizeRecordPage 识别记录分页对象 + * @return 识别记录分页对象视图 + */ + @Override + public Page getVoPage(Page recognizeRecordPage) { + List recognizeRecordList = recognizeRecordPage.getRecords(); + Page recognizeRecordVoPage = new Page<>( + recognizeRecordPage.getCurrent(), + recognizeRecordPage.getSize(), + recognizeRecordPage.getTotal()); + if (CollUtil.isEmpty(recognizeRecordList)) { + return recognizeRecordVoPage; + } + List recognizeRecordVoList = recognizeRecordList.stream().map(violationLevel -> { + HseRecognizeRecordVo vo = new HseRecognizeRecordVo(); + BeanUtils.copyProperties(violationLevel, vo); + return vo; + }).toList(); + recognizeRecordVoPage.setRecords(recognizeRecordVoList); + return recognizeRecordVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyInspectionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyInspectionServiceImpl.java new file mode 100644 index 0000000..97b3f3a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyInspectionServiceImpl.java @@ -0,0 +1,571 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.xwpf.usermodel.*; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.exception.OssException; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusProjectTeamService; +import org.dromara.safety.constant.HseSafetyConstant; +import org.dromara.safety.domain.HseSafetyInspection; +import org.dromara.safety.domain.HseTeamMeeting; +import org.dromara.safety.domain.enums.HseSafetyInspectionReviewTypeEnum; +import org.dromara.safety.domain.enums.HseSafetyInspectionStatusEnum; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionCreateReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionGisReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionQueryReq; +import org.dromara.safety.domain.dto.safetyinspection.HseSafetyInspectionUpdateReq; +import org.dromara.safety.domain.vo.safetyinspection.HseSafetyInspectionListGisVo; +import org.dromara.safety.domain.vo.safetyinspection.HseSafetyInspectionVo; +import org.dromara.safety.domain.vo.teammeeting.HseTeamMeetingGis; +import org.dromara.safety.mapper.HseSafetyInspectionMapper; +import org.dromara.safety.service.IHseSafetyInspectionService; +import org.dromara.safety.service.IHseTeamMeetingService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysUserService; +import org.dromara.common.utils.DocumentUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipOutputStream; + +/** + * 安全巡检工单Service业务层处理 + * + * @author lilemy + * @date 2025-03-20 + */ +@Slf4j +@Service +public class HseSafetyInspectionServiceImpl extends ServiceImpl + implements IHseSafetyInspectionService { + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private IBusProjectTeamService projectTeamService; + + @Resource + private IBusProjectService projectService; + + @Resource + private ISysUserService userService; + + @Resource + private ISysDictDataService dictDataService; + + @Resource + private ISysOssService ossService; + + @Resource + private IHseTeamMeetingService teamMeetingService; + + /** + * 查询安全巡检工单 + * + * @param id 主键 + * @return 安全巡检工单 + */ + @Override + public HseSafetyInspectionVo queryById(Long id) { + HseSafetyInspection safetyInspection = this.getById(id); + if (safetyInspection == null) { + throw new ServiceException("安全巡检工单信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(safetyInspection); + } + + /** + * 分页查询安全巡检工单列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全巡检工单分页列表 + */ + @Override + public TableDataInfo queryPageList(HseSafetyInspectionQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的安全巡检工单列表 + * + * @param req 查询条件 + * @return 安全巡检工单列表 + */ + @Override + public List queryList(HseSafetyInspectionQueryReq req) { + List safetyInspection = this.list(this.buildQueryWrapper(req)); + return safetyInspection.stream().map(this::getVo).toList(); + } + + /** + * 查询大屏安全信息 + * + * @param req 查询条件 + * @return 安全信息 + */ + @Override + public HseSafetyInspectionListGisVo queryGisList(HseSafetyInspectionGisReq req) { + Long projectId = req.getProjectId(); + if (projectId == null || projectService.getById(projectId) == null) { + throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); + } + HseSafetyInspectionListGisVo gisVo = new HseSafetyInspectionListGisVo(); + List teamMeetings = teamMeetingService.lambdaQuery() + .eq(HseTeamMeeting::getProjectId, projectId) + .list(); + if (CollUtil.isEmpty(teamMeetings)){ + return gisVo; + } + // 获取最新的班组列表 + List topList = teamMeetings.stream() + .sorted(Comparator.comparing(HseTeamMeeting::getCreateTime).reversed()) + .limit(Optional.ofNullable(req.getPageSize()).orElse(20)) + .toList(); + List teamIds = topList.stream().map(HseTeamMeeting::getTeamId).toList(); + Map> teamMap = projectTeamService.lambdaQuery() + .in(BusProjectTeam::getId, teamIds) + .list().stream().collect(Collectors.groupingBy(BusProjectTeam::getId)); + List gisList = topList.stream().map(teamMeeting -> { + HseTeamMeetingGis gis = new HseTeamMeetingGis(); + BeanUtils.copyProperties(teamMeeting, gis); + gis.setName("站班会"); + if (teamMap.containsKey(teamMeeting.getTeamId())) { + gis.setTeamName(teamMap.get(teamMeeting.getTeamId()).get(0).getTeamName()); + } + return gis; + }).toList(); + // 获取整改情况 + List safetyInspectionList = this.lambdaQuery() + .eq(HseSafetyInspection::getProjectId, projectId).list(); + long passCount = 0L; + for (HseSafetyInspection safetyInspection : safetyInspectionList) { + if (HseSafetyInspectionStatusEnum.REVIEW.getValue().equals(safetyInspection.getStatus()) + && HseSafetyInspectionReviewTypeEnum.PASS.getValue().equals(safetyInspection.getReviewType())) { + passCount++; + } + } + gisVo.setTeamMeetingList(gisList); + gisVo.setTeamMeetingCount((long) teamMeetings.size()); + gisVo.setSafetyInspectionCount((long) safetyInspectionList.size()); + gisVo.setCorrectSituationCount(passCount); + gisVo.setCorrectSituation(String.format("%.2f", passCount * 100.0 / safetyInspectionList.size())); + return gisVo; + } + + /** + * 新增安全巡检工单 + * + * @param req 安全巡检工单 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(HseSafetyInspectionCreateReq req) { + // 将实体类和 DTO 进行转换 + HseSafetyInspection safetyInspection = new HseSafetyInspection(); + BeanUtils.copyProperties(req, safetyInspection); + // 数据校验 + validEntityBeforeSave(safetyInspection, true); + // 写入数据库 + boolean save = this.save(safetyInspection); + if (!save) { + throw new ServiceException("新增安全巡检工单信息失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return safetyInspection.getId(); + } + + /** + * 修改安全巡检工单 + * + * @param req 安全巡检工单 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseSafetyInspectionUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseSafetyInspection safetyInspection = new HseSafetyInspection(); + BeanUtils.copyProperties(req, safetyInspection); + // 数据校验 + validEntityBeforeSave(safetyInspection, false); + // 判断是否存在 + HseSafetyInspection oldSafetyInspection = this.getById(safetyInspection.getId()); + if (oldSafetyInspection == null) { + throw new ServiceException("修改安全巡检工单信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(safetyInspection); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseSafetyInspection entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + Long correctorId = entity.getCorrectorId(); + String checkType = entity.getCheckType(); + String violationType = entity.getViolationType(); + // 创建时校验 + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (correctorId == null) { + throw new ServiceException("整改人id不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(checkType)) { + throw new ServiceException("检查类型不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isBlank(violationType)) { + throw new ServiceException("违规类型不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + if (correctorId != null && constructionUserService.getById(correctorId) == null) { + throw new ServiceException("对应整改人不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除安全巡检工单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + Long count = this.lambdaQuery().in(HseSafetyInspection::getPid, ids).count(); + if (count > 0) { + throw new ServiceException("所选安全巡检工单包含子数据,不允许删除", HttpStatus.BAD_REQUEST); + } + } + return this.removeBatchByIds(ids); + } + + /** + * 获取安全巡检工单视图对象 + * + * @param safetyInspection 安全巡检工单对象 + * @return 安全巡检工单视图对象 + */ + @Override + public HseSafetyInspectionVo getVo(HseSafetyInspection safetyInspection) { + // 对象转封装类 + HseSafetyInspectionVo safetyInspectionVo = new HseSafetyInspectionVo(); + if (safetyInspection == null) { + return safetyInspectionVo; + } + BeanUtils.copyProperties(safetyInspection, safetyInspectionVo); + // 关联班组信息 + Long teamId = safetyInspection.getTeamId(); + if (teamId != null) { + LambdaQueryWrapper teamLambdaQueryWrapper = Wrappers.lambdaQuery(BusProjectTeam.class) + .select(BusProjectTeam::getId, BusProjectTeam::getTeamName) + .eq(BusProjectTeam::getId, teamId); + BusProjectTeam projectTeam = projectTeamService.getOne(teamLambdaQueryWrapper); + safetyInspectionVo.setTeamId(projectTeam.getId()); + safetyInspectionVo.setTeamName(projectTeam.getTeamName()); + } + // 关联整改人信息 + Long correctorId = safetyInspection.getCorrectorId(); + if (correctorId != null) { + LambdaQueryWrapper constructionUserLambdaQueryWrapper = Wrappers.lambdaQuery(SubConstructionUser.class) + .select(SubConstructionUser::getId, SubConstructionUser::getUserName) + .eq(SubConstructionUser::getId, correctorId); + SubConstructionUser constructionUser = constructionUserService.getOne(constructionUserLambdaQueryWrapper); + safetyInspectionVo.setCorrectorId(constructionUser.getId()); + safetyInspectionVo.setCorrectorName(constructionUser.getUserName()); + } + // 关联创建用户信息 + Long createBy = safetyInspection.getCreateBy(); + if (createBy != null) { + SysUserVo createUser = userService.selectUserById(createBy); + safetyInspectionVo.setCreatorId(createUser.getUserId()); + safetyInspectionVo.setCreatorName(createUser.getNickName()); + } + return safetyInspectionVo; + } + + /** + * 获取安全巡检工单查询条件封装 + * + * @param req 安全巡检工单查询条件 + * @return 安全巡检工单查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseSafetyInspectionQueryReq req) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + if (req == null) { + return lqw; + } + Long pid = req.getPid(); + Long projectId = req.getProjectId(); + String checkType = req.getCheckType(); + String violationType = req.getViolationType(); + Long teamId = req.getTeamId(); + Long correctorId = req.getCorrectorId(); + String status = req.getStatus(); + String reviewType = req.getReviewType(); + // 精准查询 + lqw.eq(ObjectUtils.isNotEmpty(pid), HseSafetyInspection::getPid, pid); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseSafetyInspection::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(checkType), HseSafetyInspection::getCheckType, checkType); + lqw.eq(ObjectUtils.isNotEmpty(violationType), HseSafetyInspection::getViolationType, violationType); + lqw.eq(ObjectUtils.isNotEmpty(teamId), HseSafetyInspection::getTeamId, teamId); + lqw.eq(ObjectUtils.isNotEmpty(correctorId), HseSafetyInspection::getCorrectorId, correctorId); + lqw.eq(ObjectUtils.isNotEmpty(status), HseSafetyInspection::getStatus, status); + lqw.eq(ObjectUtils.isNotEmpty(reviewType), HseSafetyInspection::getReviewType, reviewType); + return lqw; + } + + /** + * 获取安全巡检工单分页对象视图 + * + * @param safetyInspectionPage 安全巡检工单分页对象 + * @return 安全巡检工单分页对象视图 + */ + @Override + public Page getVoPage(Page safetyInspectionPage) { + // 获取安全巡检工单 + List safetyInspectionList = safetyInspectionPage.getRecords(); + // 添加分页信息 + Page safetyInspectionVoPage = new Page<>( + safetyInspectionPage.getCurrent(), + safetyInspectionPage.getSize(), + safetyInspectionPage.getTotal()); + if (CollUtil.isEmpty(safetyInspectionList)) { + return safetyInspectionVoPage; + } + // 对象列表 => 封装对象列表 + List safetyInspectionVoList = safetyInspectionList.stream().map(this::getVo).toList(); + safetyInspectionVoPage.setRecords(safetyInspectionVoList); + return safetyInspectionVoPage; + } + + /** + * 根据id导出word + * + * @param id 主键 + * @param response 响应 + */ + @Override + public void exportWordById(Long id, HttpServletResponse response) { + HseSafetyInspection safetyInspection = this.getById(id); + if (safetyInspection == null) { + throw new ServiceException("安全巡检工单不存在"); + } + Map replacementMap = getReplacementMap(safetyInspection); + Path targetDir = Paths.get(HseSafetyConstant.getSafetyInspectionFileUrl(safetyInspection)); + // 如果存在目录则直接返回,不存在则生成文件并返回 + if (!Files.exists(targetDir)) { + // 清理旧文件 + String baseUrl = HseSafetyConstant.SAFETY_INSPECTION_FILE_URL + safetyInspection.getId(); + try { + Path dirPath = Paths.get(baseUrl); + if (Files.exists(dirPath)) { + FileUtils.deleteDirectory(dirPath); + } + } catch (IOException e) { + log.error("文件目录:{},清理失败", baseUrl, e); + } + // 生成文件 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(HseSafetyConstant.SAFETY_INSPECTION_TEMPLATE_PATH)) { + if (is == null) { + throw new ServiceException("模板文件不存在"); + } + try (XWPFDocument document = new XWPFDocument(is)) { + // 替换段落中的文本 + for (XWPFParagraph paragraph : document.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, safetyInspection); + } + // 替换表格中的文本(如果模板中有表格) + for (XWPFTable table : document.getTables()) { + for (XWPFTableRow row : table.getRows()) { + for (XWPFTableCell cell : row.getTableCells()) { + for (XWPFParagraph paragraph : cell.getParagraphs()) { + replaceInParagraph(paragraph, replacementMap, document, safetyInspection); + } + } + } + } + // 创建目标目录 + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); + } + // 组合目标文件名 + String fileName = HseSafetyConstant.getSafetyInspectionFileName(safetyInspection); + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) { + document.write(fos); + } + } + } catch (IOException | InvalidFormatException e) { + throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + } + } + // 设置响应头,返回ZIP文件 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + DocumentUtil.zipDirectory(targetDir, targetDir, zos); + zos.flush(); + } catch (Exception e) { + throw new OssException("生成ZIP文件失败,错误信息: " + e.getMessage()); + } + } + + /** + * 根据实体获取Word的文本Map + * + * @param safetyInspection 安全巡检工单对象 + * @return Map + */ + public Map getReplacementMap(HseSafetyInspection safetyInspection) { + Map replacementMap = new HashMap<>(); + String createBy = userService.selectUserById(safetyInspection.getCreateBy()).getNickName(); + replacementMap.put("${createBy}", createBy); + Date createTime = safetyInspection.getCreateTime(); + replacementMap.put("${createTime}", createTime != null ? DateUtils.formatDateTime(createTime) : ""); + String projectName = projectService.getById(safetyInspection.getProjectId()).getProjectName(); + replacementMap.put("${projectName}", projectName); + String checkType = dictDataService.selectDictLabel(HseSafetyConstant.SAFETY_INSPECTION_CHECK_TYPE, safetyInspection.getCheckType()); + replacementMap.put("${checkType}", checkType); + String violationType = dictDataService.selectDictLabel(HseSafetyConstant.SAFETY_INSPECTION_VIOLATION_TYPE, safetyInspection.getViolationType()); + replacementMap.put("${violationType}", violationType); + Date checkTime = safetyInspection.getCheckTime(); + replacementMap.put("${checkTime}", checkTime != null ? DateUtils.formatDateTime(checkTime) : ""); + String correctorName = constructionUserService.getById(safetyInspection.getCorrectorId()).getUserName(); + replacementMap.put("${correctorName}", correctorName); + replacementMap.put("${replyDate}", safetyInspection.getReplyDate()); + replacementMap.put("${hiddenDanger}", safetyInspection.getHiddenDanger()); + replacementMap.put("${checkFile}", safetyInspection.getCheckFile()); + String status = dictDataService.selectDictLabel(HseSafetyConstant.SAFETY_INSPECTION_TYPE, safetyInspection.getStatus()); + replacementMap.put("${status}", status); + String teamName = projectTeamService.getById(safetyInspection.getTeamId()).getTeamName(); + replacementMap.put("${teamName}", teamName); + Date rectificationTime = safetyInspection.getRectificationTime(); + replacementMap.put("${rectificationTime}", rectificationTime != null ? DateUtils.formatDateTime(rectificationTime) : ""); + replacementMap.put("${measure}", safetyInspection.getMeasure()); + replacementMap.put("${rectificationFile}", safetyInspection.getRectificationFile()); + Date reviewTime = safetyInspection.getReviewTime(); + replacementMap.put("${reviewTime}", reviewTime != null ? DateUtils.formatDateTime(reviewTime) : ""); + replacementMap.put("${review}", safetyInspection.getReview()); + return replacementMap; + } + + /** + * 替换段落中所有文本运行的占位符内容,对于 checkFile 和 rectificationFile + * 插入图片或超链接(附件)展示。 + * + * @param paragraph 当前段落 + * @param replacements 占位符与替换内容的映射 + * @param document 当前文档,用于插入图片或创建超链接 + */ + public void replaceInParagraph(XWPFParagraph paragraph, Map replacements, XWPFDocument document, HseSafetyInspection safetyInspection) throws InvalidFormatException, IOException { + // 先拷贝 paragraph 里所有的 run + List runs = new ArrayList<>(paragraph.getRuns()); + // 在拷贝上遍历,修改原 paragraph(增删 run)都不会抛 CME + for (XWPFRun run : runs) { + String text = run.getText(0); + if (text != null) { + // 针对每个占位符进行检查 + for (Map.Entry entry : replacements.entrySet()) { + String placeholder = entry.getKey(); + String value = entry.getValue(); + if (text.contains(placeholder)) { + // 针对 checkFile 和 rectificationFile 进行特殊处理 + if (placeholder.equals("${checkFile}") || placeholder.equals("${rectificationFile}")) { + // 判断该 run 中的文本是否仅包含该占位符(建议模板中独占一行) + if (text.trim().equals(placeholder)) { + // 清空原有文本 + run.setText("", 0); + // 根据附件的后缀决定以图片或超链接展示 + if (StringUtils.isBlank(value)) { + continue; + } + // 获取附件的ossId + List ossIdList = Arrays.stream(value.split(",")).map(Long::parseLong).toList(); + List ossVoList = ossService.listByIds(ossIdList); + String baseFile = HseSafetyConstant.getSafetyInspectionFileUrl(safetyInspection) + "/file"; + for (SysOssVo ossVo : ossVoList) { + String lowerVal = ossVo.getUrl().toLowerCase(); + OssClient storage = OssFactory.instance(ossVo.getService()); + String fileDownload = storage.fileDownload(ossVo.getUrl(), ossVo.getOriginalName(), baseFile); + if (lowerVal.endsWith(".png") || lowerVal.endsWith(".jpg") || lowerVal.endsWith(".jpeg") || lowerVal.endsWith(".gif")) { + try { + DocumentUtil.insertImageDynamic(run, fileDownload, document, 300); + } catch (Exception e) { + throw new ServiceException("插入图片失败"); + } + } else { + // —— 非图片:插入超链接 —— + XWPFHyperlinkRun link = paragraph.createHyperlinkRun(ossVo.getUrl()); + link.setText(ossVo.getOriginalName()); + link.setColor("0000FF"); + link.setUnderline(UnderlinePatterns.SINGLE); + } + } + } else { + // 如果占位符与其它文本混合,可进行文本替换,提示附件展示请单独使用占位符 + text = text.replace(placeholder, "[附件]"); + run.setText(text, 0); + } + } else { + // 普通文本占位符直接替换 + if (StringUtils.isBlank(value)) { + // 如果填入值为空,清空原有文本 + run.setText("", 0); + continue; + } + text = text.replace(placeholder, value); + run.setText(text, 0); + } + } + } + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyLogServiceImpl.java new file mode 100644 index 0000000..5fbded0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyLogServiceImpl.java @@ -0,0 +1,245 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.vo.IdAndNameVO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.domain.HseSafetyLog; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogCreateReq; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogQueryReq; +import org.dromara.safety.domain.dto.safetylog.HseSafetyLogUpdateReq; +import org.dromara.safety.domain.vo.safetylog.HseSafetyLogVo; +import org.dromara.safety.mapper.HseSafetyLogMapper; +import org.dromara.safety.service.IHseSafetyLogService; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 安全日志Service业务层处理 + * + * @author lilemy + * @date 2025-03-20 + */ +@Service +public class HseSafetyLogServiceImpl extends ServiceImpl + implements IHseSafetyLogService { + + @Resource + private IBusProjectService projectService; + + @Resource + private SysUserMapper userMapper; + + /** + * 查询安全日志 + * + * @param id 主键 + * @return 安全日志 + */ + @Override + public HseSafetyLogVo queryById(Long id) { + HseSafetyLog safetyLog = this.getById(id); + if (safetyLog == null) { + throw new ServiceException("安全日志信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(safetyLog); + } + + /** + * 分页查询安全日志列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全日志分页列表 + */ + @Override + public TableDataInfo queryPageList(HseSafetyLogQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的安全日志列表 + * + * @param req 查询条件 + * @return 安全日志列表 + */ + @Override + public List queryList(HseSafetyLogQueryReq req) { + List safetyLogList = this.list(this.buildQueryWrapper(req)); + return safetyLogList.stream().map(this::getVo).toList(); + } + + /** + * 新增安全日志 + * + * @param req 安全日志 + * @return 新增id + */ + @Override + public Long insertByBo(HseSafetyLogCreateReq req) { + // 将实体类和 DTO 进行转换 + HseSafetyLog safetyLog = new HseSafetyLog(); + BeanUtils.copyProperties(req, safetyLog); + // 数据校验 + validEntityBeforeSave(safetyLog, true); + // 写入数据库 + boolean save = this.save(safetyLog); + if (!save) { + throw new ServiceException("新增安全日志信息失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return safetyLog.getId(); + } + + /** + * 修改安全日志 + * + * @param req 安全日志 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseSafetyLogUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseSafetyLog safetyLog = new HseSafetyLog(); + BeanUtils.copyProperties(req, safetyLog); + // 数据校验 + validEntityBeforeSave(safetyLog, false); + // 判断是否存在 + HseSafetyLog oldSafetyLog = this.getById(safetyLog.getId()); + if (oldSafetyLog == null) { + throw new ServiceException("修改安全日志信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(safetyLog); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseSafetyLog entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除安全日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return this.removeBatchByIds(ids); + } + + /** + * 获取安全日志视图对象 + * + * @param safetyLog 安全日志对象 + * @return 安全日志视图对象 + */ + @Override + public HseSafetyLogVo getVo(HseSafetyLog safetyLog) { + // 对象转封装类 + HseSafetyLogVo safetyLogVo = new HseSafetyLogVo(); + if (safetyLog == null) { + return safetyLogVo; + } + BeanUtils.copyProperties(safetyLog, safetyLogVo); + // 关联创建用户信息 + Long createBy = safetyLog.getCreateBy(); + if (createBy != null) { + SysUserVo sysUserVo = userMapper.selectVoById(createBy); + safetyLogVo.setCreator(IdAndNameVO.build(sysUserVo.getUserId(), sysUserVo.getNickName())); + } + return safetyLogVo; + } + + /** + * 获取安全日志查询条件封装 + * + * @param req 安全日志查询条件 + * @return 安全日志查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseSafetyLogQueryReq req) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + String dateOfOccurrence = req.getDateOfOccurrence(); + String creatorName = req.getCreatorName(); + // 联表查询 + if (StringUtils.isNotBlank(creatorName)) { + LambdaQueryWrapper userQueryWrapper = new LambdaQueryWrapper<>(); + userQueryWrapper.like(SysUser::getUserName, creatorName); + List sysUserVos = userMapper.selectUserList(userQueryWrapper); + if (CollUtil.isNotEmpty(sysUserVos)) { + List userIds = sysUserVos.stream().map(SysUserVo::getUserId).toList(); + lqw.in(HseSafetyLog::getCreateBy, userIds); + } + } + // 精确查询 + lqw.eq(ObjectUtils.isNotEmpty(id), HseSafetyLog::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseSafetyLog::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(dateOfOccurrence), HseSafetyLog::getDateOfOccurrence, dateOfOccurrence); + return lqw; + } + + /** + * 获取安全日志分页对象视图 + * + * @param safetyLogPage 安全日志分页对象 + * @return 安全日志分页对象视图 + */ + @Override + public Page getVoPage(Page safetyLogPage) { + // 获取安全日志列表 + List safetyLogList = safetyLogPage.getRecords(); + // 添加分页信息 + Page safetyLogVoPage = new Page<>( + safetyLogPage.getCurrent(), + safetyLogPage.getSize(), + safetyLogPage.getTotal()); + if (CollUtil.isEmpty(safetyLogList)) { + return safetyLogVoPage; + } + // 对象列表 => 封装对象列表 + List safetyLogVoList = safetyLogList.stream().map(this::getVo).toList(); + safetyLogVoPage.setRecords(safetyLogVoList); + return safetyLogVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyWeeklyReportServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyWeeklyReportServiceImpl.java new file mode 100644 index 0000000..ae58a3e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseSafetyWeeklyReportServiceImpl.java @@ -0,0 +1,241 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.domain.HseSafetyWeeklyReport; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportCreateReq; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportQueryReq; +import org.dromara.safety.domain.dto.safetyweeklyreport.HseSafetyWeeklyReportUpdateReq; +import org.dromara.safety.domain.vo.safetyweeklyreport.HseSafetyWeeklyReportVo; +import org.dromara.safety.mapper.HseSafetyWeeklyReportMapper; +import org.dromara.safety.service.IHseSafetyWeeklyReportService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 安全周报Service业务层处理 + * + * @author lilemy + * @date 2025-03-20 + */ +@Service +public class HseSafetyWeeklyReportServiceImpl extends ServiceImpl + implements IHseSafetyWeeklyReportService { + + @Resource + private ISysOssService ossService; + + @Resource + private IBusProjectService projectService; + + /** + * 查询安全周报 + * + * @param id 主键 + * @return 安全周报 + */ + @Override + public HseSafetyWeeklyReportVo queryById(Long id) { + HseSafetyWeeklyReport safetyWeeklyReport = this.getById(id); + if (safetyWeeklyReport == null) { + throw new ServiceException("安全周报信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(safetyWeeklyReport); + } + + /** + * 分页查询安全周报列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 安全周报分页列表 + */ + @Override + public TableDataInfo queryPageList(HseSafetyWeeklyReportQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的安全周报列表 + * + * @param req 查询条件 + * @return 安全周报列表 + */ + @Override + public List queryList(HseSafetyWeeklyReportQueryReq req) { + List safetyWeeklyReportList = this.list(this.buildQueryWrapper(req)); + return safetyWeeklyReportList.stream().map(this::getVo).toList(); + } + + /** + * 新增安全周报 + * + * @param req 安全周报 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(HseSafetyWeeklyReportCreateReq req) { + // 将实体类和 DTO 进行转换 + HseSafetyWeeklyReport safetyWeeklyReport = new HseSafetyWeeklyReport(); + BeanUtils.copyProperties(req, safetyWeeklyReport); + // 数据校验 + validEntityBeforeSave(safetyWeeklyReport, true); + // 写入数据库 + boolean save = this.save(safetyWeeklyReport); + if (!save) { + throw new ServiceException("新增安全周报信息失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return safetyWeeklyReport.getId(); + } + + /** + * 修改安全周报 + * + * @param req 安全周报 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseSafetyWeeklyReportUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseSafetyWeeklyReport safetyWeeklyReport = new HseSafetyWeeklyReport(); + BeanUtils.copyProperties(req, safetyWeeklyReport); + // 数据校验 + validEntityBeforeSave(safetyWeeklyReport, false); + // 判断是否存在 + HseSafetyWeeklyReport oldSafetyWeeklyReport = this.getById(safetyWeeklyReport.getId()); + if (oldSafetyWeeklyReport == null) { + throw new ServiceException("修改安全周报信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(safetyWeeklyReport); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseSafetyWeeklyReport entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除安全周报信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return this.removeBatchByIds(ids); + } + + /** + * 获取安全周报视图对象 + * + * @param safetyWeeklyReport 安全周报对象 + * @return 安全周报视图对象 + */ + @Override + public HseSafetyWeeklyReportVo getVo(HseSafetyWeeklyReport safetyWeeklyReport) { + // 对象转封装类 + HseSafetyWeeklyReportVo safetyWeeklyReportVo = new HseSafetyWeeklyReportVo(); + if (safetyWeeklyReport == null) { + return safetyWeeklyReportVo; + } + BeanUtils.copyProperties(safetyWeeklyReport, safetyWeeklyReportVo); + // 获取文件信息 + String path = safetyWeeklyReport.getPath(); + if (StringUtils.isNotBlank(path)) { + SysOssVo ossVo = ossService.getById(Long.valueOf(path)); + safetyWeeklyReportVo.setPathUrl(ossVo.getUrl()); + } + return safetyWeeklyReportVo; + } + + /** + * 获取安全周报查询条件封装 + * + * @param req 安全周报查询条件 + * @return 安全周报查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseSafetyWeeklyReportQueryReq req) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + String week = req.getWeek(); + List scopeDate = req.getScopeDate(); + String remark = req.getRemark(); + // 时间范围查询 + if (ObjectUtils.isNotEmpty(scopeDate)) { + lqw.ge(HseSafetyWeeklyReport::getScopeEnd, scopeDate.get(0)) + .le(HseSafetyWeeklyReport::getScope, scopeDate.get(1)); + } + // 模糊查询 + lqw.like(StringUtils.isNotBlank(remark), HseSafetyWeeklyReport::getRemark, remark); + // 精准查询 + lqw.eq(ObjectUtils.isNotEmpty(id), HseSafetyWeeklyReport::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseSafetyWeeklyReport::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(week), HseSafetyWeeklyReport::getWeek, week); + return lqw; + } + + /** + * 获取安全周报分页对象视图 + * + * @param safetyWeeklyReportPage 安全周报分页对象 + * @return 安全周报分页对象视图 + */ + @Override + public Page getVoPage(Page safetyWeeklyReportPage) { + // 获取安全周报列表 + List safetyWeeklyReportList = safetyWeeklyReportPage.getRecords(); + // 添加分页信息 + Page safetyWeeklyReportVoPage = new Page<>( + safetyWeeklyReportPage.getCurrent(), + safetyWeeklyReportPage.getSize(), + safetyWeeklyReportPage.getTotal()); + if (CollUtil.isEmpty(safetyWeeklyReportList)) { + return safetyWeeklyReportVoPage; + } + // 对象列表 => 封装对象列表 + List safetyWeeklyReportVoList = safetyWeeklyReportList.stream().map(this::getVo).toList(); + safetyWeeklyReportVoPage.setRecords(safetyWeeklyReportVoList); + return safetyWeeklyReportVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseTeamMeetingServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseTeamMeetingServiceImpl.java new file mode 100644 index 0000000..4c91e9e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseTeamMeetingServiceImpl.java @@ -0,0 +1,375 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.domain.vo.IdAndNameVO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubConstructionUser; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.project.domain.BusProjectTeam; +import org.dromara.contractor.service.ISubConstructionUserService; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusProjectTeamService; +import org.dromara.safety.domain.HseTeamMeeting; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingCreateReq; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingQueryReq; +import org.dromara.safety.domain.dto.teammeeting.HseTeamMeetingUpdateReq; +import org.dromara.safety.domain.vo.teammeeting.HseTeamMeetingVo; +import org.dromara.safety.mapper.HseTeamMeetingMapper; +import org.dromara.safety.service.IHseTeamMeetingService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 站班会Service业务层处理 + * + * @author lilemy + * @date 2025-03-19 + */ +@Service +public class HseTeamMeetingServiceImpl extends ServiceImpl + implements IHseTeamMeetingService { + + @Resource + private ISysOssService ossService; + + @Resource + private ISubConstructionUserService constructionUserService; + + @Resource + private ISubContractorService contractorService; + + @Resource + private IBusProjectTeamService projectTeamService; + + @Resource + private IBusProjectService projectService; + + /** + * 查询站班会 + * + * @param id 主键 + * @return 站班会 + */ + @Override + public HseTeamMeetingVo queryById(Long id) { + HseTeamMeeting teamMeeting = this.getById(id); + if (teamMeeting == null) { + throw new ServiceException("站班会信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(teamMeeting); + } + + /** + * 分页查询站班会列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 站班会分页列表 + */ + @Override + public TableDataInfo queryPageList(HseTeamMeetingQueryReq req, PageQuery pageQuery) { + Page result = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的站班会列表 + * + * @param req 查询条件 + * @return 站班会列表 + */ + @Override + public List queryList(HseTeamMeetingQueryReq req) { + List list = this.list(this.buildQueryWrapper(req)); + // 对象列表 => 封装对象列表 + return list.stream().map(this::getVo).toList(); + } + + /** + * 新增站班会 + * + * @param req 站班会 + * @return 是否新增成功 + */ + @Override + public Long insertByBo(HseTeamMeetingCreateReq req) { + // 将实体类和 DTO 进行转换 + HseTeamMeeting teamMeeting = new HseTeamMeeting(); + BeanUtils.copyProperties(req, teamMeeting); + // 数据转换 + List participantIdList = req.getParticipantIdList(); + String participantIdStr = JSONUtil.toJsonStr(participantIdList); + teamMeeting.setParticipantId(participantIdStr); + // 数据校验 + validEntityBeforeSave(teamMeeting, true); + // 写入数据库 + boolean save = this.save(teamMeeting); + if (!save) { + throw new ServiceException("新增站班会信息失败,数据库异常", HttpStatus.ERROR); + } + // 返回新写入的数据 + return teamMeeting.getId(); + } + + /** + * 修改站班会 + * + * @param req 站班会 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(HseTeamMeetingUpdateReq req) { + // 将实体类和 DTO 进行转换 + HseTeamMeeting teamMeeting = new HseTeamMeeting(); + BeanUtils.copyProperties(req, teamMeeting); + // 数据转换 + List participantIdList = req.getParticipantIdList(); + String participantIdStr = JSONUtil.toJsonStr(participantIdList); + teamMeeting.setParticipantId(participantIdStr); + // 数据校验 + validEntityBeforeSave(teamMeeting, false); + // 判断是否存在 + HseTeamMeeting oldTeamMeeting = this.getById(teamMeeting.getId()); + if (oldTeamMeeting == null) { + throw new ServiceException("修改站班会信息失败,数据不存在", HttpStatus.NOT_FOUND); + } + // 操作数据库 + return this.updateById(teamMeeting); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseTeamMeeting entity, Boolean create) { + // TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除站班会信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List teamMeetingList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectId = teamMeetingList.stream().map(HseTeamMeeting::getProjectId).toList(); + projectService.validAuth(projectId, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取站班会视图对象 + * + * @param teamMeeting 站班会对象 + * @return 站班会视图对象 + */ + @Override + public HseTeamMeetingVo getVo(HseTeamMeeting teamMeeting) { + // 对象转封装类 + HseTeamMeetingVo teamMeetingVo = new HseTeamMeetingVo(); + if (teamMeeting == null) { + return teamMeetingVo; + } + BeanUtils.copyProperties(teamMeeting, teamMeetingVo); + // 查询对应分包公司 + Long contractorId = teamMeeting.getContractorId(); + if (contractorId != null) { + // 仅查询id 和 name + LambdaQueryWrapper contractorLambdaQueryWrapper = Wrappers.lambdaQuery(SubContractor.class) + .select(SubContractor::getId, SubContractor::getName) + .eq(SubContractor::getId, contractorId); + SubContractor contractor = contractorService.getOne(contractorLambdaQueryWrapper); + teamMeetingVo.setContractorName(contractor.getName()); + } + // 查询对应班组 + Long teamId = teamMeeting.getTeamId(); + if (teamId != null) { + LambdaQueryWrapper teamLambdaQueryWrapper = Wrappers.lambdaQuery(BusProjectTeam.class) + .select(BusProjectTeam::getId, BusProjectTeam::getTeamName) + .eq(BusProjectTeam::getId, teamId); + BusProjectTeam projectTeam = projectTeamService.getOne(teamLambdaQueryWrapper); + teamMeetingVo.setTeamName(projectTeam.getTeamName()); + } + // 查询对应参会用户 + String participantId = teamMeeting.getParticipantId(); + List participantIdList = JSONUtil.toList(participantId, Long.class); + if (CollUtil.isNotEmpty(participantIdList)) { + LambdaQueryWrapper constructionUserLambdaQueryWrapper = Wrappers.lambdaQuery(SubConstructionUser.class) + .select(SubConstructionUser::getId, SubConstructionUser::getUserName) + .in(SubConstructionUser::getId, participantIdList); + List constructionUserList = constructionUserService.list(constructionUserLambdaQueryWrapper); + List idAndNameVOList = constructionUserList.stream() + .map(constructionUser -> IdAndNameVO.build(constructionUser.getId(), constructionUser.getUserName())) + .toList(); + teamMeetingVo.setParticipantList(idAndNameVOList); + } + // 查询对应宣讲人 + Long compereId = teamMeeting.getCompereId(); + if (compereId != null) { + LambdaQueryWrapper constructionUserLambdaQueryWrapper = Wrappers.lambdaQuery(SubConstructionUser.class) + .select(SubConstructionUser::getId, SubConstructionUser::getUserName) + .eq(SubConstructionUser::getId, compereId); + SubConstructionUser constructionUser = constructionUserService.getOne(constructionUserLambdaQueryWrapper); + teamMeetingVo.setCompereName(constructionUser.getUserName()); + } + // 查询对应文件信息 + String picture = teamMeeting.getPicture(); + if (StringUtils.isNotBlank(picture)) { + List ossIdList = Arrays.stream(picture.split(",")).map(Long::parseLong).toList(); + List sysOssVoList = ossService.listByIds(ossIdList); + List pictureUrlList = sysOssVoList.stream().map(SysOssVo::getUrl).toList(); + teamMeetingVo.setPictureUrlList(pictureUrlList); + } + return teamMeetingVo; + } + + /** + * 获取站班会查询条件封装 + * + * @param req 站班会查询条件 + * @return 站班会查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseTeamMeetingQueryReq req) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + Long teamId = req.getTeamId(); + Long contractorId = req.getContractorId(); + Date meetingDate = req.getMeetingDate(); + Long compereId = req.getCompereId(); + List participantIdList = req.getParticipantIdList(); + String content = req.getContent(); + String remark = req.getRemark(); + // JSON 数组查询 + if (CollUtil.isNotEmpty(participantIdList)) { + for (String participantId : participantIdList) { + lqw.like(HseTeamMeeting::getParticipantId, "\"" + participantId + "\""); + } + } + // 模糊查询 + lqw.like(StringUtils.isNotBlank(content), HseTeamMeeting::getContent, content); + lqw.like(StringUtils.isNotBlank(remark), HseTeamMeeting::getRemark, remark); + // 精准查询 + lqw.eq(ObjectUtils.isNotEmpty(id), HseTeamMeeting::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseTeamMeeting::getProjectId, projectId); + lqw.eq(ObjectUtils.isNotEmpty(teamId), HseTeamMeeting::getTeamId, teamId); + lqw.eq(ObjectUtils.isNotEmpty(contractorId), HseTeamMeeting::getContractorId, contractorId); + lqw.eq(ObjectUtils.isNotEmpty(meetingDate), HseTeamMeeting::getMeetingDate, meetingDate); + lqw.eq(ObjectUtils.isNotEmpty(compereId), HseTeamMeeting::getCompereId, compereId); + return lqw; + } + + /** + * 获取站班会分页对象视图 + * + * @param teamMeetingPage 站班会分页对象 + * @return 站班会分页对象视图 + */ + @Override + public Page getVoPage(Page teamMeetingPage) { + // 获取材料数据 + List teamMeetingList = teamMeetingPage.getRecords(); + // 添加分页信息 + Page teamMeetingVoPage = new Page<>(teamMeetingPage.getCurrent(), teamMeetingPage.getSize(), teamMeetingPage.getTotal()); + if (CollUtil.isEmpty(teamMeetingList)) { + return teamMeetingVoPage; + } + // 获取对应班组 + Set teamIdList = teamMeetingList.stream().map(HseTeamMeeting::getTeamId).collect(Collectors.toSet()); + Map> teamMap = projectTeamService.listByIds(teamIdList) + .stream().collect(Collectors.groupingBy(BusProjectTeam::getId)); + // 获取对应分包公司 + Set contractorIdList = teamMeetingList.stream().map(HseTeamMeeting::getContractorId).collect(Collectors.toSet()); + Map> contractorMap = contractorService.listByIds(contractorIdList) + .stream().collect(Collectors.groupingBy(SubContractor::getId)); + // 获取对应参会人 + Set userIdList = new HashSet<>(); + for (HseTeamMeeting teamMeeting : teamMeetingList) { + String participantId = teamMeeting.getParticipantId(); + userIdList.addAll(JSONUtil.toList(participantId, Long.class)); + } + // 获取对应宣讲人 + Set compereIdList = teamMeetingList.stream().map(HseTeamMeeting::getCompereId).collect(Collectors.toSet()); + userIdList.addAll(compereIdList); + Map> userMap = constructionUserService.listByIds(userIdList) + .stream().collect(Collectors.groupingBy(SubConstructionUser::getId)); + // 对象列表 => 封装对象列表 + List teamMeetingVoList = teamMeetingList.stream().map(teamMeeting -> { + HseTeamMeetingVo teamMeetingVo = new HseTeamMeetingVo(); + BeanUtils.copyProperties(teamMeeting, teamMeetingVo); + // 关联班组信息 + String teamName = null; + if (teamMap.containsKey(teamMeeting.getTeamId())) { + teamName = teamMap.get(teamMeeting.getTeamId()).getFirst().getTeamName(); + } + teamMeetingVo.setTeamName(teamName); + // 关联分包公司信息 + String contractorName = null; + if (contractorMap.containsKey(teamMeeting.getContractorId())) { + contractorName = contractorMap.get(teamMeeting.getContractorId()).getFirst().getName(); + } + teamMeetingVo.setContractorName(contractorName); + // 关联宣讲人信息 + String compereName = null; + if (userMap.containsKey(teamMeeting.getCompereId())) { + compereName = userMap.get(teamMeeting.getCompereId()).getFirst().getUserName(); + } + teamMeetingVo.setCompereName(compereName); + // 关联参会人信息 + List participantList = new ArrayList<>(); + String participantId = teamMeeting.getParticipantId(); + List idList = JSONUtil.toList(participantId, Long.class); + if (CollUtil.isNotEmpty(idList)) { + for (Long userId : idList) { + if (userMap.containsKey(userId)) { + SubConstructionUser constructionUser = userMap.get(userId).getFirst(); + participantList.add(IdAndNameVO.build(constructionUser.getId(), constructionUser.getUserName())); + } + } + } + teamMeetingVo.setParticipantList(participantList); + return teamMeetingVo; + }).toList(); + teamMeetingVoPage.setRecords(teamMeetingVoList); + return teamMeetingVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationLevelPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationLevelPostServiceImpl.java new file mode 100644 index 0000000..2193a7d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationLevelPostServiceImpl.java @@ -0,0 +1,19 @@ +package org.dromara.safety.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.dromara.safety.domain.HseViolationLevelPost; +import org.dromara.safety.mapper.HseViolationLevelPostMapper; +import org.dromara.safety.service.IHseViolationLevelPostService; +import org.springframework.stereotype.Service; + +/** + * 等级与岗位关联Service业务层处理 + * + * @author lilemy + * @date 2025-06-20 + */ +@Service +public class HseViolationLevelPostServiceImpl extends ServiceImpl + implements IHseViolationLevelPostService { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationLevelServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationLevelServiceImpl.java new file mode 100644 index 0000000..5c940e7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationLevelServiceImpl.java @@ -0,0 +1,432 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.service.IBusProjectService; +import org.dromara.safety.constant.HseSafetyConstant; +import org.dromara.safety.domain.HseViolationLevel; +import org.dromara.safety.domain.HseViolationLevelPost; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelCreateReq; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelQueryReq; +import org.dromara.safety.domain.dto.violationlevel.HseViolationLevelUpdateReq; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelByPostVo; +import org.dromara.safety.domain.vo.violationlevel.HseViolationLevelVo; +import org.dromara.safety.mapper.HseViolationLevelMapper; +import org.dromara.safety.service.IHseViolationLevelPostService; +import org.dromara.safety.service.IHseViolationLevelService; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.mapper.SysPostMapper; +import org.dromara.system.service.ISysDictDataService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 违章等级Service业务层处理 + * + * @author lilemy + * @date 2025-06-20 + */ +@Service +public class HseViolationLevelServiceImpl extends ServiceImpl + implements IHseViolationLevelService { + + @Resource + private IBusProjectService projectService; + + @Resource + private IHseViolationLevelPostService violationLevelPostService; + + @Resource + private SysPostMapper postMapper; + + @Resource + private ISysDictDataService dictDataService; + + /** + * 查询违章等级 + * + * @param id 主键 + * @return 违章等级 + */ + @Override + public HseViolationLevelByPostVo queryById(Long id) { + HseViolationLevel violationLevel = this.getById(id); + if (violationLevel == null) { + throw new ServiceException("违章等级信息不存在", HttpStatus.NOT_FOUND); + } + return this.getByPostVo(violationLevel); + } + + /** + * 分页查询违章等级列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 违章等级分页列表 + */ + @Override + public TableDataInfo queryPageList(HseViolationLevelQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的违章等级列表 + * + * @param req 查询条件 + * @return 违章等级列表 + */ + @Override + public List queryList(HseViolationLevelQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(violationLevel -> { + HseViolationLevelVo vo = new HseViolationLevelVo(); + BeanUtils.copyProperties(violationLevel, vo); + return vo; + }).toList(); + } + + /** + * 新增违章等级 + * + * @param req 违章等级 + * @return 新增违章等级主键id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long insertByBo(HseViolationLevelCreateReq req) { + Long projectId = req.getProjectId(); + if (projectService.getById(projectId) == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + HseViolationLevel violationLevel = new HseViolationLevel(); + BeanUtils.copyProperties(req, violationLevel); + // 校验参数 + validEntityBeforeSave(violationLevel, true); + List postIdList = req.getPostIdList(); + if (CollUtil.isEmpty(postIdList)) { + throw new ServiceException("岗位不能为空", HttpStatus.BAD_REQUEST); + } + // 判断违章等级或风险等级是否存在 + List existList = this.lambdaQuery() + .eq(HseViolationLevel::getProjectId, projectId) + .and(wrapper -> wrapper + .eq(HseViolationLevel::getViolationLevel, violationLevel.getViolationLevel()) + .or() + .eq(HseViolationLevel::getRiskType, violationLevel.getRiskType()) + ) + .list(); + for (HseViolationLevel exist : existList) { + if (exist.getViolationLevel().equals(violationLevel.getViolationLevel())) { + throw new ServiceException("违章等级已存在", HttpStatus.BAD_REQUEST); + } + if (exist.getRiskType().equals(violationLevel.getRiskType())) { + throw new ServiceException("风险等级已存在", HttpStatus.BAD_REQUEST); + } + } + // 拆分 violationType + Set violationTypeList = Arrays.stream(req.getViolationType().split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toSet()); + if (CollUtil.isEmpty(violationTypeList)) { + throw new ServiceException("违章类型不能为空", HttpStatus.BAD_REQUEST); + } + // 判断违章类型是否存在 + List allViolationTypeList = this.lambdaQuery() + .select(HseViolationLevel::getViolationType) + .eq(HseViolationLevel::getProjectId, projectId) + .list().stream() + .flatMap(v -> Arrays.stream(v.getViolationType().split(","))) + .map(String::trim) + .distinct() + .toList(); + // 判断是否存在交集(只要一个存在就抛异常) + for (String type : violationTypeList) { + if (allViolationTypeList.contains(type)) { + String dictLabel = dictDataService.selectDictLabel(HseSafetyConstant.VIOLATION_LEVEL_TYPE, type); + throw new ServiceException("违章类型 [" + dictLabel + "] 已存在,不能重复添加", HttpStatus.BAD_REQUEST); + } + } + boolean result = this.save(violationLevel); + if (!result) { + throw new ServiceException("新增违章等级失败", HttpStatus.ERROR); + } + Long id = violationLevel.getId(); + // 新增岗位与违章等级关联 + List postList = postIdList.stream().map(postId -> { + HseViolationLevelPost violationLevelPost = new HseViolationLevelPost(); + violationLevelPost.setLevel(id); + violationLevelPost.setPost(postId); + return violationLevelPost; + }).toList(); + boolean saveRelevancy = violationLevelPostService.saveBatch(postList); + if (!saveRelevancy) { + throw new ServiceException("新增岗位与违章等级关联失败,数据库异常", HttpStatus.ERROR); + } + return id; + } + + /** + * 修改违章等级 + * + * @param req 违章等级 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(HseViolationLevelUpdateReq req) { + HseViolationLevel violationLevel = new HseViolationLevel(); + BeanUtils.copyProperties(req, violationLevel); + validEntityBeforeSave(violationLevel, false); + Long id = req.getId(); + HseViolationLevel oldViolationLevel = this.getById(id); + if (oldViolationLevel == null) { + throw new ServiceException("修改的违章等级信息不存在", HttpStatus.NOT_FOUND); + } + // 判断违章等级是否存在 + if (!oldViolationLevel.getViolationLevel().equals(violationLevel.getViolationLevel())) { + Long count = this.lambdaQuery() + .eq(HseViolationLevel::getProjectId, oldViolationLevel.getProjectId()) + .eq(HseViolationLevel::getViolationLevel, violationLevel.getViolationLevel()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名违章等级", HttpStatus.CONFLICT); + } + } + // 判断风险等级是否存在 + if (!oldViolationLevel.getRiskType().equals(violationLevel.getRiskType())) { + Long count = this.lambdaQuery() + .eq(HseViolationLevel::getProjectId, oldViolationLevel.getProjectId()) + .eq(HseViolationLevel::getRiskType, violationLevel.getRiskType()) + .count(); + if (count > 0) { + throw new ServiceException("该项目已存在同名风险等级", HttpStatus.CONFLICT); + } + } + Set newTypeSet = Arrays.stream(req.getViolationType().split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toSet()); + if (CollUtil.isEmpty(newTypeSet)) { + throw new ServiceException("违章类型不能为空", HttpStatus.BAD_REQUEST); + } + Set oldTypeSet = Arrays.stream(oldViolationLevel.getViolationType().split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toSet()); + // 如果新旧类型完全相同,则不需要校验 + if (!newTypeSet.equals(oldTypeSet)) { + // 查询其他记录的 violationType(排除当前这条记录) + List otherViolationTypes = this.lambdaQuery() + .select(HseViolationLevel::getViolationType) + .eq(HseViolationLevel::getProjectId, oldViolationLevel.getProjectId()) + .ne(HseViolationLevel::getId, id) + .list().stream() + .flatMap(v -> Arrays.stream(v.getViolationType().split(","))) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .distinct() + .toList(); + // 检查是否有交集 + for (String type : newTypeSet) { + if (otherViolationTypes.contains(type)) { + String dictLabel = dictDataService.selectDictLabel(HseSafetyConstant.VIOLATION_LEVEL_TYPE, type); + throw new ServiceException("违章类型 [" + dictLabel + "] 已存在,不能重复添加", HttpStatus.BAD_REQUEST); + } + } + } + List postIdList = req.getPostIdList(); + if (CollUtil.isNotEmpty(postIdList)) { + List oldPostIdList = violationLevelPostService.lambdaQuery() + .eq(HseViolationLevelPost::getLevel, id) + .select(HseViolationLevelPost::getPost) + .list().stream().map(HseViolationLevelPost::getPost).toList(); + // 转换为 Set + Set newSet = new HashSet<>(postIdList); + Set oldSet = new HashSet<>(oldPostIdList); + // 需要添加的岗位ID(在 new 中有,但在 old 中没有) + Set needAdd = new HashSet<>(newSet); + needAdd.removeAll(oldSet); + // 需要删除的岗位ID(在 old 中有,但在 new 中没有) + Set needDelete = new HashSet<>(oldSet); + needDelete.removeAll(newSet); + // 执行新增 + if (CollUtil.isNotEmpty(needAdd)) { + List addList = needAdd.stream().map(postId -> { + HseViolationLevelPost item = new HseViolationLevelPost(); + item.setLevel(id); + item.setPost(postId); + return item; + }).toList(); + boolean result = violationLevelPostService.saveBatch(addList); + if (!result) { + throw new ServiceException("新增岗位与违章等级关联失败,数据库异常", HttpStatus.ERROR); + } + } + // 执行删除 + if (CollUtil.isNotEmpty(needDelete)) { + boolean remove = violationLevelPostService.lambdaUpdate() + .eq(HseViolationLevelPost::getLevel, id) + .in(HseViolationLevelPost::getPost, needDelete) + .remove(); + if (!remove) { + throw new ServiceException("删除岗位与违章等级关联失败,数据库异常", HttpStatus.ERROR); + } + } + } + boolean result = this.updateById(violationLevel); + if (!result) { + throw new ServiceException("修改违章等级失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(HseViolationLevel entity, Boolean create) { + //TODO 做一些数据校验,如唯一约束 + Long projectId = entity.getProjectId(); + String violationLevel = entity.getViolationLevel(); + if (create) { + if (projectId == null) { + throw new ServiceException("项目id不能为空", HttpStatus.BAD_REQUEST); + } + if (StringUtils.isEmpty(violationLevel)) { + throw new ServiceException("违章等级不能为空", HttpStatus.BAD_REQUEST); + } + } + if (projectId != null && projectService.getById(projectId) == null) { + throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 校验并批量删除违章等级信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long userId = LoginHelper.getUserId(); + List violationLevelList = this.listByIds(ids); + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + List projectIds = violationLevelList.stream().map(HseViolationLevel::getProjectId).distinct().toList(); + projectService.validAuth(projectIds, userId); + } + return this.removeBatchByIds(ids); + } + + /** + * 获取违章等级视图对象 + * + * @param violationLevel 违章等级对象 + * @return 违章等级视图对象 + */ + @Override + public HseViolationLevelByPostVo getByPostVo(HseViolationLevel violationLevel) { + HseViolationLevelByPostVo vo = new HseViolationLevelByPostVo(); + if (violationLevel == null) { + return vo; + } + BeanUtils.copyProperties(violationLevel, vo); + List levelPostList = violationLevelPostService.lambdaQuery() + .eq(HseViolationLevelPost::getLevel, violationLevel.getId()) + .list(); + if (CollUtil.isNotEmpty(levelPostList)) { + List postIdList = levelPostList.stream().map(HseViolationLevelPost::getPost).toList(); + List postList = postMapper.selectVoByIds(postIdList); + vo.setPostList(postList); + } + return vo; + } + + /** + * 获取违章等级视图对象 + * + * @param violationLevel 违章等级对象 + * @return 违章等级视图对象 + */ + @Override + public HseViolationLevelVo getVo(HseViolationLevel violationLevel) { + HseViolationLevelVo vo = new HseViolationLevelVo(); + if (violationLevel == null) { + return vo; + } + BeanUtils.copyProperties(violationLevel, vo); + return vo; + } + + /** + * 获取违章等级查询条件封装 + * + * @param req 违章等级查询条件 + * @return 违章等级查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseViolationLevelQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + Long projectId = req.getProjectId(); + String violationLevel = req.getViolationLevel(); + String riskType = req.getRiskType(); + String violationType = req.getViolationType(); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseViolationLevel::getProjectId, projectId); + lqw.like(StringUtils.isNotBlank(violationLevel), HseViolationLevel::getViolationLevel, violationLevel); + lqw.eq(StringUtils.isNotBlank(riskType), HseViolationLevel::getRiskType, riskType); + if (StringUtils.isNotBlank(violationType)) { + lqw.likeRight(HseViolationLevel::getViolationType, violationType + ",") + .or() + .likeLeft(HseViolationLevel::getViolationType, "," + violationType) + .or() + .like(HseViolationLevel::getViolationType, "," + violationType + ",") + .or() + .eq(HseViolationLevel::getViolationType, violationType); + } + return lqw; + } + + /** + * 获取违章等级分页对象视图 + * + * @param violationLevelPage 违章等级分页对象 + * @return 违章等级分页对象视图 + */ + @Override + public Page getVoPage(Page violationLevelPage) { + List violationLevelList = violationLevelPage.getRecords(); + Page violationLevelVoPage = new Page<>( + violationLevelPage.getCurrent(), + violationLevelPage.getSize(), + violationLevelPage.getTotal()); + if (CollUtil.isEmpty(violationLevelList)) { + return violationLevelVoPage; + } + List violationLevelVoList = violationLevelList.stream().map(violationLevel -> { + HseViolationLevelVo vo = new HseViolationLevelVo(); + BeanUtils.copyProperties(violationLevel, vo); + return vo; + }).toList(); + violationLevelVoPage.setRecords(violationLevelVoList); + return violationLevelVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationRecordServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationRecordServiceImpl.java new file mode 100644 index 0000000..db959e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/safety/service/impl/HseViolationRecordServiceImpl.java @@ -0,0 +1,361 @@ +package org.dromara.safety.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.safety.domain.HseRecognizeRecord; +import org.dromara.safety.domain.HseViolationLevel; +import org.dromara.safety.domain.HseViolationLevelPost; +import org.dromara.safety.domain.HseViolationRecord; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateDto; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordCreateHandlerReq; +import org.dromara.safety.domain.dto.violationrecord.HseViolationRecordQueryReq; +import org.dromara.safety.domain.vo.violationrecord.HseViolationRecordVo; +import org.dromara.safety.mapper.HseViolationRecordMapper; +import org.dromara.safety.service.IHseRecognizeRecordService; +import org.dromara.safety.service.IHseViolationLevelPostService; +import org.dromara.safety.service.IHseViolationLevelService; +import org.dromara.safety.service.IHseViolationRecordService; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 违规记录Service业务层处理 + * + * @author lilemy + * @date 2025-07-22 + */ +@Slf4j +@Service +public class HseViolationRecordServiceImpl extends ServiceImpl + implements IHseViolationRecordService { + + @Resource + private ISysUserService userService; + + @Resource + private IHseViolationLevelService violationLevelService; + + @Lazy + @Resource + private IHseRecognizeRecordService recognizeRecordService; + + @Resource + private IHseViolationLevelPostService violationLevelPostService; + + /** + * 查询违规记录 + * + * @param id 主键 + * @return 违规记录 + */ + @Override + public HseViolationRecordVo queryById(Long id) { + HseViolationRecord violationRecord = this.getById(id); + if (violationRecord == null) { + throw new ServiceException("违规记录信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(violationRecord); + } + + /** + * 分页查询违规记录列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 违规记录分页列表 + */ + @Override + public TableDataInfo queryPageList(HseViolationRecordQueryReq req, PageQuery pageQuery) { + Page violationRecordPage = this.page(pageQuery.build(), this.buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(violationRecordPage)); + } + + /** + * 查询符合条件的违规记录列表 + * + * @param req 查询条件 + * @return 违规记录列表 + */ + @Override + public List queryList(HseViolationRecordQueryReq req) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 新增违规记录信息 + * + * @param dto 违规记录信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertByMonitor(List dto) { + if (CollUtil.isEmpty(dto)) { + return; + } + List violationRecordList = new ArrayList<>(); + // 1. 获取所有相关项目的风险等级配置 + Set projectIds = dto.stream() + .map(HseViolationRecordCreateDto::getProjectId) + .collect(Collectors.toSet()); + List violationLevelList = violationLevelService.lambdaQuery() + .in(HseViolationLevel::getProjectId, projectIds) + .list(); + + // 2. 构建 "项目 -> (违规类型 -> 等级ID)" 的映射 + Map> projectTypeToLevelIdMap = new HashMap<>(); + for (HseViolationLevel level : violationLevelList) { + Long projectId = level.getProjectId(); + String[] types = level.getViolationType().split(","); + Map typeMap = projectTypeToLevelIdMap.computeIfAbsent(projectId, k -> new HashMap<>()); + for (String type : types) { + typeMap.put(type.trim(), level.getId()); + } + } + // 3. 遍历DTO,按LevelId对ViolationType分组,然后创建记录 + for (HseViolationRecordCreateDto dtoItem : dto) { + if (dtoItem.getProjectId() == null) { + continue; + } + Map typeToLevelIdMap = projectTypeToLevelIdMap.get(dtoItem.getProjectId()); + if (typeToLevelIdMap == null) { + log.warn("项目[{}]中找不到任何违章等级定义", dtoItem.getProjectId()); + continue; + } + // 创建一个临时Map,用于根据LevelId对本次DTO中的types进行分组 + Map> levelIdToTypesMap = new HashMap<>(); + String[] typesFromDto = dtoItem.getViolationType().split(","); + for (String type : typesFromDto) { + type = type.trim(); + Long levelId = typeToLevelIdMap.get(type); + if (levelId == null) { + log.warn("项目[{}]中找不到违章类型[{}]对应的违章等级", dtoItem.getProjectId(), type); + continue; + } + // 将当前type添加到对应levelId的列表中 + levelIdToTypesMap.computeIfAbsent(levelId, k -> new ArrayList<>()).add(type); + } + // 4. 为每个分组(即每个LevelId)创建一条合并后的记录 + for (Map.Entry> entry : levelIdToTypesMap.entrySet()) { + Long levelId = entry.getKey(); + List groupedTypesList = entry.getValue(); + HseViolationRecord record = new HseViolationRecord(); + record.setProjectId(dtoItem.getProjectId()); + record.setRecognizeId(dtoItem.getRecognizeId()); + record.setViolationTime(dtoItem.getViolationTime()); + record.setRemark(dtoItem.getRemark()); + record.setLevelId(levelId); // 设置分组的LevelId + // 将分组后的types用逗号拼接,设置为合并后的ViolationType + record.setViolationType(String.join(",", groupedTypesList)); + violationRecordList.add(record); + } + } + // 批量保存 + if (CollUtil.isNotEmpty(violationRecordList)) { + violationRecordList.forEach(violationRecord -> violationRecord.setCreateBy(SystemConstants.SUPER_ADMIN_ID)); + boolean result = this.saveBatch(violationRecordList); + if (!result) { + throw new ServiceException("批量新增违规记录失败,数据库异常", HttpStatus.ERROR); + } + // 通知对应人员 + Set levelIds = violationRecordList.stream().map(HseViolationRecord::getLevelId).collect(Collectors.toSet()); + List levelPostList = violationLevelPostService.lambdaQuery() + .in(HseViolationLevelPost::getLevel, levelIds) + .list(); + List postIdList = levelPostList.stream().map(HseViolationLevelPost::getPost).distinct().toList(); + List userVoList = userService.selectUserListByPostList(postIdList); + if (CollUtil.isNotEmpty(userVoList)) { + // 通过 sse 向指定用户发送通知 + Set userIds = userVoList.stream().map(SysUserVo::getUserId).collect(Collectors.toSet()); + SseMessageDto messageDto = new SseMessageDto(); + messageDto.setUserIds(new ArrayList<>(userIds)); + for (HseViolationRecord violationRecord : violationRecordList) { + messageDto.setMessage("您有一份重要的违章需要处理!工单号为:" + violationRecord.getId()); + SseMessageUtils.publishMessage(messageDto); + } + } + } + } + + /** + * 新增违章处理人 + * + * @param req 违章处理人 + * @return 是否新增成功 + */ + @Override + public Boolean insertHandler(HseViolationRecordCreateHandlerReq req) { + Long id = req.getId(); + HseViolationRecord oldViolationRecord = this.getById(id); + if (oldViolationRecord == null) { + throw new ServiceException("违规记录信息不存在", HttpStatus.NOT_FOUND); + } + Long handlerId = req.getHandlerId(); + SysUserVo user = userService.selectUserById(handlerId); + if (user == null) { + throw new ServiceException("处理人信息不存在", HttpStatus.NOT_FOUND); + } + HseViolationRecord violationRecord = new HseViolationRecord(); + violationRecord.setId(id); + violationRecord.setHandlerId(handlerId); + violationRecord.setDisposeDeadline(req.getDisposeDeadline()); + violationRecord.setRemark(req.getRemark()); + boolean result = this.updateById(violationRecord); + if (!result) { + throw new ServiceException("更新处理人操作失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 批量删除违规记录信息 + * + * @param ids 待删除的主键集合 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids) { + return this.removeBatchByIds(ids); + } + + /** + * 获取违规记录视图对象 + * + * @param violationRecord 违规记录对象 + * @return 违规记录视图对象 + */ + @Override + public HseViolationRecordVo getVo(HseViolationRecord violationRecord) { + HseViolationRecordVo violationRecordVo = new HseViolationRecordVo(); + if (violationRecord == null) { + return violationRecordVo; + } + BeanUtils.copyProperties(violationRecord, violationRecordVo); + // 关联等级 + Long levelId = violationRecord.getLevelId(); + if (ObjectUtils.isNotEmpty(levelId)) { + HseViolationLevel level = violationLevelService.getById(levelId); + violationRecordVo.setLevelVo(violationLevelService.getVo(level)); + } + // 关联识别记录 + Long recognizeId = violationRecord.getRecognizeId(); + if (ObjectUtils.isNotEmpty(recognizeId)) { + HseRecognizeRecord recognizeRecord = recognizeRecordService.getById(recognizeId); + violationRecordVo.setRecognizeVo(recognizeRecordService.getVo(recognizeRecord)); + } + // 关联违章人信息 + Long handlerId = violationRecord.getHandlerId(); + if (ObjectUtils.isNotEmpty(handlerId)) { + SysUserVo handler = userService.selectUserById(handlerId); + violationRecordVo.setHandlerName(handler.getNickName()); + } + return violationRecordVo; + } + + /** + * 获取违规记录查询条件封装 + * + * @param req 违规记录查询条件 + * @return 违规记录查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(HseViolationRecordQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long id = req.getId(); + Long projectId = req.getProjectId(); + String violationType = req.getViolationType(); + Date violationTime = req.getViolationTime(); + lqw.eq(ObjectUtils.isNotEmpty(id), HseViolationRecord::getId, id); + lqw.eq(ObjectUtils.isNotEmpty(projectId), HseViolationRecord::getProjectId, projectId); + lqw.eq(StringUtils.isNotBlank(violationType), HseViolationRecord::getViolationType, violationType); + if (violationTime != null) { + // 构造当天的起始和结束时间 + LocalDate localDate = violationTime.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + LocalDateTime startOfDay = localDate.atStartOfDay(); + LocalDateTime startOfNextDay = localDate.plusDays(1).atStartOfDay(); + Date start = Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()); + Date end = Date.from(startOfNextDay.atZone(ZoneId.systemDefault()).toInstant()); + lqw.ge(HseViolationRecord::getViolationTime, start) + .lt(HseViolationRecord::getViolationTime, end); + } + return lqw; + } + + /** + * 获取违规记录分页对象视图 + * + * @param violationRecordPage 违规记录分页对象 + * @return 违规记录分页对象视图 + */ + @Override + public Page getVoPage(Page violationRecordPage) { + List violationRecordList = violationRecordPage.getRecords(); + Page violationRecordVoPage = new Page<>( + violationRecordPage.getCurrent(), + violationRecordPage.getSize(), + violationRecordPage.getTotal()); + if (CollUtil.isEmpty(violationRecordList)) { + return violationRecordVoPage; + } + // 关联等级 + Set levelIds = violationRecordList.stream().map(HseViolationRecord::getLevelId).collect(Collectors.toSet()); + Map levelIdLevelMap = violationLevelService.listByIds(levelIds).stream() + .collect(Collectors.toMap(HseViolationLevel::getId, level -> level)); + // 关联识别记录 + Set recognizeIds = violationRecordList.stream().map(HseViolationRecord::getRecognizeId).collect(Collectors.toSet()); + Map recognizeIdRecognizeMap = recognizeRecordService.listByIds(recognizeIds).stream() + .collect(Collectors.toMap(HseRecognizeRecord::getId, recognize -> recognize)); + // 关联违章人信息 + List handlerIds = violationRecordList.stream().map(HseViolationRecord::getHandlerId).distinct().toList(); + Map handlerIdUserMap = userService.selectUserByIds(handlerIds, null).stream() + .collect(Collectors.toMap(SysUserVo::getUserId, user -> user)); + List violationRecordVoList = violationRecordList.stream().map(violationLevel -> { + HseViolationRecordVo vo = new HseViolationRecordVo(); + BeanUtils.copyProperties(violationLevel, vo); + // 关联等级 + if (CollUtil.isNotEmpty(levelIdLevelMap) && levelIdLevelMap.containsKey(violationLevel.getLevelId())) { + vo.setLevelVo(violationLevelService.getVo(levelIdLevelMap.get(violationLevel.getLevelId()))); + } + // 关联识别记录 + if (CollUtil.isNotEmpty(recognizeIdRecognizeMap) && recognizeIdRecognizeMap.containsKey(violationLevel.getRecognizeId())) { + vo.setRecognizeVo(recognizeRecordService.getVo(recognizeIdRecognizeMap.get(violationLevel.getRecognizeId()))); + } + // 违章人信息 + if (CollUtil.isNotEmpty(handlerIdUserMap) && handlerIdUserMap.containsKey(violationLevel.getHandlerId())) { + vo.setHandlerName(handlerIdUserMap.get(violationLevel.getHandlerId()).getNickName()); + } + return vo; + }).toList(); + violationRecordVoPage.setRecords(violationRecordVoList); + return violationRecordVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java new file mode 100644 index 0000000..6b7499a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java @@ -0,0 +1,55 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.domain.vo.CacheListInfoVo; +import lombok.RequiredArgsConstructor; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 缓存监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/cache") +public class CacheController { + + private final RedissonConnectionFactory connectionFactory; + + /** + * 获取缓存监控列表 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping() + public R getInfo() throws Exception { + RedisConnection connection = connectionFactory.getConnection(); + Properties commandStats = connection.commands().info("commandstats"); + + List> pieList = new ArrayList<>(); + if (commandStats != null) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + } + + CacheListInfoVo infoVo = new CacheListInfoVo(); + infoVo.setInfo(connection.commands().info()); + infoVo.setDbSize(connection.commands().dbSize()); + infoVo.setCommandStats(pieList); + return R.ok(infoVo); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java new file mode 100644 index 0000000..98ac2d5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java @@ -0,0 +1,89 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysLogininforBo; +import org.dromara.system.domain.vo.SysLogininforVo; +import org.dromara.system.service.ISysLogininforService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 系统访问记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/logininfor") +public class SysLogininforController extends BaseController { + + private final ISysLogininforService logininforService; + + /** + * 获取系统访问记录列表 + */ + @SaCheckPermission("monitor:logininfor:list") + @GetMapping("/list") + public TableDataInfo list(SysLogininforBo logininfor, PageQuery pageQuery) { + return logininforService.selectPageLogininforList(logininfor, pageQuery); + } + + /** + * 导出系统访问记录列表 + */ + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:logininfor:export") + @PostMapping("/export") + public void export(SysLogininforBo logininfor, HttpServletResponse response) { + List list = logininforService.selectLogininforList(logininfor); + ExcelUtil.exportExcel(list, "登录日志", SysLogininforVo.class, response); + } + + /** + * 批量删除登录日志 + * @param infoIds 日志ids + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public R remove(@PathVariable Long[] infoIds) { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + + /** + * 清理系统访问记录 + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public R clean() { + logininforService.cleanLogininfor(); + return R.ok(); + } + + @SaCheckPermission("monitor:logininfor:unlock") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public R unlock(@PathVariable("userName") String userName) { + String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName; + if (RedisUtils.hasKey(loginName)) { + RedisUtils.deleteObject(loginName); + } + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java new file mode 100644 index 0000000..575aba6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java @@ -0,0 +1,75 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; +import org.dromara.system.service.ISysOperLogService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 操作日志记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController { + + private final ISysOperLogService operLogService; + + /** + * 获取操作日志记录列表 + */ + @SaCheckPermission("monitor:operlog:list") + @GetMapping("/list") + public TableDataInfo list(SysOperLogBo operLog, PageQuery pageQuery) { + return operLogService.selectPageOperLogList(operLog, pageQuery); + } + + /** + * 导出操作日志记录列表 + */ + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:operlog:export") + @PostMapping("/export") + public void export(SysOperLogBo operLog, HttpServletResponse response) { + List list = operLogService.selectOperLogList(operLog); + ExcelUtil.exportExcel(list, "操作日志", SysOperLogVo.class, response); + } + + /** + * 批量删除操作日志记录 + * @param operIds 日志ids + */ + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/{operIds}") + public R remove(@PathVariable Long[] operIds) { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + /** + * 清理操作日志记录 + */ + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/clean") + public R clean() { + operLogService.cleanOperLog(); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000..1cab232 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,131 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.dto.UserOnlineDTO; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysUserOnline; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 在线用户监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController { + + /** + * 获取在线用户监控列表 + * + * @param ipaddr IP地址 + * @param userName 用户名 + */ + @SaCheckPermission("monitor:online:list") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) { + // 获取所有未过期的 token + Collection keys = RedisUtils.keys(CacheConstants.ONLINE_TOKEN_KEY + "*"); + List userOnlineDTOList = new ArrayList<>(); + for (String key : keys) { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + continue; + } + userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)); + } + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) && + StringUtils.equals(userName, userOnline.getUserName()) + ); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) + ); + } else if (StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(userName, userOnline.getUserName()) + ); + } + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + + /** + * 强退用户 + * + * @param tokenId token值 + */ + @SaCheckPermission("monitor:online:forceLogout") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public R forceLogout(@PathVariable String tokenId) { + try { + StpUtil.kickoutByTokenValue(tokenId); + } catch (NotLoginException ignored) { + } + return R.ok(); + } + + /** + * 获取当前用户登录在线设备 + */ + @GetMapping() + public TableDataInfo getInfo() { + // 获取指定账号 id 的 token 集合 + List tokenIds = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + List userOnlineDTOList = tokenIds.stream() + .filter(token -> StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) >= -1) + .map(token -> (UserOnlineDTO) RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)) + .collect(Collectors.toList()); + //复制和处理 SysUserOnline 对象列表 + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + + /** + * 强退当前在线设备 + * + * @param tokenId token值 + */ + @Log(title = "在线设备", businessType = BusinessType.FORCE) + @DeleteMapping("/myself/{tokenId}") + public R remove(@PathVariable("tokenId") String tokenId) { + try { + // 获取指定账号 id 的 token 集合 + List keys = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + keys.stream() + .filter(key -> key.equals(tokenId)) + .findFirst() + .ifPresent(key -> StpUtil.kickoutByTokenValue(tokenId)); + } catch (NotLoginException ignored) { + } + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java new file mode 100644 index 0000000..eaed068 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java @@ -0,0 +1,115 @@ +package org.dromara.system.controller.system; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.system.service.ISysClientService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 客户端管理 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/client") +public class SysClientController extends BaseController { + + private final ISysClientService sysClientService; + + /** + * 查询客户端管理列表 + */ + @SaCheckPermission("system:client:list") + @GetMapping("/list") + public TableDataInfo list(SysClientBo bo, PageQuery pageQuery) { + return sysClientService.queryPageList(bo, pageQuery); + } + + /** + * 导出客户端管理列表 + */ + @SaCheckPermission("system:client:export") + @Log(title = "客户端管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysClientBo bo, HttpServletResponse response) { + List list = sysClientService.queryList(bo); + ExcelUtil.exportExcel(list, "客户端管理", SysClientVo.class, response); + } + + /** + * 获取客户端管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:client:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(sysClientService.queryById(id)); + } + + /** + * 新增客户端管理 + */ + @SaCheckPermission("system:client:add") + @Log(title = "客户端管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysClientBo bo) { + return toAjax(sysClientService.insertByBo(bo)); + } + + /** + * 修改客户端管理 + */ + @SaCheckPermission("system:client:edit") + @Log(title = "客户端管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysClientBo bo) { + return toAjax(sysClientService.updateByBo(bo)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:client:edit") + @Log(title = "客户端管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysClientBo bo) { + return toAjax(sysClientService.updateClientStatus(bo.getClientId(), bo.getStatus())); + } + + /** + * 删除客户端管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:client:remove") + @Log(title = "客户端管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(sysClientService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java new file mode 100644 index 0000000..c73c386 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java @@ -0,0 +1,137 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; +import org.dromara.system.service.ISysConfigService; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 参数配置 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController { + + private final ISysConfigService configService; + + /** + * 获取参数配置列表 + */ + @SaCheckPermission("system:config:list") + @GetMapping("/list") + public TableDataInfo list(SysConfigBo config, PageQuery pageQuery) { + return configService.selectPageConfigList(config, pageQuery); + } + + /** + * 导出参数配置列表 + */ + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:config:export") + @PostMapping("/export") + public void export(SysConfigBo config, HttpServletResponse response) { + List list = configService.selectConfigList(config); + ExcelUtil.exportExcel(list, "参数数据", SysConfigVo.class, response); + } + + /** + * 根据参数编号获取详细信息 + * + * @param configId 参数ID + */ + @SaCheckPermission("system:config:query") + @GetMapping(value = "/{configId}") + public R getInfo(@PathVariable Long configId) { + return R.ok(configService.selectConfigById(configId)); + } + + /** + * 根据参数键名查询参数值 + * + * @param configKey 参数Key + */ + @GetMapping(value = "/configKey/{configKey}") + public R getConfigKey(@PathVariable String configKey) { + return R.ok("操作成功", configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置 + */ + @SaCheckPermission("system:config:add") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysConfigBo config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.insertConfig(config); + return R.ok(); + } + + /** + * 修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysConfigBo config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.updateConfig(config); + return R.ok(); + } + + /** + * 根据参数键名修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping("/updateByKey") + public R updateByKey(@RequestBody SysConfigBo config) { + configService.updateConfig(config); + return R.ok(); + } + + /** + * 删除参数配置 + * + * @param configIds 参数ID串 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public R remove(@PathVariable Long[] configIds) { + configService.deleteConfigByIds(configIds); + return R.ok(); + } + + /** + * 刷新参数缓存 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + configService.resetConfigCache(); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java new file mode 100644 index 0000000..bc30bb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java @@ -0,0 +1,163 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysPostService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 部门信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController { + + private final ISysDeptService deptService; + private final ISysPostService postService; + + /** + * 获取部门列表 + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list") + public R> list(SysDeptBo dept) { + List depts = deptService.selectDeptList(dept); + return R.ok(depts); + } + + /** + * 查询部门列表(排除节点) + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list/exclude/{deptId}") + public R> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) { + List depts = deptService.selectDeptList(new SysDeptBo()); + depts.removeIf(d -> d.getDeptId().equals(deptId) + || StringUtils.splitList(d.getAncestors()).contains(Convert.toStr(deptId))); + return R.ok(depts); + } + + /** + * 根据项目id获取部门树以及岗位列表 + */ + @SaCheckPermission("system:dept:treeByProjectId") + @GetMapping("/list/treeByProjectId/{projectId}") + public R>> listTreeByProjectId(@PathVariable Long projectId) { + List> tree = deptService.buildDeptTreeByProjectId(projectId); + return R.ok(tree); + } + + /** + * 根据部门编号获取详细信息 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:query") + @GetMapping(value = "/{deptId}") + public R getInfo(@PathVariable Long deptId) { + deptService.checkDeptDataScope(deptId); + return R.ok(deptService.selectDeptById(deptId)); + } + +// /** +// * 根据部门编号获取详细信息 +// * +// */ +// @SaCheckPermission("system:dept:informationRetrieval") +// @GetMapping(value = "informationRetrieval") +// public R getInfo(SysDeptBo dept) { +// deptService.checkDeptDataScope(dept.getDeptId()); +// return R.ok(deptService.selectDeptByIdBo(dept)); +// } + + + /** + * 新增部门 + */ + @SaCheckPermission("system:dept:add") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDeptBo dept) { + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门 + */ + @SaCheckPermission("system:dept:edit") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDeptBo dept) { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } else if (dept.getParentId().equals(deptId)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } else if (StringUtils.equals(SystemConstants.DISABLE, dept.getStatus())) { + if (deptService.selectNormalChildrenDeptById(deptId) > 0) { + return R.fail("该部门包含未停用的子部门!"); + } else if (deptService.checkDeptExistUser(deptId)) { + return R.fail("该部门下存在已分配用户,不能禁用!"); + } + } + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:remove") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public R remove(@PathVariable Long deptId) { + if (deptService.hasChildByDeptId(deptId)) { + return R.warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) { + return R.warn("部门存在用户,不允许删除"); + } + if (postService.countPostByDeptId(deptId) > 0) { + return R.warn("部门存在岗位,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } + + /** + * 获取部门选择框列表 + * + * @param deptIds 部门ID串 + */ + @SaCheckPermission("system:dept:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] deptIds) { + return R.ok(deptService.selectDeptByIds(deptIds == null ? null : List.of(deptIds))); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java new file mode 100644 index 0000000..5752751 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java @@ -0,0 +1,123 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.system.service.ISysDictTypeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController { + + private final ISysDictDataService dictDataService; + private final ISysDictTypeService dictTypeService; + + /** + * 查询字典数据列表 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictDataBo dictData, PageQuery pageQuery) { + return dictDataService.selectPageDictDataList(dictData, pageQuery); + } + + /** + * 导出字典数据列表 + */ + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictDataBo dictData, HttpServletResponse response) { + List list = dictDataService.selectDictDataList(dictData); + ExcelUtil.exportExcel(list, "字典数据", SysDictDataVo.class, response); + } + + /** + * 查询字典数据详细 + * + * @param dictCode 字典code + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictCode}") + public R getInfo(@PathVariable Long dictCode) { + return R.ok(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 根据字典类型查询字典数据信息 + * + * @param dictType 字典类型 + */ + @GetMapping(value = "/type/{dictType}") + public R> dictType(@PathVariable String dictType) { + List data = dictTypeService.selectDictDataByType(dictType); + if (ObjectUtil.isNull(data)) { + data = new ArrayList<>(); + } + return R.ok(data); + } + + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictDataBo dict) { + if (!dictDataService.checkDictDataUnique(dict)) { + return R.fail("新增字典数据'" + dict.getDictValue() + "'失败,字典键值已存在"); + } + dictDataService.insertDictData(dict); + return R.ok(); + } + + /** + * 修改保存字典类型 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictDataBo dict) { + if (!dictDataService.checkDictDataUnique(dict)) { + return R.fail("修改字典数据'" + dict.getDictValue() + "'失败,字典键值已存在"); + } + dictDataService.updateDictData(dict); + return R.ok(); + } + + /** + * 删除字典类型 + * + * @param dictCodes 字典code串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public R remove(@PathVariable Long[] dictCodes) { + dictDataService.deleteDictDataByIds(dictCodes); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java new file mode 100644 index 0000000..67c1f51 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java @@ -0,0 +1,125 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictTypeVo; +import org.dromara.system.service.ISysDictTypeService; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController { + + private final ISysDictTypeService dictTypeService; + + /** + * 查询字典类型列表 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictTypeBo dictType, PageQuery pageQuery) { + return dictTypeService.selectPageDictTypeList(dictType, pageQuery); + } + + /** + * 导出字典类型列表 + */ + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictTypeBo dictType, HttpServletResponse response) { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil.exportExcel(list, "字典类型", SysDictTypeVo.class, response); + } + + /** + * 查询字典类型详细 + * + * @param dictId 字典ID + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictId}") + public R getInfo(@PathVariable Long dictId) { + return R.ok(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictTypeBo dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.insertDictType(dict); + return R.ok(); + } + + /** + * 修改字典类型 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictTypeBo dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.updateDictType(dict); + return R.ok(); + } + + /** + * 删除字典类型 + * + * @param dictIds 字典ID串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public R remove(@PathVariable Long[] dictIds) { + dictTypeService.deleteDictTypeByIds(dictIds); + return R.ok(); + } + + /** + * 刷新字典缓存 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + dictTypeService.resetDictCache(); + return R.ok(); + } + + /** + * 获取字典选择框列表 + */ + @GetMapping("/optionselect") + public R> optionselect() { + List dictTypes = dictTypeService.selectDictTypeAll(); + return R.ok(dictTypes); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java new file mode 100644 index 0000000..d8cd335 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java @@ -0,0 +1,174 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.annotation.SaMode; +import cn.hutool.core.lang.tree.Tree; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.MenuTreeSelectVo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; +import org.dromara.system.service.ISysMenuService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 菜单信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + + private final ISysMenuService menuService; + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("/getRouters") + public R> getRouters() { + List menus = menuService.selectMenuTreeByUserId(LoginHelper.getUserId()); + return R.ok(menuService.buildMenus(menus)); + } + + /** + * 获取菜单列表 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + TenantConstants.TENANT_ADMIN_ROLE_KEY + }, mode = SaMode.OR) + @SaCheckPermission("system:menu:list") + @GetMapping("/list") + public R> list(SysMenuBo menu) { + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); + return R.ok(menus); + } + + /** + * 根据菜单编号获取详细信息 + * + * @param menuId 菜单ID + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + TenantConstants.TENANT_ADMIN_ROLE_KEY + }, mode = SaMode.OR) + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/{menuId}") + public R getInfo(@PathVariable Long menuId) { + return R.ok(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表 + */ + @SaCheckPermission("system:menu:query") + @GetMapping("/treeselect") + public R>> treeselect(SysMenuBo menu) { + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); + return R.ok(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public R roleMenuTreeselect(@PathVariable("roleId") Long roleId) { + List menus = menuService.selectMenuList(LoginHelper.getUserId()); + MenuTreeSelectVo selectVo = new MenuTreeSelectVo(); + selectVo.setCheckedKeys(menuService.selectMenuListByRoleId(roleId)); + selectVo.setMenus(menuService.buildMenuTreeSelect(menus)); + return R.ok(selectVo); + } + + /** + * 加载对应租户套餐菜单列表树 + * + * @param packageId 租户套餐ID + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/tenantPackageMenuTreeselect/{packageId}") + public R tenantPackageMenuTreeselect(@PathVariable("packageId") Long packageId) { + List menus = menuService.selectMenuList(LoginHelper.getUserId()); + MenuTreeSelectVo selectVo = new MenuTreeSelectVo(); + selectVo.setCheckedKeys(menuService.selectMenuListByPackageId(packageId)); + selectVo.setMenus(menuService.buildMenuTreeSelect(menus)); + return R.ok(selectVo); + } + + /** + * 新增菜单 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:add") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysMenuBo menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:edit") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysMenuBo menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (menu.getMenuId().equals(menu.getParentId())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + * + * @param menuId 菜单ID + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:remove") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public R remove(@PathVariable("menuId") Long menuId) { + if (menuService.hasChildByMenuId(menuId)) { + return R.warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) { + return R.warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java new file mode 100644 index 0000000..5d65137 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java @@ -0,0 +1,90 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.service.DictService; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; +import org.dromara.system.service.ISysNoticeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 公告 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController { + + private final ISysNoticeService noticeService; + private final DictService dictService; + + /** + * 获取通知公告列表 + */ + @SaCheckPermission("system:notice:list") + @GetMapping("/list") + public TableDataInfo list(SysNoticeBo notice, PageQuery pageQuery) { + return noticeService.selectPageNoticeList(notice, pageQuery); + } + + /** + * 根据通知公告编号获取详细信息 + * + * @param noticeId 公告ID + */ + @SaCheckPermission("system:notice:query") + @GetMapping(value = "/{noticeId}") + public R getInfo(@PathVariable Long noticeId) { + return R.ok(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告 + */ + @SaCheckPermission("system:notice:add") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysNoticeBo notice) { + int rows = noticeService.insertNotice(notice); + if (rows <= 0) { + return R.fail(); + } + String type = dictService.getDictLabel("sys_notice_type", notice.getNoticeType()); + SseMessageUtils.publishAll("[" + type + "] " + notice.getNoticeTitle()); + return R.ok(); + } + + /** + * 修改通知公告 + */ + @SaCheckPermission("system:notice:edit") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysNoticeBo notice) { + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + * + * @param noticeIds 公告ID串 + */ + @SaCheckPermission("system:notice:remove") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public R remove(@PathVariable Long[] noticeIds) { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java new file mode 100644 index 0000000..24ddaff --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java @@ -0,0 +1,105 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; +import org.dromara.system.service.ISysOssConfigService; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 对象存储配置 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/resource/oss/config") +public class SysOssConfigController extends BaseController { + + private final ISysOssConfigService ossConfigService; + + /** + * 查询对象存储配置列表 + */ + @SaCheckPermission("system:ossConfig:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) { + return ossConfigService.queryPageList(bo, pageQuery); + } + + /** + * 获取对象存储配置详细信息 + * + * @param ossConfigId OSS配置ID + */ + @SaCheckPermission("system:ossConfig:list") + @GetMapping("/{ossConfigId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long ossConfigId) { + return R.ok(ossConfigService.queryById(ossConfigId)); + } + + /** + * 新增对象存储配置 + */ + @SaCheckPermission("system:ossConfig:add") + @Log(title = "对象存储配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.insertByBo(bo)); + } + + /** + * 修改对象存储配置 + */ + @SaCheckPermission("system:ossConfig:edit") + @Log(title = "对象存储配置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.updateByBo(bo)); + } + + /** + * 删除对象存储配置 + * + * @param ossConfigIds OSS配置ID串 + */ + @SaCheckPermission("system:ossConfig:remove") + @Log(title = "对象存储配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossConfigIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossConfigIds) { + return toAjax(ossConfigService.deleteWithValidByIds(List.of(ossConfigIds), true)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:ossConfig:edit") + @Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.updateOssConfigStatus(bo)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java new file mode 100644 index 0000000..b8aea77 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java @@ -0,0 +1,124 @@ +package org.dromara.system.controller.system; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +/** + * 文件上传 控制层 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/resource/oss") +public class SysOssController extends BaseController { + + private final ISysOssService ossService; + + /** + * 查询OSS对象存储列表 + */ + @SaCheckPermission("system:oss:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) { + return ossService.queryPageList(bo, pageQuery); + } + + /** + * 查询OSS对象基于id串 + * + * @param ossIds OSS对象ID串 + */ + @SaCheckPermission("system:oss:query") + @GetMapping("/listByIds/{ossIds}") + public R> listByIds(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + List list = ossService.listByIds(Arrays.asList(ossIds)); + return R.ok(list); + } + + /** + * 上传OSS对象存储 + * + * @param file 文件 + */ + @SaCheckPermission("system:oss:upload") + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) + @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R upload(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + SysOssVo oss = ossService.upload(file); + SysOssUploadVo uploadVo = new SysOssUploadVo(); + uploadVo.setUrl(oss.getUrl()); + uploadVo.setFileName(oss.getOriginalName()); + uploadVo.setOssId(oss.getOssId().toString()); + return R.ok(uploadVo); + } + + /** + * 上传OSS对象存储(不自动保存数据) + * + * @param file 文件 + */ + @SaCheckPermission("system:oss:upload") + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) + @PostMapping(value = "/upload/vo", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R uploadWithNoSave(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + SysOssUploadVo uploadVo = ossService.uploadWithNoSave(file); + return R.ok(uploadVo); + } + + /** + * 下载OSS对象 + * + * @param ossId OSS对象ID + */ + @SaCheckPermission("system:oss:download") + @GetMapping("/download/{ossId}") + public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException { + ossService.download(ossId, response); + } + + /** + * 删除OSS对象存储 + * + * @param ossIds OSS对象ID串 + */ + @SaCheckPermission("system:oss:remove") + @Log(title = "OSS对象存储", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + return toAjax(ossService.deleteWithValidByIds(List.of(ossIds), true)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java new file mode 100644 index 0000000..5333a4a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java @@ -0,0 +1,133 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.service.ISysPostService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController { + + private final ISysPostService postService; + + /** + * 获取岗位列表 + */ + @SaCheckPermission("system:post:list") + @GetMapping("/list") + public TableDataInfo list(SysPostBo post, PageQuery pageQuery) { + return postService.selectPagePostList(post, pageQuery); + } + + /** + * 导出岗位列表 + */ + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:post:export") + @PostMapping("/export") + public void export(SysPostBo post, HttpServletResponse response) { + List list = postService.selectPostList(post); + ExcelUtil.exportExcel(list, "岗位数据", SysPostVo.class, response); + } + + /** + * 根据岗位编号获取详细信息 + * + * @param postId 岗位ID + */ + @SaCheckPermission("system:post:query") + @GetMapping(value = "/{postId}") + public R getInfo(@PathVariable Long postId) { + return R.ok(postService.selectPostById(postId)); + } + + /** + * 新增岗位 + */ + @SaCheckPermission("system:post:add") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysPostBo post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位 + */ + @SaCheckPermission("system:post:edit") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysPostBo post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } else if (SystemConstants.DISABLE.equals(post.getStatus()) + && postService.countUserPostById(post.getPostId()) > 0) { + return R.fail("该岗位下存在已分配用户,不能禁用!"); + } + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + * + * @param postIds 岗位ID串 + */ + @SaCheckPermission("system:post:remove") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public R remove(@PathVariable Long[] postIds) { + return toAjax(postService.deletePostByIds(postIds)); + } + + /** + * 获取岗位选择框列表 + * + * @param postIds 岗位ID串 + * @param deptId 部门id + */ + @SaCheckPermission("system:post:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] postIds, @RequestParam(required = false) Long deptId) { + List list = new ArrayList<>(); + if (ObjectUtil.isNotNull(deptId)) { + SysPostBo post = new SysPostBo(); + post.setDeptId(deptId); + list = postService.selectPostList(post); + } else if (postIds != null) { + list = postService.selectPostByIds(List.of(postIds)); + } + return R.ok(list); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java new file mode 100644 index 0000000..5f187cb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java @@ -0,0 +1,133 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.io.FileUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.MimeTypeUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.bo.SysUserPasswordBo; +import org.dromara.system.domain.bo.SysUserProfileBo; +import org.dromara.system.domain.vo.AvatarVo; +import org.dromara.system.domain.vo.ProfileVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysUserService; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Arrays; + +/** + * 个人信息 业务处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController { + + private final ISysUserService userService; + private final ISysOssService ossService; + + /** + * 个人信息 + */ + @GetMapping + public R profile() { + SysUserVo user = userService.selectUserById(LoginHelper.getUserId()); + ProfileVo profileVo = new ProfileVo(); + profileVo.setUser(user); + profileVo.setRoleGroup(userService.selectUserRoleGroup(user.getUserId())); + profileVo.setPostGroup(userService.selectUserPostGroup(user.getUserId())); + return R.ok(profileVo); + } + + /** + * 修改用户信息 + */ + @RepeatSubmit + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public R updateProfile(@Validated @RequestBody SysUserProfileBo profile) { + SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class); + user.setUserId(LoginHelper.getUserId()); + String username = LoginHelper.getUsername(); + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + username + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + username + "'失败,邮箱账号已存在"); + } + int rows = DataPermissionHelper.ignore(() -> userService.updateUserProfile(user)); + if (rows > 0) { + return R.ok(); + } + return R.fail("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + * + * @param bo 新旧密码 + */ + @RepeatSubmit + @ApiEncrypt + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public R updatePwd(@Validated @RequestBody SysUserPasswordBo bo) { + SysUserVo user = userService.selectUserById(LoginHelper.getUserId()); + String password = user.getPassword(); + if (!BCrypt.checkpw(bo.getOldPassword(), password)) { + return R.fail("修改密码失败,旧密码错误"); + } + if (BCrypt.checkpw(bo.getNewPassword(), password)) { + return R.fail("新密码不能与旧密码相同"); + } + int rows = DataPermissionHelper.ignore(() -> userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(bo.getNewPassword()))); + if (rows > 0) { + return R.ok(); + } + return R.fail("修改密码异常,请联系管理员"); + } + + /** + * 头像上传 + * + * @param avatarfile 用户头像 + */ + @RepeatSubmit + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R avatar(@RequestPart("avatarfile") MultipartFile avatarfile) { + if (!avatarfile.isEmpty()) { + String extension = FileUtil.extName(avatarfile.getOriginalFilename()); + if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) { + return R.fail("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式"); + } + SysOssVo oss = ossService.upload(avatarfile); + String avatar = oss.getUrl(); + boolean updateSuccess = DataPermissionHelper.ignore(() -> userService.updateUserAvatar(LoginHelper.getUserId(), oss.getOssId())); + if (updateSuccess) { + AvatarVo avatarVo = new AvatarVo(); + avatarVo.setImgUrl(avatar); + return R.ok(avatarVo); + } + } + return R.fail("上传图片异常,请联系管理员"); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java new file mode 100644 index 0000000..ecf97b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java @@ -0,0 +1,259 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.DeptTreeSelectVo; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysRoleService; +import org.dromara.system.service.ISysUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 角色信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController { + + private final ISysRoleService roleService; + private final ISysUserService userService; + private final ISysDeptService deptService; + + /** + * 获取角色信息列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/list") + public TableDataInfo list(SysRoleBo role, PageQuery pageQuery) { + return roleService.selectPageRoleList(role, pageQuery); + } + + /** + * 获取角色信息列表(不分页) + */ + @SaCheckPermission("system:role:list") + @GetMapping("/listNoPage") + public R> listNoPage(SysRoleBo role) { + return R.ok(roleService.selectRoleList(role)); + } + + /** + * 导出角色信息列表 + */ + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:role:export") + @PostMapping("/export") + public void export(SysRoleBo role, HttpServletResponse response) { + List list = roleService.selectRoleList(role); + ExcelUtil.exportExcel(list, "角色数据", SysRoleVo.class, response); + } + + /** + * 根据角色编号获取详细信息 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:query") + @GetMapping(value = "/{roleId}") + public R getInfo(@PathVariable Long roleId) { + roleService.checkRoleDataScope(roleId); + return R.ok(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色 + */ + @SaCheckPermission("system:role:add") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + Long deptId = role.getDeptId(); + if (deptId == null) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,请选择关联的部门"); + } + SysDeptVo deptVo = deptService.selectDeptById(deptId); + if (deptVo == null) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,关联的部门不存在"); + } + if (deptVo.getParentId() == 0) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,关联的部门不能为顶级部门"); + } + return toAjax(roleService.insertRole(role)); + } + + /** + * 修改保存角色 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + Long deptId = role.getDeptId(); + if (deptId == null) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,请选择关联的部门"); + } + SysDeptVo deptVo = deptService.selectDeptById(deptId); + if (deptVo == null) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,关联的部门不存在"); + } + if (deptVo.getParentId() == 0) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,关联的部门不能为顶级部门"); + } + if (roleService.updateRole(role) > 0) { + roleService.cleanOnlineUserByRole(role.getRoleId()); + return R.ok(); + } + return R.fail("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + + /** + * 修改保存数据权限 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public R dataScope(@RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.updateRoleStatus(role.getRoleId(), role.getStatus())); + } + + /** + * 删除角色 + * + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:role:remove") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public R remove(@PathVariable Long[] roleIds) { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + + /** + * 获取角色选择框列表 + * + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:role:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] roleIds) { + return R.ok(roleService.selectRoleByIds(roleIds == null ? null : List.of(roleIds))); + } + + /** + * 查询已分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUserBo user, PageQuery pageQuery) { + return userService.selectAllocatedList(user, pageQuery); + } + + /** + * 查询未分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUserBo user, PageQuery pageQuery) { + return userService.selectUnallocatedList(user, pageQuery); + } + + /** + * 取消授权用户 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public R cancelAuthUser(@RequestBody SysUserRole userRole) { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public R cancelAuthUserAll(Long roleId, Long[] userIds) { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 批量选择用户授权 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public R selectAuthUserAll(Long roleId, Long[] userIds) { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + + /** + * 获取对应角色部门树列表 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:list") + @GetMapping(value = "/deptTree/{roleId}") + public R roleDeptTreeselect(@PathVariable("roleId") Long roleId) { + DeptTreeSelectVo selectVo = new DeptTreeSelectVo(); + selectVo.setCheckedKeys(deptService.selectDeptListByRoleId(roleId)); + selectVo.setDepts(deptService.selectDeptTreeList(new SysDeptBo())); + return R.ok(selectVo); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java new file mode 100644 index 0000000..b0281cf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java @@ -0,0 +1,38 @@ +package org.dromara.system.controller.system; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.service.ISysSocialService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 社会化关系 + * + * @author thiszhc + * @date 2023-06-16 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/social") +public class SysSocialController extends BaseController { + + private final ISysSocialService socialUserService; + + /** + * 查询社会化关系列表 + */ + @GetMapping("/list") + public R> list() { + return R.ok(socialUserService.queryListByUserId(LoginHelper.getUserId())); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java new file mode 100644 index 0000000..66c1b7d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java @@ -0,0 +1,193 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import com.baomidou.lock.annotation.Lock4j; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.service.ISysTenantService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 租户管理 + * + * @author Michelle.Chung + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/tenant") +@ConditionalOnProperty(value = "tenant.enable", havingValue = "true") +public class SysTenantController extends BaseController { + + private final ISysTenantService tenantService; + + /** + * 查询租户列表 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:list") + @GetMapping("/list") + public TableDataInfo list(SysTenantBo bo, PageQuery pageQuery) { + return tenantService.queryPageList(bo, pageQuery); + } + + /** + * 导出租户列表 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:export") + @Log(title = "租户管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysTenantBo bo, HttpServletResponse response) { + List list = tenantService.queryList(bo); + ExcelUtil.exportExcel(list, "租户", SysTenantVo.class, response); + } + + /** + * 获取租户详细信息 + * + * @param id 主键 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tenantService.queryById(id)); + } + + /** + * 新增租户 + */ + @ApiEncrypt + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:add") + @Log(title = "租户管理", businessType = BusinessType.INSERT) + @Lock4j + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysTenantBo bo) { + if (!tenantService.checkCompanyNameUnique(bo)) { + return R.fail("新增租户'" + bo.getCompanyName() + "'失败,企业名称已存在"); + } + return toAjax(TenantHelper.ignore(() -> tenantService.insertByBo(bo))); + } + + /** + * 修改租户 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:edit") + @Log(title = "租户管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysTenantBo bo) { + tenantService.checkTenantAllowed(bo.getTenantId()); + if (!tenantService.checkCompanyNameUnique(bo)) { + return R.fail("修改租户'" + bo.getCompanyName() + "'失败,公司名称已存在"); + } + return toAjax(tenantService.updateByBo(bo)); + } + + /** + * 状态修改 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:edit") + @Log(title = "租户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysTenantBo bo) { + tenantService.checkTenantAllowed(bo.getTenantId()); + return toAjax(tenantService.updateTenantStatus(bo)); + } + + /** + * 删除租户 + * + * @param ids 主键串 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:remove") + @Log(title = "租户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tenantService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 动态切换租户 + * + * @param tenantId 租户ID + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @GetMapping("/dynamic/{tenantId}") + public R dynamicTenant(@NotBlank(message = "租户ID不能为空") @PathVariable String tenantId) { + TenantHelper.setDynamic(tenantId, true); + return R.ok(); + } + + /** + * 清除动态租户 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @GetMapping("/dynamic/clear") + public R dynamicClear() { + TenantHelper.clearDynamic(); + return R.ok(); + } + + + /** + * 同步租户套餐 + * + * @param tenantId 租户id + * @param packageId 套餐id + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenant:edit") + @Log(title = "租户管理", businessType = BusinessType.UPDATE) + @GetMapping("/syncTenantPackage") + public R syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId, + @NotNull(message = "套餐ID不能为空") Long packageId) { + return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId))); + } + + /** + * 同步租户字典 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @Log(title = "租户管理", businessType = BusinessType.INSERT) + @GetMapping("/syncTenantDict") + public R syncTenantDict() { + if (!TenantHelper.isEnable()) { + return R.fail("当前未开启租户模式"); + } + tenantService.syncTenantDict(); + return R.ok("同步租户字典成功"); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java new file mode 100644 index 0000000..4bfe597 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java @@ -0,0 +1,142 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysTenantPackageBo; +import org.dromara.system.domain.vo.SysTenantPackageVo; +import org.dromara.system.service.ISysTenantPackageService; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 租户套餐管理 + * + * @author Michelle.Chung + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/tenant/package") +@ConditionalOnProperty(value = "tenant.enable", havingValue = "true") +public class SysTenantPackageController extends BaseController { + + private final ISysTenantPackageService tenantPackageService; + + /** + * 查询租户套餐列表 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:list") + @GetMapping("/list") + public TableDataInfo list(SysTenantPackageBo bo, PageQuery pageQuery) { + return tenantPackageService.queryPageList(bo, pageQuery); + } + + /** + * 查询租户套餐下拉选列表 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:list") + @GetMapping("/selectList") + public R> selectList() { + return R.ok(tenantPackageService.selectList()); + } + + /** + * 导出租户套餐列表 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:export") + @Log(title = "租户套餐", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysTenantPackageBo bo, HttpServletResponse response) { + List list = tenantPackageService.queryList(bo); + ExcelUtil.exportExcel(list, "租户套餐", SysTenantPackageVo.class, response); + } + + /** + * 获取租户套餐详细信息 + * + * @param packageId 主键 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:query") + @GetMapping("/{packageId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long packageId) { + return R.ok(tenantPackageService.queryById(packageId)); + } + + /** + * 新增租户套餐 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:add") + @Log(title = "租户套餐", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) { + if (!tenantPackageService.checkPackageNameUnique(bo)) { + return R.fail("新增套餐'" + bo.getPackageName() + "'失败,套餐名称已存在"); + } + return toAjax(tenantPackageService.insertByBo(bo)); + } + + /** + * 修改租户套餐 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:edit") + @Log(title = "租户套餐", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) { + if (!tenantPackageService.checkPackageNameUnique(bo)) { + return R.fail("修改套餐'" + bo.getPackageName() + "'失败,套餐名称已存在"); + } + return toAjax(tenantPackageService.updateByBo(bo)); + } + + /** + * 状态修改 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:edit") + @Log(title = "租户套餐", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysTenantPackageBo bo) { + return toAjax(tenantPackageService.updatePackageStatus(bo)); + } + + /** + * 删除租户套餐 + * + * @param packageIds 主键串 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:tenantPackage:remove") + @Log(title = "租户套餐", businessType = BusinessType.DELETE) + @DeleteMapping("/{packageIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] packageIds) { + return toAjax(tenantPackageService.deleteWithValidByIds(List.of(packageIds), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java new file mode 100644 index 0000000..b467b2f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java @@ -0,0 +1,326 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.enums.SysDeptTypeEnum; +import org.dromara.system.domain.vo.*; +import org.dromara.system.listener.SysUserImportListener; +import org.dromara.system.service.*; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用户信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController { + + private final ISysUserService userService; + private final ISysRoleService roleService; + private final ISysPostService postService; + private final ISysDeptService deptService; + private final ISysTenantService tenantService; + private final ISubContractorService contractorService; + + /** + * 获取用户列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list") + public TableDataInfo list(SysUserBo user, PageQuery pageQuery) { + return userService.selectPageUserList(user, pageQuery); + } + + /** + * 导出用户列表 + */ + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:user:export") + @PostMapping("/export") + public void export(SysUserBo user, HttpServletResponse response) { + List list = userService.selectUserExportList(user); + ExcelUtil.exportExcel(list, "用户数据", SysUserExportVo.class, response); + } + + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:user:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { + ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport)); + return R.ok(result.getAnalysis()); + } + + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response); + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("/getInfo") + public R getInfo() { + UserInfoVo userInfoVo = new UserInfoVo(); + LoginUser loginUser = LoginHelper.getLoginUser(); + if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { + // 超级管理员 如果重新加载用户信息需清除动态租户 + TenantHelper.clearDynamic(); + } + SysUserVo user = userService.selectUserById(loginUser.getUserId()); + if (ObjectUtil.isNull(user)) { + return R.fail("没有权限访问用户数据!"); + } + userInfoVo.setUser(user); + userInfoVo.setPermissions(loginUser.getMenuPermission()); + userInfoVo.setRoles(loginUser.getRolePermission()); + Long deptId = user.getDeptId(); + if (ObjectUtil.isNotNull(deptId)) { + SysDeptVo deptVo = deptService.selectDeptById(deptId); + Long contractorId = deptVo.getContractorId(); + if (deptVo.getDeptType().equals(SysDeptTypeEnum.CONTRACT.getCode()) && ObjectUtil.isNotNull(contractorId)) { + userInfoVo.setContractorId(contractorId); + } + } + return R.ok(userInfoVo); + } + + /** + * 根据用户编号获取详细信息 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping(value = {"/", "/{userId}"}) + public R getInfo(@PathVariable(value = "userId", required = false) Long userId) { + SysUserInfoVo userInfoVo = new SysUserInfoVo(); + if (ObjectUtil.isNotNull(userId)) { + userService.checkUserDataScope(userId); + SysUserVo sysUser = userService.selectUserById(userId); + List roles = sysUser.getRoles(); + if (CollUtil.isNotEmpty(roles)) { + sysUser.setRoleIds(roles.stream().map(SysRoleVo::getRoleId).toList().toArray(Long[]::new)); + } + userInfoVo.setUser(sysUser); +// userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId)); + Long deptId = sysUser.getDeptId(); + if (ObjectUtil.isNotNull(deptId)) { + SysPostBo postBo = new SysPostBo(); + postBo.setDeptId(deptId); + userInfoVo.setPosts(postService.selectPostList(postBo)); + userInfoVo.setPostIds(postService.selectPostListByUserId(userId)); + SysRoleBo role = new SysRoleBo(); + role.setDeptId(deptId); + List roleVoList = roleService.selectRoleList(role); + userInfoVo.setRoles(roleVoList); + userInfoVo.setRoleIds(roleVoList.stream().map(SysRoleVo::getRoleId).toList()); + } + } + /*SysRoleBo roleBo = new SysRoleBo(); + roleBo.setStatus(SystemConstants.NORMAL); + List roles = roleService.selectRoleList(roleBo); + userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));*/ + return R.ok(userInfoVo); + } + + /** + * 新增用户 + */ + @SaCheckPermission("system:user:add") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysUserBo user) { + deptService.checkDeptDataScope(user.getDeptId()); + deptService.checkDeptMatchRole(user.getUserId(), List.of(user.getRoleIds())); + if (!userService.checkUserNameUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isEmpty(user.getPhonenumber())) { + return R.fail("新增用户'" + user.getUserName() + "'失败,手机号不能为空"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + if (TenantHelper.isEnable()) { + if (!tenantService.checkAccountBalance(TenantHelper.getTenantId())) { + return R.fail("当前租户下用户名额不足,请联系管理员"); + } + } + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.insertUser(user)); + } + + /** + * 修改用户 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + deptService.checkDeptDataScope(user.getDeptId()); + deptService.checkDeptMatchRole(user.getUserId(), List.of(user.getRoleIds())); + if (!userService.checkUserNameUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isEmpty(user.getPhonenumber())) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号不能为空"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + return toAjax(userService.updateUser(user)); + } + + /** + * 删除用户 + * + * @param userIds 角色ID串 + */ + @SaCheckPermission("system:user:remove") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public R remove(@PathVariable Long[] userIds) { + if (ArrayUtil.contains(userIds, LoginHelper.getUserId())) { + return R.fail("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + /** + * 根据用户ID串批量获取用户基础信息 + * + * @param userIds 用户ID串 + * @param deptId 部门ID + */ + @SaCheckPermission("system:user:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] userIds, + @RequestParam(required = false) Long deptId) { + return R.ok(userService.selectUserByIds(ArrayUtil.isEmpty(userIds) ? null : List.of(userIds), deptId)); + } + + /** + * 重置密码 + */ + @ApiEncrypt + @SaCheckPermission("system:user:resetPwd") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/resetPwd") + public R resetPwd(@RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.resetUserPwd(user.getUserId(), user.getPassword())); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + return toAjax(userService.updateUserStatus(user.getUserId(), user.getStatus())); + } + + /** + * 根据用户编号获取授权角色 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping("/authRole/{userId}") + public R authRole(@PathVariable Long userId) { + userService.checkUserDataScope(userId); + SysUserVo user = userService.selectUserById(userId); + List roles = roleService.selectRolesAuthByUserId(userId); + SysUserInfoVo userInfoVo = new SysUserInfoVo(); + userInfoVo.setUser(user); + userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin())); + return R.ok(userInfoVo); + } + + /** + * 用户授权角色 + * + * @param userId 用户Id + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public R insertAuthRole(Long userId, Long[] roleIds) { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return R.ok(); + } + + /** + * 获取部门树列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/deptTree") + public R>> deptTree(SysDeptBo dept) { + return R.ok(deptService.selectDeptTreeList(dept)); + } + + /** + * 获取部门下的所有用户信息 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list/dept/{deptId}") + public R> listByDept(@PathVariable @NotNull Long deptId) { + return R.ok(userService.selectUserListByDept(deptId)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserFileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserFileController.java new file mode 100644 index 0000000..dc2a8c4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserFileController.java @@ -0,0 +1,101 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.dto.userfile.SysUserFileCreateReq; +import org.dromara.system.domain.dto.userfile.SysUserFileQueryReq; +import org.dromara.system.domain.vo.SysUserFileVo; +import org.dromara.system.service.ISysUserFileService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 用户文件关联 + * + * @author lilemy + * @date 2025-06-25 + */ +@Validated +@RestController +@RequestMapping("/system/userFile") +public class SysUserFileController extends BaseController { + + @Resource + private ISysUserFileService userFileService; + + /** + * 查询用户文件关联列表 + */ + @SaCheckPermission("system:userFile:list") + @GetMapping("/list") + public TableDataInfo list(SysUserFileQueryReq req, PageQuery pageQuery) { + return userFileService.queryPageList(req, pageQuery); + } + + /** + * 获取用户文件关联详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:userFile:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(userFileService.queryById(id)); + } + + /** + * 根据用户id获取用户文件关联列表 + */ + @SaCheckPermission("system:userFile:query") + @GetMapping("/user/{userId}") + public R> getInfoByUserId(@NotNull(message = "用户id不能为空") + @PathVariable Long userId) { + return R.ok(userFileService.queryListByUserId(userId)); + } + + /** + * 获取登录用户文件关联列表 + */ + @SaCheckPermission("system:userFile:query") + @GetMapping("/login/user") + public R> getInfoByLoginUser() { + return R.ok(userFileService.queryListByLoginUser()); + } + + /** + * 新增用户文件关联 + */ + @SaCheckPermission("system:userFile:add") + @Log(title = "用户文件关联", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysUserFileCreateReq req) { + return toAjax(userFileService.insertByBo(req)); + } + + /** + * 删除用户文件关联 + * + * @param id 主键 + */ + @SaCheckPermission("system:userFile:remove") + @Log(title = "用户文件关联", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long id) { + return toAjax(userFileService.deleteById(id)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java new file mode 100644 index 0000000..e398a20 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java @@ -0,0 +1,47 @@ +package org.dromara.system.domain; + +import org.dromara.common.core.utils.StringUtils; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 缓存信息 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class SysCache { + + /** + * 缓存名称 + */ + private String cacheName = ""; + + /** + * 缓存键名 + */ + private String cacheKey = ""; + + /** + * 缓存内容 + */ + private String cacheValue = ""; + + /** + * 备注 + */ + private String remark = ""; + + public SysCache(String cacheName, String remark) { + this.cacheName = cacheName; + this.remark = remark; + } + + public SysCache(String cacheName, String cacheKey, String cacheValue) { + this.cacheName = StringUtils.replace(cacheName, ":", ""); + this.cacheKey = StringUtils.replace(cacheKey, cacheName, ""); + this.cacheValue = cacheValue; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java new file mode 100644 index 0000000..ee2475d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java @@ -0,0 +1,77 @@ +package org.dromara.system.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 授权管理对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_client") +public class SysClient extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + private String clientKey; + + /** + * 客户端秘钥 + */ + private String clientSecret; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java new file mode 100644 index 0000000..6fcb88f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java @@ -0,0 +1,51 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 参数配置表 sys_config + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_config") +public class SysConfig extends TenantEntity { + + /** + * 参数主键 + */ + @TableId(value = "config_id") + private Long configId; + + /** + * 参数名称 + */ + private String configName; + + /** + * 参数键名 + */ + private String configKey; + + /** + * 参数键值 + */ + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + private String configType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java new file mode 100644 index 0000000..c3729ab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java @@ -0,0 +1,102 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 部门表 sys_dept + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dept") +public class SysDept extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门ID + */ + @TableId(value = "dept_id") + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 分包公司ID + */ + private Long contractorId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 部门类别编码 + */ + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人 + */ + private Long leader; + + /** + * 联系电话 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 部门状态:0正常,1停用 + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 是否隐藏(0隐藏 1显示) + */ + private String isShow; + + /** + * 部门类型 + */ + private String deptType; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java new file mode 100644 index 0000000..9d83736 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java @@ -0,0 +1,71 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.tenant.core.TenantEntity; + +/** + * 字典数据表 sys_dict_data + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_data") +public class SysDictData extends TenantEntity { + + /** + * 字典编码 + */ + @TableId(value = "dict_code") + private Long dictCode; + + /** + * 字典排序 + */ + private Integer dictSort; + + /** + * 字典标签 + */ + private String dictLabel; + + /** + * 字典键值 + */ + private String dictValue; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + private String cssClass; + + /** + * 表格字典样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 备注 + */ + private String remark; + + public boolean getDefault() { + return SystemConstants.YES.equals(this.isDefault); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java new file mode 100644 index 0000000..955af85 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java @@ -0,0 +1,41 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典类型表 sys_dict_type + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_type") +public class SysDictType extends TenantEntity { + + /** + * 字典主键 + */ + @TableId(value = "dict_id") + private Long dictId; + + /** + * 字典名称 + */ + private String dictName; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java new file mode 100644 index 0000000..c57dc0a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java @@ -0,0 +1,85 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 系统访问记录表 sys_logininfor + * + * @author Lion Li + */ + +@Data +@TableName("sys_logininfor") +public class SysLogininfor implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "info_id") + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录状态 0成功 1失败 + */ + private String status; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 提示消息 + */ + private String msg; + + /** + * 访问时间 + */ + private Date loginTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java new file mode 100644 index 0000000..2df5596 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java @@ -0,0 +1,191 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.util.ArrayList; +import java.util.List; + +/** + * 菜单权限表 sys_menu + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_menu") +public class SysMenu extends BaseEntity { + + /** + * 菜单ID + */ + @TableId(value = "menu_id") + private Long menuId; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限字符串 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 备注 + */ + private String remark; + + /** + * 父菜单名称 + */ + @TableField(exist = false) + private String parentName; + + /** + * 子菜单 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + + /** + * 获取路由名称 + */ + public String getRouteName() { + String routerName = StringUtils.capitalize(path); + // 非外链并且是一级目录(类型为目录) + if (isMenuFrame()) { + routerName = StringUtils.EMPTY; + } + return routerName; + } + + /** + * 获取路由地址 + */ + public String getRouterPath() { + String routerPath = this.path; + // 内链打开外网方式 + if (getParentId() != 0L && isInnerLink()) { + routerPath = innerLinkReplaceEach(routerPath); + } + // 非外链并且是一级目录(类型为目录) + if (0L == getParentId() && SystemConstants.TYPE_DIR.equals(getMenuType()) + && SystemConstants.NO_FRAME.equals(getIsFrame())) { + routerPath = "/" + this.path; + } + // 非外链并且是一级目录(类型为菜单) + else if (isMenuFrame()) { + routerPath = "/"; + } + return routerPath; + } + + /** + * 获取组件信息 + */ + public String getComponentInfo() { + String component = SystemConstants.LAYOUT; + if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) { + component = this.component; + } else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && isInnerLink()) { + component = SystemConstants.INNER_LINK; + } else if (StringUtils.isEmpty(this.component) && isParentView()) { + component = SystemConstants.PARENT_VIEW; + } + return component; + } + + /** + * 是否为菜单内部跳转 + */ + public boolean isMenuFrame() { + return getParentId() == 0L && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME); + } + + /** + * 是否为内链组件 + */ + public boolean isInnerLink() { + return isFrame.equals(SystemConstants.NO_FRAME) && StringUtils.ishttp(path); + } + + /** + * 是否为parent_view组件 + */ + public boolean isParentView() { + return getParentId() != 0L && SystemConstants.TYPE_DIR.equals(menuType); + } + + /** + * 内链域名特殊字符替换 + */ + public static String innerLinkReplaceEach(String path) { + return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":"}, + new String[]{"", "", "", "/", "/"}); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java new file mode 100644 index 0000000..bfcc2bc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java @@ -0,0 +1,51 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +/** + * 通知公告表 sys_notice + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_notice") +public class SysNotice extends TenantEntity { + + /** + * 公告ID + */ + @TableId(value = "notice_id") + private Long noticeId; + + /** + * 公告标题 + */ + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java new file mode 100644 index 0000000..41a8c59 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java @@ -0,0 +1,115 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 操作日志记录表 oper_log + * + * @author Lion Li + */ + +@Data +@TableName("sys_oper_log") +public class SysOperLog implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @TableId(value = "oper_id") + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 操作模块 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求url + */ + private String operUrl; + + /** + * 操作地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java new file mode 100644 index 0000000..af88898 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java @@ -0,0 +1,50 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * OSS对象存储对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss") +public class SysOss extends TenantEntity { + + /** + * 对象存储主键 + */ + @TableId(value = "oss_id") + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 服务商 + */ + private String service; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java new file mode 100644 index 0000000..4b67d63 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java @@ -0,0 +1,89 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 对象存储配置对象 sys_oss_config + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss_config") +public class SysOssConfig extends BaseEntity { + + /** + * 主键 + */ + @TableId(value = "oss_config_id") + private Long ossConfigId; + + /** + * 配置key + */ + private String configKey; + + /** + * accessKey + */ + private String accessKey; + + /** + * 秘钥 + */ + private String secretKey; + + /** + * 桶名称 + */ + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + private String endpoint; + + /** + * 自定义域名 + */ + private String domain; + + /** + * 是否https(0否 1是) + */ + private String isHttps; + + /** + * 域 + */ + private String region; + + /** + * 是否默认(0=是,1=否) + */ + private String status; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java new file mode 100644 index 0000000..2c985da --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java @@ -0,0 +1,61 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 岗位表 sys_post + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_post") +public class SysPost extends TenantEntity { + + /** + * 岗位序号 + */ + @TableId(value = "post_id") + private Long postId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 岗位编码 + */ + private String postCode; + + /** + * 岗位名称 + */ + private String postName; + + /** + * 岗位类别编码 + */ + private String postCategory; + + /** + * 岗位排序 + */ + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java new file mode 100644 index 0000000..363dd91 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java @@ -0,0 +1,90 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.tenant.core.TenantEntity; + +/** + * 角色表 sys_role + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_role") +public class SysRole extends TenantEntity { + + /** + * 角色ID + */ + @TableId(value = "role_id") + private Long roleId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色权限 + */ + private String roleKey; + + /** + * 角色排序 + */ + private Integer roleSort; + + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + private String dataScope; + + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + + /** + * 是否特殊角色(0否 1是) + */ + private String isSpecial; + + + public SysRole(Long roleId) { + this.roleId = roleId; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java new file mode 100644 index 0000000..ba77694 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和部门关联 sys_role_dept + * + * @author Lion Li + */ + +@Data +@TableName("sys_role_dept") +public class SysRoleDept { + + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + + /** + * 部门ID + */ + private Long deptId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java new file mode 100644 index 0000000..ba28f17 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author Lion Li + */ + +@Data +@TableName("sys_role_menu") +public class SysRoleMenu { + + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java new file mode 100644 index 0000000..10f2936 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java @@ -0,0 +1,136 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 社会化关系对象 sys_social + * + * @author thiszhc + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_social") +public class SysSocial extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 的唯一ID + */ + private String authId; + + /** + * 用户来源 + */ + private String source; + + /** + * 用户的授权令牌 + */ + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 用户的 open id + */ + private String openId; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java new file mode 100644 index 0000000..9800c30 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java @@ -0,0 +1,103 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.util.Date; + +/** + * 租户对象 sys_tenant + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_tenant") +public class SysTenant extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 联系人 + */ + private String contactUserName; + + /** + * 联系电话 + */ + private String contactPhone; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 统一社会信用代码 + */ + private String licenseNumber; + + /** + * 地址 + */ + private String address; + + /** + * 域名 + */ + private String domain; + + /** + * 企业简介 + */ + private String intro; + + /** + * 备注 + */ + private String remark; + + /** + * 租户套餐编号 + */ + private Long packageId; + + /** + * 过期时间 + */ + private Date expireTime; + + /** + * 用户数量(-1不限制) + */ + private Long accountCount; + + /** + * 租户状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java new file mode 100644 index 0000000..5f58e3e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java @@ -0,0 +1,60 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.io.Serial; + +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 租户套餐对象 sys_tenant_package + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_tenant_package") +public class SysTenantPackage extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户套餐id + */ + @TableId(value = "package_id") + private Long packageId; + + /** + * 套餐名称 + */ + private String packageName; + + /** + * 关联菜单id + */ + private String menuIds; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private Boolean menuCheckStrictly; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java new file mode 100644 index 0000000..3712f80 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java @@ -0,0 +1,115 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.tenant.core.TenantEntity; + +import java.util.Date; + +/** + * 用户对象 sys_user + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_user") +public class SysUser extends TenantEntity { + + /** + * 用户ID + */ + @TableId(value = "user_id") + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + private String email; + + /** + * 手机号码 + */ + private String phonenumber; + + /** + * 用户性别 + */ + private String sex; + + /** + * 用户头像 + */ + private Long avatar; + + /** + * 密码 + */ + @TableField( + insertStrategy = FieldStrategy.NOT_EMPTY, + updateStrategy = FieldStrategy.NOT_EMPTY, + whereStrategy = FieldStrategy.NOT_EMPTY + ) + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private Date loginDate; + + /** + * 备注 + */ + private String remark; + + + public SysUser(Long userId) { + this.userId = userId; + } + + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ID.equals(this.userId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserFile.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserFile.java new file mode 100644 index 0000000..66929b8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserFile.java @@ -0,0 +1,39 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户文件关联对象 sys_user_file + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@TableName("sys_user_file") +public class SysUserFile implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 用户id + */ + private Long userId; + + /** + * 文件id + */ + private Long fileId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java new file mode 100644 index 0000000..ba30eb6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java @@ -0,0 +1,63 @@ +package org.dromara.system.domain; + +import lombok.Data; + +/** + * 当前在线会话 + * + * @author Lion Li + */ +@Data +public class SysUserOnline { + + /** + * 会话编号 + */ + private String tokenId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 用户名称 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地址 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java new file mode 100644 index 0000000..119c117 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和岗位关联 sys_user_post + * + * @author Lion Li + */ + +@Data +@TableName("sys_user_post") +public class SysUserPost { + + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * 岗位ID + */ + private Long postId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java new file mode 100644 index 0000000..0a50e80 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和角色关联 sys_user_role + * + * @author Lion Li + */ + +@Data +@TableName("sys_user_role") +public class SysUserRole { + + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * 角色ID + */ + private Long roleId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java new file mode 100644 index 0000000..e5f5ffa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java @@ -0,0 +1,80 @@ +package org.dromara.system.domain.bo; + +import org.dromara.system.domain.SysClient; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.util.List; + +/** + * 授权管理业务对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysClient.class, reverseConvertGenerate = false) +public class SysClientBo extends BaseEntity { + + /** + * id + */ + @NotNull(message = "id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + @NotBlank(message = "客户端key不能为空", groups = { AddGroup.class, EditGroup.class }) + private String clientKey; + + /** + * 客户端秘钥 + */ + @NotBlank(message = "客户端秘钥不能为空", groups = { AddGroup.class, EditGroup.class }) + private String clientSecret; + + /** + * 授权类型 + */ + @NotNull(message = "授权类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private List grantTypeList; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java new file mode 100644 index 0000000..257935d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java @@ -0,0 +1,59 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysConfig; + +/** + * 参数配置业务对象 sys_config + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysConfig.class, reverseConvertGenerate = false) +public class SysConfigBo extends BaseEntity { + + /** + * 参数主键 + */ + private Long configId; + + /** + * 参数名称 + */ + @NotBlank(message = "参数名称不能为空") + @Size(min = 0, max = 100, message = "参数名称不能超过{max}个字符") + private String configName; + + /** + * 参数键名 + */ + @NotBlank(message = "参数键名不能为空") + @Size(min = 0, max = 100, message = "参数键名长度不能超过{max}个字符") + private String configKey; + + /** + * 参数键值 + */ + @NotBlank(message = "参数键值不能为空") + @Size(min = 0, max = 500, message = "参数键值长度不能超过{max}个字符") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + private String configType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java new file mode 100644 index 0000000..4ff5bab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java @@ -0,0 +1,162 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysDept; + +import java.io.Serial; + +/** + * 部门业务对象 sys_dept + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDept.class, reverseConvertGenerate = false) +public class SysDeptBo extends BaseEntity { + + @Serial + private static final long serialVersionUID = -7462841004330805895L; + + /** + * 部门id + */ + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 项目id + */ + private Long projectId; + + /** + * 项目部门项目id + */ + private Long rowProjectId; + + /** + * 分包公司ID + */ + private Long contractorId; + + /** + * 部门名称 + */ + @NotBlank(message = "部门名称不能为空") + @Size(min = 0, max = 30, message = "部门名称长度不能超过{max}个字符") + private String deptName; + + /** + * 部门类别编码 + */ + @Size(min = 0, max = 100, message = "部门类别编码长度不能超过{max}个字符") + private String deptCategory; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 负责人 + */ + private Long leader; + + /** + * 联系电话 + */ + @Size(min = 0, max = 11, message = "联系电话长度不能超过{max}个字符") + private String phone; + + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + private String status; + + /** + * 是否隐藏(0隐藏 1显示) + */ + @Pattern(regexp = "^[01]$", message = "isShow字段值必须是0或1") + private String isShow; + + /** + * 部门类型 + */ + @NotBlank(message = "部门类型不能为空") + private String deptType; + + +// /** +// * ====================== +// * 如果子集为0,则需要新增角色 +// * ====================== +// */ +// +// /** +// * 角色ID +// */ +// private Long roleId; +// +// /** +// * 角色权限字符串 +// */ +// private String roleKey; +// +// /** +// * 显示顺序 +// */ +// private Integer roleSort; +// +// /** +// * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) +// */ +// private String dataScope; +// +// /** +// * 菜单树选择项是否关联显示 +// */ +// private Boolean menuCheckStrictly; +// +// /** +// * 部门树选择项是否关联显示 +// */ +// private Boolean deptCheckStrictly; +// +// /** +// * 角色状态(0正常 1停用) +// */ +// private String roleStatus; +// +// /** +// * 备注 +// */ +// private String remark; +// +// /** +// * 菜单组 +// */ +// private Long[] menuIds; +// +// /** +// * 部门组(数据权限) +// */ +// private Long[] deptIds; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java new file mode 100644 index 0000000..042946c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java @@ -0,0 +1,80 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysDictData; + +/** + * 字典数据业务对象 sys_dict_data + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDictData.class, reverseConvertGenerate = false) +public class SysDictDataBo extends BaseEntity { + + /** + * 字典编码 + */ + private Long dictCode; + + /** + * 字典排序 + */ + private Integer dictSort; + + /** + * 字典标签 + */ + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过{max}个字符") + private String dictLabel; + + /** + * 字典键值 + */ + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过{max}个字符") + private String dictValue; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过{max}个字符") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + @Size(min = 0, max = 100, message = "样式属性长度不能超过{max}个字符") + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java new file mode 100644 index 0000000..fcc1ac1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java @@ -0,0 +1,50 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysDictType; + +/** + * 字典类型业务对象 sys_dict_type + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDictType.class, reverseConvertGenerate = false) +public class SysDictTypeBo extends BaseEntity { + + /** + * 字典主键 + */ + private Long dictId; + + /** + * 字典名称 + */ + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过{max}个字符") + private String dictName; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过{max}个字符") + @Pattern(regexp = RegexConstants.DICTIONARY_TYPE, message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + private String dictType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java new file mode 100644 index 0000000..4646162 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java @@ -0,0 +1,87 @@ +package org.dromara.system.domain.bo; + +import org.dromara.system.domain.SysLogininfor; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 系统访问记录业务对象 sys_logininfor + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysLogininfor.class, reverseConvertGenerate = false) +public class SysLogininforBo { + + /** + * 访问ID + */ + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录状态(0成功 1失败) + */ + private String status; + + /** + * 提示消息 + */ + private String msg; + + /** + * 访问时间 + */ + private Date loginTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java new file mode 100644 index 0000000..fbaafaa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java @@ -0,0 +1,110 @@ +package org.dromara.system.domain.bo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysMenu; + +/** + * 菜单权限业务对象 sys_menu + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysMenu.class, reverseConvertGenerate = false) +public class SysMenuBo extends BaseEntity { + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 菜单名称 + */ + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过{max}个字符") + private String menuName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 路由地址 + */ + @Size(min = 0, max = 200, message = "路由地址不能超过{max}个字符") + private String path; + + /** + * 组件路径 + */ + @Size(min = 0, max = 200, message = "组件路径不能超过{max}个字符") + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + @NotBlank(message = "菜单类型不能为空") + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + @Size(min = 0, max = 100, message = "权限标识长度不能超过{max}个字符") + @Pattern(regexp = RegexConstants.PERMISSION_STRING, message = "权限标识必须符合 tool:build:list 格式") + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java new file mode 100644 index 0000000..cdcc575 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java @@ -0,0 +1,61 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.xss.Xss; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysNotice; + +/** + * 通知公告业务对象 sys_notice + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysNotice.class, reverseConvertGenerate = false) +public class SysNoticeBo extends BaseEntity { + + /** + * 公告ID + */ + private Long noticeId; + + /** + * 公告标题 + */ + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空") + @Size(min = 0, max = 50, message = "公告标题不能超过{max}个字符") + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建人名称 + */ + private String createByName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java new file mode 100644 index 0000000..f16400a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java @@ -0,0 +1,127 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.system.domain.SysOperLog; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMappers; +import lombok.Data; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 操作日志记录业务对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ + +@Data +@AutoMappers({ + @AutoMapper(target = SysOperLog.class, reverseConvertGenerate = false), + @AutoMapper(target = OperLogEvent.class) +}) +public class SysOperLogBo { + + /** + * 日志主键 + */ + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 模块标题 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求URL + */ + private String operUrl; + + /** + * 主机地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java new file mode 100644 index 0000000..7cb3104 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java @@ -0,0 +1,49 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysOss; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * OSS对象存储分页查询对象 sys_oss + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysOss.class, reverseConvertGenerate = false) +public class SysOssBo extends BaseEntity { + + /** + * ossId + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 服务商 + */ + private String service; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java new file mode 100644 index 0000000..3dc4328 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java @@ -0,0 +1,109 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysOssConfig; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 对象存储配置业务对象 sys_oss_config + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysOssConfig.class, reverseConvertGenerate = false) +public class SysOssConfigBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long ossConfigId; + + /** + * 配置key + */ + @NotBlank(message = "配置key不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "configKey长度必须介于{min}和{max} 之间") + private String configKey; + + /** + * accessKey + */ + @NotBlank(message = "accessKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "accessKey长度必须介于{min}和{max} 之间") + private String accessKey; + + /** + * 秘钥 + */ + @NotBlank(message = "secretKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "secretKey长度必须介于{min}和{max} 之间") + private String secretKey; + + /** + * 桶名称 + */ + @NotBlank(message = "桶名称不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "bucketName长度必须介于{min}和{max}之间") + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + @NotBlank(message = "访问站点不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "endpoint长度必须介于{min}和{max}之间") + private String endpoint; + + /** + * 自定义域名 + */ + private String domain; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + + /** + * 是否默认(0=是,1=否) + */ + private String status; + + /** + * 域 + */ + private String region; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + @NotBlank(message = "桶权限类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String accessPolicy; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java new file mode 100644 index 0000000..09805cd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java @@ -0,0 +1,75 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysPost; + +/** + * 岗位信息业务对象 sys_post + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysPost.class, reverseConvertGenerate = false) +public class SysPostBo extends BaseEntity { + + /** + * 岗位ID + */ + private Long postId; + + /** + * 部门id(单部门) + */ + @NotNull(message = "部门id不能为空") + private Long deptId; + + /** + * 归属部门id(部门树) + */ + private Long belongDeptId; + + /** + * 岗位编码 + */ + @NotBlank(message = "岗位编码不能为空") + @Size(min = 0, max = 64, message = "岗位编码长度不能超过{max}个字符") + private String postCode; + + /** + * 岗位名称 + */ + @NotBlank(message = "岗位名称不能为空") + @Size(min = 0, max = 50, message = "岗位名称长度不能超过{max}个字符") + private String postName; + + /** + * 岗位类别编码 + */ + @Size(min = 0, max = 100, message = "类别编码长度不能超过{max}个字符") + private String postCategory; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java new file mode 100644 index 0000000..8d839ae --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java @@ -0,0 +1,104 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysRole; + +/** + * 角色信息业务对象 sys_role + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysRole.class, reverseConvertGenerate = false) +public class SysRoleBo extends BaseEntity { + + /** + * 角色ID + */ + private Long roleId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 角色名称 + */ + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过{max}个字符") + private String roleName; + + /** + * 角色权限字符串 + */ + @NotBlank(message = "角色权限字符串不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符") + private String roleKey; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + */ + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单组 + */ + private Long[] menuIds; + + /** + * 部门组(数据权限) + */ + private Long[] deptIds; + + /** + * 是否特殊角色(0否 1是) + */ + private String isSpecial; + + public SysRoleBo(Long roleId) { + this.roleId = roleId; + } + + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ID.equals(this.roleId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java new file mode 100644 index 0000000..cede1e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java @@ -0,0 +1,142 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.tenant.core.TenantEntity; +import org.dromara.system.domain.SysSocial; + +/** + * 社会化关系业务对象 sys_social + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysSocial.class, reverseConvertGenerate = false) +public class SysSocialBo extends TenantEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 认证唯一ID + */ + @NotBlank(message = "认证唯一ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private String authId; + + /** + * 用户来源 + */ + @NotBlank(message = "用户来源不能为空", groups = { AddGroup.class, EditGroup.class }) + private String source; + + /** + * 用户的授权令牌 + */ + @NotBlank(message = "用户的授权令牌不能为空", groups = { AddGroup.class, EditGroup.class }) + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 平台唯一id + */ + private String openId; + + /** + * 用户的 ID + */ + @NotBlank(message = "用户的ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long userId; + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java new file mode 100644 index 0000000..e3ac642 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java @@ -0,0 +1,114 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.system.domain.SysTenant; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.util.Date; + +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 租户业务对象 sys_tenant + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysTenant.class, reverseConvertGenerate = false) +public class SysTenantBo extends BaseEntity { + + /** + * id + */ + @NotNull(message = "id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 联系人 + */ + @NotBlank(message = "联系人不能为空", groups = { AddGroup.class, EditGroup.class }) + private String contactUserName; + + /** + * 联系电话 + */ + @NotBlank(message = "联系电话不能为空", groups = { AddGroup.class, EditGroup.class }) + private String contactPhone; + + /** + * 企业名称 + */ + @NotBlank(message = "企业名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String companyName; + + /** + * 用户名(创建系统用户) + */ + @NotBlank(message = "用户名不能为空", groups = { AddGroup.class }) + private String username; + + /** + * 密码(创建系统用户) + */ + @NotBlank(message = "密码不能为空", groups = { AddGroup.class }) + private String password; + + /** + * 统一社会信用代码 + */ + private String licenseNumber; + + /** + * 地址 + */ + private String address; + + /** + * 域名 + */ + private String domain; + + /** + * 企业简介 + */ + private String intro; + + /** + * 备注 + */ + private String remark; + + /** + * 租户套餐编号 + */ + @NotNull(message = "租户套餐不能为空", groups = { AddGroup.class }) + private Long packageId; + + /** + * 过期时间 + */ + private Date expireTime; + + /** + * 用户数量(-1不限制) + */ + private Long accountCount; + + /** + * 租户状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java new file mode 100644 index 0000000..eecbc9f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java @@ -0,0 +1,59 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.system.domain.SysTenantPackage; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMapping; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 租户套餐业务对象 sys_tenant_package + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysTenantPackage.class, reverseConvertGenerate = false) +public class SysTenantPackageBo extends BaseEntity { + + /** + * 租户套餐id + */ + @NotNull(message = "租户套餐id不能为空", groups = { EditGroup.class }) + private Long packageId; + + /** + * 套餐名称 + */ + @NotBlank(message = "套餐名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String packageName; + + /** + * 关联菜单id + */ + @AutoMapping(target = "menuIds", expression = "java(org.dromara.common.core.utils.StringUtils.join(source.getMenuIds(), \",\"))") + private Long[] menuIds; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单树选择项是否关联显示 + */ + private Boolean menuCheckStrictly; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java new file mode 100644 index 0000000..2669a81 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java @@ -0,0 +1,119 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.xss.Xss; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysUser; + +/** + * 用户信息业务对象 sys_user + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysUser.class, reverseConvertGenerate = false) +public class SysUserBo extends BaseEntity { + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") + private String userName; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @NotBlank(message = "用户昵称不能为空") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 密码 + */ + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 角色组 + */ + @Size(min = 1, message = "用户角色不能为空") + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + /** + * 排除不查询的用户(工作流用) + */ + private String excludeUserIds; + + public SysUserBo(Long userId) { + this.userId = userId; + } + + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ID.equals(this.userId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java new file mode 100644 index 0000000..8615fcd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户密码修改bo + */ +@Data +public class SysUserPasswordBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 旧密码 + */ + @NotBlank(message = "旧密码不能为空") + private String oldPassword; + + /** + * 新密码 + */ + @NotBlank(message = "新密码不能为空") + private String newPassword; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java new file mode 100644 index 0000000..846dd79 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java @@ -0,0 +1,53 @@ +package org.dromara.system.domain.bo; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.common.core.xss.Xss; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.sensitive.annotation.Sensitive; +import org.dromara.common.sensitive.core.SensitiveStrategy; + +/** + * 个人信息业务处理 + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SysUserProfileBo extends BaseEntity { + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL) + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + @Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确") + @Sensitive(strategy = SensitiveStrategy.PHONE) + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/userfile/SysUserFileCreateReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/userfile/SysUserFileCreateReq.java new file mode 100644 index 0000000..2da422b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/userfile/SysUserFileCreateReq.java @@ -0,0 +1,28 @@ +package org.dromara.system.domain.dto.userfile; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/25 16:58 + */ +@Data +public class SysUserFileCreateReq implements Serializable { + + @Serial + private static final long serialVersionUID = -5473752959026971387L; + + /** + * 用户id + */ + private Long userId; + + /** + * 文件列表id(,分隔) + */ + private String fileId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/userfile/SysUserFileQueryReq.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/userfile/SysUserFileQueryReq.java new file mode 100644 index 0000000..0d5b4fd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/userfile/SysUserFileQueryReq.java @@ -0,0 +1,28 @@ +package org.dromara.system.domain.dto.userfile; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/6/25 16:58 + */ +@Data +public class SysUserFileQueryReq implements Serializable { + + @Serial + private static final long serialVersionUID = 6499152510654651256L; + + /** + * 用户id + */ + private Long userId; + + /** + * 文件id + */ + private Long fileId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/enums/SysDeptTypeEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/enums/SysDeptTypeEnum.java new file mode 100644 index 0000000..a626d1d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/enums/SysDeptTypeEnum.java @@ -0,0 +1,26 @@ +package org.dromara.system.domain.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/7/18 9:41 + */ +@Getter +public enum SysDeptTypeEnum { + + NORMAL("1", "正常"), + SPECIAL("2", "特殊"), + PROJECT("3", "项目"), + CONTRACT("4", "分包"); + + private final String code; + + private final String message; + + SysDeptTypeEnum(String code, String message) { + this.code = code; + this.message = message; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/enums/SysPostManagerEnum.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/enums/SysPostManagerEnum.java new file mode 100644 index 0000000..ff4051e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/enums/SysPostManagerEnum.java @@ -0,0 +1,43 @@ +package org.dromara.system.domain.enums; + +import lombok.Getter; + +import java.util.Arrays; +import java.util.List; + +/** + * @author lilemy + * @date 2025/6/26 9:39 + */ +@Getter +public enum SysPostManagerEnum { + + MAJOR("major", "专业负责人"), + CONSTRUCTION("construction", "施工员"), + QUALITY("quality", "质检员"), + SAFETY("safety", "安全员"), + MEASURE("measure", "测量员"), + DATA("data", "资料员"), + TEST("test", "试验员"), + MATERIALS("materials", "材料员"), + SUPERVISOR("supervisor", "监理员"); + + private final String code; + + private final String name; + + SysPostManagerEnum(String code, String name) { + this.code = code; + this.name = name; + } + + /** + * 获取全部枚举 + * + * @return 全部枚举 + */ + public static List toList() { + return Arrays.asList(values()); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java new file mode 100644 index 0000000..46c020b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java @@ -0,0 +1,18 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +/** + * 用户头像信息 + * + * @author Michelle.Chung + */ +@Data +public class AvatarVo { + + /** + * 头像地址 + */ + private String imgUrl; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java new file mode 100644 index 0000000..f827cba --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java @@ -0,0 +1,23 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * 缓存监控列表信息 + * + * @author Michelle.Chung + */ +@Data +public class CacheListInfoVo { + + private Properties info; + + private Long dbSize; + + private List> commandStats; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java new file mode 100644 index 0000000..6f7db28 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java @@ -0,0 +1,26 @@ +package org.dromara.system.domain.vo; + +import cn.hutool.core.lang.tree.Tree; +import lombok.Data; + +import java.util.List; + +/** + * 角色部门列表树信息 + * + * @author Michelle.Chung + */ +@Data +public class DeptTreeSelectVo { + + /** + * 选中部门列表 + */ + private List checkedKeys; + + /** + * 下拉树结构列表 + */ + private List> depts; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java new file mode 100644 index 0000000..0724538 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java @@ -0,0 +1,26 @@ +package org.dromara.system.domain.vo; + +import cn.hutool.core.lang.tree.Tree; +import lombok.Data; + +import java.util.List; + +/** + * 角色菜单列表树信息 + * + * @author Michelle.Chung + */ +@Data +public class MenuTreeSelectVo { + + /** + * 选中菜单列表 + */ + private List checkedKeys; + + /** + * 菜单下拉树结构列表 + */ + private List> menus; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java new file mode 100644 index 0000000..f720cd7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java @@ -0,0 +1,61 @@ +package org.dromara.system.domain.vo; + +import org.dromara.common.core.utils.StringUtils; +import lombok.Data; + +/** + * 路由显示信息 + * + * @author ruoyi + */ + +@Data +public class MetaVo { + + /** + * 设置该路由在侧边栏和面包屑中展示的名字 + */ + private String title; + + /** + * 设置该路由的图标,对应路径src/assets/icons/svg + */ + private String icon; + + /** + * 设置为true,则不会被 缓存 + */ + private boolean noCache; + + /** + * 内链地址(http(s)://开头) + */ + private String link; + + public MetaVo(String title, String icon) { + this.title = title; + this.icon = icon; + } + + public MetaVo(String title, String icon, boolean noCache) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + public MetaVo(String title, String icon, String link) { + this.title = title; + this.icon = icon; + this.link = link; + } + + public MetaVo(String title, String icon, boolean noCache, String link) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) { + this.link = link; + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java new file mode 100644 index 0000000..c047651 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +/** + * 用户个人信息 + * + * @author Michelle.Chung + */ +@Data +public class ProfileVo { + + /** + * 用户信息 + */ + private SysUserVo user; + + /** + * 用户所属角色组 + */ + private String roleGroup; + + /** + * 用户所属岗位组 + */ + private String postGroup; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java new file mode 100644 index 0000000..0d576ef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java @@ -0,0 +1,62 @@ +package org.dromara.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.util.List; + +/** + * 路由配置信息 + * + * @author Lion Li + */ +@Data +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class RouterVo { + + /** + * 路由名字 + */ + private String name; + + /** + * 路由地址 + */ + private String path; + + /** + * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + */ + private boolean hidden; + + /** + * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + */ + private String redirect; + + /** + * 组件地址 + */ + private String component; + + /** + * 路由参数:如 {"id": 1, "name": "ry"} + */ + private String query; + + /** + * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + */ + private Boolean alwaysShow; + + /** + * 其他元素 + */ + private MetaVo meta; + + /** + * 子路由 + */ + private List children; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java new file mode 100644 index 0000000..34f24eb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java @@ -0,0 +1,90 @@ +package org.dromara.system.domain.vo; + +import org.dromara.system.domain.SysClient; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 授权管理视图对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysClient.class) +public class SysClientVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 客户端id + */ + @ExcelProperty(value = "客户端id") + private String clientId; + + /** + * 客户端key + */ + @ExcelProperty(value = "客户端key") + private String clientKey; + + /** + * 客户端秘钥 + */ + @ExcelProperty(value = "客户端秘钥") + private String clientSecret; + + /** + * 授权类型 + */ + @ExcelProperty(value = "授权类型") + private List grantTypeList; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + @ExcelProperty(value = "token活跃超时时间") + private Long activeTimeout; + + /** + * token固定超时时间 + */ + @ExcelProperty(value = "token固定超时时间") + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java new file mode 100644 index 0000000..f896000 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java @@ -0,0 +1,72 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysConfig; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 参数配置视图对象 sys_config + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysConfig.class) +public class SysConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 参数主键 + */ + @ExcelProperty(value = "参数主键") + private Long configId; + + /** + * 参数名称 + */ + @ExcelProperty(value = "参数名称") + private String configName; + + /** + * 参数键名 + */ + @ExcelProperty(value = "参数键名") + private String configKey; + + /** + * 参数键值 + */ + @ExcelProperty(value = "参数键值") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + @ExcelProperty(value = "系统内置", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String configType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java new file mode 100644 index 0000000..c8a7283 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java @@ -0,0 +1,137 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; +import org.dromara.project.domain.vo.project.BusProjectVo; +import org.dromara.system.domain.SysDept; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 部门视图对象 sys_dept + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDept.class) +public class SysDeptVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 父部门id + */ + private Long parentId; + + /** + * 父部门名称 + */ + private String parentName; + + /** + * 父部门信息 + */ + private SysDeptVo parent; + + /** + * 项目id + */ + private Long projectId; + + /** + * 分包公司ID + */ + private Long contractorId; + + /** + * 未绑定项目信息 + */ + private List projectList; + + /** + * 未绑定分包信息 + */ + private List contractorList; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 部门类别编码 + */ + @ExcelProperty(value = "部门类别编码") + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人ID + */ + private Long leader; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String leaderName; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String phone; + + /** + * 邮箱 + */ + @ExcelProperty(value = "邮箱") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + @ExcelProperty(value = "部门状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 部门类型 + */ + @ExcelProperty(value = "部门类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_dept_type") + private String deptType; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java new file mode 100644 index 0000000..83ea619 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java @@ -0,0 +1,88 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysDictData; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 字典数据视图对象 sys_dict_data + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictData.class) +public class SysDictDataVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典编码 + */ + @ExcelProperty(value = "字典编码") + private Long dictCode; + + /** + * 字典排序 + */ + @ExcelProperty(value = "字典排序") + private Integer dictSort; + + /** + * 字典标签 + */ + @ExcelProperty(value = "字典标签") + private String dictLabel; + + /** + * 字典键值 + */ + @ExcelProperty(value = "字典键值") + private String dictValue; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + @ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isDefault; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java new file mode 100644 index 0000000..e6a184f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java @@ -0,0 +1,59 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysDictType; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 字典类型视图对象 sys_dict_type + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictType.class) +public class SysDictTypeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典主键 + */ + @ExcelProperty(value = "字典主键") + private Long dictId; + + /** + * 字典名称 + */ + @ExcelProperty(value = "字典名称") + private String dictName; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java new file mode 100644 index 0000000..de19aea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java @@ -0,0 +1,106 @@ +package org.dromara.system.domain.vo; + +import java.util.Date; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysLogininfor; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + + +/** + * 系统访问记录视图对象 sys_logininfor + * + * @author Michelle.Chung + * @date 2023-02-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysLogininfor.class) +public class SysLogininforVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 访问ID + */ + @ExcelProperty(value = "序号") + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "用户账号") + private String userName; + + /** + * 客户端 + */ + @ExcelProperty(value = "客户端") + private String clientKey; + + /** + * 设备类型 + */ + @ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_device_type") + private String deviceType; + + /** + * 登录状态(0成功 1失败) + */ + @ExcelProperty(value = "登录状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; + + /** + * 登录IP地址 + */ + @ExcelProperty(value = "登录地址") + private String ipaddr; + + /** + * 登录地点 + */ + @ExcelProperty(value = "登录地点") + private String loginLocation; + + /** + * 浏览器类型 + */ + @ExcelProperty(value = "浏览器") + private String browser; + + /** + * 操作系统 + */ + @ExcelProperty(value = "操作系统") + private String os; + + + /** + * 提示消息 + */ + @ExcelProperty(value = "提示消息") + private String msg; + + /** + * 访问时间 + */ + @ExcelProperty(value = "访问时间") + private Date loginTime; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java new file mode 100644 index 0000000..5214a33 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java @@ -0,0 +1,116 @@ +package org.dromara.system.domain.vo; + +import org.dromara.system.domain.SysMenu; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + + +/** + * 菜单权限视图对象 sys_menu + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysMenu.class) +public class SysMenuVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 子菜单 + */ + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java new file mode 100644 index 0000000..afe7367 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java @@ -0,0 +1,73 @@ +package org.dromara.system.domain.vo; + +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysNotice; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 通知公告视图对象 sys_notice + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysNotice.class) +public class SysNoticeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 公告ID + */ + private Long noticeId; + + /** + * 公告标题 + */ + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + private String createByName; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java new file mode 100644 index 0000000..d9eb71d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java @@ -0,0 +1,144 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysOperLog; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 操作日志记录视图对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysOperLog.class) +public class SysOperLogVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @ExcelProperty(value = "日志主键") + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 模块标题 + */ + @ExcelProperty(value = "操作模块") + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + @ExcelProperty(value = "业务类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_oper_type") + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + @ExcelProperty(value = "请求方法") + private String method; + + /** + * 请求方式 + */ + @ExcelProperty(value = "请求方式") + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + @ExcelProperty(value = "操作类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + + /** + * 操作人员 + */ + @ExcelProperty(value = "操作人员") + private String operName; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 请求URL + */ + @ExcelProperty(value = "请求地址") + private String operUrl; + + /** + * 主机地址 + */ + @ExcelProperty(value = "操作地址") + private String operIp; + + /** + * 操作地点 + */ + @ExcelProperty(value = "操作地点") + private String operLocation; + + /** + * 请求参数 + */ + @ExcelProperty(value = "请求参数") + private String operParam; + + /** + * 返回参数 + */ + @ExcelProperty(value = "返回参数") + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private Integer status; + + /** + * 错误消息 + */ + @ExcelProperty(value = "错误消息") + private String errorMsg; + + /** + * 操作时间 + */ + @ExcelProperty(value = "操作时间") + private Date operTime; + + /** + * 消耗时间 + */ + @ExcelProperty(value = "消耗时间") + private Long costTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java new file mode 100644 index 0000000..e7cfde4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java @@ -0,0 +1,97 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import org.dromara.system.domain.SysOssConfig; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 对象存储配置视图对象 sys_oss_config + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysOssConfig.class) +public class SysOssConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long ossConfigId; + + /** + * 配置key + */ + private String configKey; + + /** + * accessKey + */ + private String accessKey; + + /** + * 秘钥 + */ + private String secretKey; + + /** + * 桶名称 + */ + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + private String endpoint; + + /** + * 自定义域名 + */ + private String domain; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + + /** + * 域 + */ + private String region; + + /** + * 是否默认(0=是,1=否) + */ + private String status; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java new file mode 100644 index 0000000..11e0ff8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java @@ -0,0 +1,28 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +/** + * 上传对象信息 + * + * @author Michelle.Chung + */ +@Data +public class SysOssUploadVo { + + /** + * URL地址 + */ + private String url; + + /** + * 文件名 + */ + private String fileName; + + /** + * 对象存储主键 + */ + private String ossId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java new file mode 100644 index 0000000..8d5c429 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java @@ -0,0 +1,72 @@ +package org.dromara.system.domain.vo; + +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysOss; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * OSS对象存储视图对象 sys_oss + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysOss.class) +public class SysOssVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 对象存储主键 + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 上传人 + */ + private Long createBy; + + /** + * 上传人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + private String createByName; + + /** + * 服务商 + */ + private String service; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java new file mode 100644 index 0000000..69be547 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java @@ -0,0 +1,91 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysPost; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 岗位信息视图对象 sys_post + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysPost.class) +public class SysPostVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 岗位ID + */ + @ExcelProperty(value = "岗位序号") + private Long postId; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 岗位编码 + */ + @ExcelProperty(value = "岗位编码") + private String postCode; + + /** + * 岗位名称 + */ + @ExcelProperty(value = "岗位名称") + private String postName; + + /** + * 岗位类别编码 + */ + @ExcelProperty(value = "类别编码") + private String postCategory; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "岗位排序") + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 部门名 + */ + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java new file mode 100644 index 0000000..b0ed7ea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java @@ -0,0 +1,112 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysRole; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 角色信息视图对象 sys_role + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysRole.class) +public class SysRoleVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + @ExcelProperty(value = "角色序号") + private Long roleId; + + /** + * 角色名称 + */ + @ExcelProperty(value = "角色名称") + private String roleName; + + /** + * 角色权限字符串 + */ + @ExcelProperty(value = "角色权限") + private String roleKey; + + /** + * 部门ID + */ + @ExcelProperty(value = "部门") + private Long deptId; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "角色排序") + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + */ + @ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + @ExcelProperty(value = "菜单树选择项是否关联显示") + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + @ExcelProperty(value = "部门树选择项是否关联显示") + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + @ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 是否特殊角色(0否 1是) + */ + @ExcelProperty(value = "是否特殊角色(0否 1是)") + private String isSpecial; + + /** + * 用户是否存在此角色标识 默认不存在 + */ + private boolean flag = false; + + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ID.equals(this.roleId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java new file mode 100644 index 0000000..948dbcc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java @@ -0,0 +1,144 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysSocial; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 社会化关系视图对象 sys_social + * + * @author thiszhc + */ +@Data +@AutoMapper(target = SysSocial.class) +public class SysSocialVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 的唯一ID + */ + private String authId; + + /** + * 用户来源 + */ + private String source; + + /** + * 用户的授权令牌 + */ + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 用户的 open id + */ + private String openId; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + /** + * 创建时间 + */ + private Date createTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java new file mode 100644 index 0000000..070334b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java @@ -0,0 +1,66 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysTenantPackage; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 租户套餐视图对象 sys_tenant_package + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysTenantPackage.class) +public class SysTenantPackageVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户套餐id + */ + @ExcelProperty(value = "租户套餐id") + private Long packageId; + + /** + * 套餐名称 + */ + @ExcelProperty(value = "套餐名称") + private String packageName; + + /** + * 关联菜单id + */ + @ExcelProperty(value = "关联菜单id") + private String menuIds; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 菜单树选择项是否关联显示 + */ + @ExcelProperty(value = "菜单树选择项是否关联显示") + private Boolean menuCheckStrictly; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java new file mode 100644 index 0000000..6a45315 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java @@ -0,0 +1,115 @@ +package org.dromara.system.domain.vo; + +import java.util.Date; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysTenant; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 租户视图对象 sys_tenant + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysTenant.class) +public class SysTenantVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 租户编号 + */ + @ExcelProperty(value = "租户编号") + private String tenantId; + + /** + * 联系人 + */ + @ExcelProperty(value = "联系人") + private String contactUserName; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String contactPhone; + + /** + * 企业名称 + */ + @ExcelProperty(value = "企业名称") + private String companyName; + + /** + * 统一社会信用代码 + */ + @ExcelProperty(value = "统一社会信用代码") + private String licenseNumber; + + /** + * 地址 + */ + @ExcelProperty(value = "地址") + private String address; + + /** + * 域名 + */ + @ExcelProperty(value = "域名") + private String domain; + + /** + * 企业简介 + */ + @ExcelProperty(value = "企业简介") + private String intro; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 租户套餐编号 + */ + @ExcelProperty(value = "租户套餐编号") + private Long packageId; + + /** + * 过期时间 + */ + @ExcelProperty(value = "过期时间") + private Date expireTime; + + /** + * 用户数量(-1不限制) + */ + @ExcelProperty(value = "用户数量") + private Long accountCount; + + /** + * 租户状态(0正常 1停用) + */ + @ExcelProperty(value = "租户状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java new file mode 100644 index 0000000..37ec6b7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java @@ -0,0 +1,96 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.ReverseAutoMapping; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 用户对象导出VO + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class SysUserExportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 最后登录IP + */ + @ExcelProperty(value = "最后登录IP") + private String loginIp; + + /** + * 最后登录时间 + */ + @ExcelProperty(value = "最后登录时间") + private Date loginDate; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 负责人 + */ + @ExcelProperty(value = "部门负责人") + private String leaderName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserFileVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserFileVo.java new file mode 100644 index 0000000..4dd07e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserFileVo.java @@ -0,0 +1,46 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysUserFile; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 用户文件关联视图对象 sys_user_file + * + * @author lilemy + * @date 2025-06-25 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysUserFile.class) +public class SysUserFileVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 文件id + */ + @ExcelProperty(value = "文件id") + private Long fileId; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java new file mode 100644 index 0000000..c34a23c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java @@ -0,0 +1,76 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户对象导入VO + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +// @Accessors(chain = true) // 导入不允许使用 会找不到set方法 +public class SysUserImportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 部门ID + */ + @ExcelProperty(value = "部门编号") + private Long deptId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java new file mode 100644 index 0000000..e41355d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java @@ -0,0 +1,40 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 用户信息 + * + * @author Michelle.Chung + */ +@Data +public class SysUserInfoVo { + + /** + * 用户信息 + */ + private SysUserVo user; + + /** + * 角色ID列表 + */ + private List roleIds; + + /** + * 角色列表 + */ + private List roles; + + /** + * 岗位ID列表 + */ + private List postIds; + + /** + * 岗位列表 + */ + private List posts; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java new file mode 100644 index 0000000..9e35b62 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java @@ -0,0 +1,147 @@ +package org.dromara.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.sensitive.annotation.Sensitive; +import org.dromara.common.sensitive.core.SensitiveStrategy; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysUser; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 用户信息视图对象 sys_user + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysUser.class) +public class SysUserVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户文件列表 + */ + private String filePath; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit") + private String email; + + /** + * 手机号码 + */ + @Sensitive(strategy = SensitiveStrategy.PHONE, perms = "system:user:edit") + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 头像地址 + */ + @Translation(type = TransConstant.OSS_ID_TO_URL) + private Long avatar; + + /** + * 密码 + */ + @JsonIgnore + @JsonProperty + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private Date loginDate; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 部门名 + */ + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; + + /** + * 角色对象 + */ + private List roles; + + /** + * 角色组 + */ + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java new file mode 100644 index 0000000..d9e118e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java @@ -0,0 +1,35 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.Set; + +/** + * 登录用户信息 + * + * @author Michelle.Chung + */ +@Data +public class UserInfoVo { + + /** + * 用户基本信息 + */ + private SysUserVo user; + + /** + * 菜单权限 + */ + private Set permissions; + + /** + * 角色权限 + */ + private Set roles; + + /** + * 分包公司ID + */ + private Long contractorId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java new file mode 100644 index 0000000..25b62a9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java @@ -0,0 +1,127 @@ +package org.dromara.system.listener; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.BCrypt; +import cn.hutool.http.HtmlUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.excel.core.ExcelListener; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserImportVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.ISysUserService; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 系统用户自定义导入 + * + * @author Lion Li + */ +@Slf4j +public class SysUserImportListener extends AnalysisEventListener implements ExcelListener { + + private final ISysUserService userService; + + private final String password; + + private final Boolean isUpdateSupport; + + private final Long operUserId; + + private int successNum = 0; + private int failureNum = 0; + private final StringBuilder successMsg = new StringBuilder(); + private final StringBuilder failureMsg = new StringBuilder(); + + public SysUserImportListener(Boolean isUpdateSupport) { + String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword"); + this.userService = SpringUtils.getBean(ISysUserService.class); + this.password = BCrypt.hashpw(initPassword); + this.isUpdateSupport = isUpdateSupport; + this.operUserId = LoginHelper.getUserId(); + } + + @Override + public void invoke(SysUserImportVo userVo, AnalysisContext context) { + SysUserVo sysUser = this.userService.selectUserByUserName(userVo.getUserName()); + try { + // 验证是否存在这个用户 + if (ObjectUtil.isNull(sysUser)) { + SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class); + ValidatorUtils.validate(user); + user.setPassword(password); + user.setCreateBy(operUserId); + userService.insertUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功"); + } else if (isUpdateSupport) { + Long userId = sysUser.getUserId(); + SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class); + user.setUserId(userId); + ValidatorUtils.validate(user); + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + user.setUpdateBy(operUserId); + userService.updateUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功"); + } else { + failureNum++; + failureMsg.append("
").append(failureNum).append("、账号 ").append(sysUser.getUserName()).append(" 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、账号 " + HtmlUtil.cleanHtmlTag(userVo.getUserName()) + " 导入失败:"; + String message = e.getMessage(); + if (e instanceof ConstraintViolationException cvException) { + message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", "); + } + failureMsg.append(msg).append(message); + log.error(msg, e); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + + @Override + public ExcelResult getExcelResult() { + return new ExcelResult<>() { + + @Override + public String getAnalysis() { + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + @Override + public List getList() { + return null; + } + + @Override + public List getErrorList() { + return null; + } + }; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java new file mode 100644 index 0000000..15bcfb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java @@ -0,0 +1,15 @@ +package org.dromara.system.mapper; + +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 授权管理Mapper接口 + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +public interface SysClientMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..0eaaee8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysConfig; +import org.dromara.system.domain.vo.SysConfigVo; + +/** + * 参数配置 数据层 + * + * @author Lion Li + */ +public interface SysConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java new file mode 100644 index 0000000..aa7bd50 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java @@ -0,0 +1,97 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.vo.SysDeptVo; + +import java.util.List; + +/** + * 部门管理 数据层 + * + * @author Lion Li + */ +public interface SysDeptMapper extends BaseMapperPlus { + + /** + * 查询部门管理数据 + * + * @param queryWrapper 查询条件 + * @return 部门信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id") + }) + List selectDeptList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询部门管理数据 + * + * @param queryWrapper 查询条件 + * @return 部门信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + }) + Page selectPageDeptList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 统计指定部门ID的部门数量 + * + * @param deptId 部门ID + * @return 该部门ID的部门数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id") + }) + long countDeptById(Long deptId); + + /** + * 根据父部门ID查询其所有子部门的列表 + * + * @param parentId 父部门ID + * @return 包含子部门的列表 + */ + default List selectListByParentId(Long parentId) { + return this.selectList(new LambdaQueryWrapper() + .select(SysDept::getDeptId) + .apply(DataBaseHelper.findInSet(parentId, "ancestors"))); + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @param deptCheckStrictly 部门树选择项是否关联显示 + * @return 选中部门列表 + */ + List selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly); + + @Select(""" + WITH RECURSIVE dept_tree AS ( + SELECT dept_id, parent_id, project_id, dept_type + FROM sys_dept + WHERE dept_id = #{deptId} + + UNION ALL + + SELECT d.dept_id, d.parent_id, d.project_id, d.dept_type + FROM sys_dept d + INNER JOIN dept_tree dt ON d.parent_id = dt.dept_id + ) + SELECT DISTINCT project_id + FROM dept_tree + WHERE dept_type = '3' AND project_id IS NOT NULL + """) + List getProjectIdsByDept(@Param("deptId") Long deptId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java new file mode 100644 index 0000000..7298db3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java @@ -0,0 +1,29 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysDictData; +import org.dromara.system.domain.vo.SysDictDataVo; + +import java.util.List; + +/** + * 字典表 数据层 + * + * @author Lion Li + */ +public interface SysDictDataMapper extends BaseMapperPlus { + + /** + * 根据字典类型查询字典数据列表 + * + * @param dictType 字典类型 + * @return 符合条件的字典数据列表 + */ + default List selectDictDataByType(String dictType) { + return selectVoList( + new LambdaQueryWrapper() + .eq(SysDictData::getDictType, dictType) + .orderByAsc(SysDictData::getDictSort)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java new file mode 100644 index 0000000..9a9bdd5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.system.domain.SysDictType; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.vo.SysDictTypeVo; + +/** + * 字典表 数据层 + * + * @author Lion Li + */ +public interface SysDictTypeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java new file mode 100644 index 0000000..85edd1d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysLogininfor; +import org.dromara.system.domain.vo.SysLogininforVo; + +/** + * 系统访问日志情况信息 数据层 + * + * @author Lion Li + */ +public interface SysLogininforMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..205413b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java @@ -0,0 +1,76 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.vo.SysMenuVo; + +import java.util.List; + +/** + * 菜单表 数据层 + * + * @author Lion Li + */ +public interface SysMenuMapper extends BaseMapperPlus { + + /** + * 根据用户查询系统菜单列表 + * + * @param queryWrapper 查询条件 + * @return 菜单列表 + */ + List selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + List selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + List selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询菜单 + * + * @return 菜单列表 + */ + default List selectMenuTreeAll() { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU) + .eq(SysMenu::getStatus, SystemConstants.NORMAL) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum); + return this.selectList(lqw); + } + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @param menuCheckStrictly 菜单树选择项是否关联显示 + * @return 选中菜单列表 + */ + List selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java new file mode 100644 index 0000000..1e27b77 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysNotice; +import org.dromara.system.domain.vo.SysNoticeVo; + +/** + * 通知公告表 数据层 + * + * @author Lion Li + */ +public interface SysNoticeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000..5d20404 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOperLog; +import org.dromara.system.domain.vo.SysOperLogVo; + +/** + * 操作日志 数据层 + * + * @author Lion Li + */ +public interface SysOperLogMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java new file mode 100644 index 0000000..f93d34d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java @@ -0,0 +1,16 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOssConfig; +import org.dromara.system.domain.vo.SysOssConfigVo; + +/** + * 对象存储配置Mapper接口 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +public interface SysOssConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java new file mode 100644 index 0000000..3da621d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOss; +import org.dromara.system.domain.vo.SysOssVo; + +/** + * 文件上传 数据层 + * + * @author Lion Li + */ +public interface SysOssMapper extends BaseMapperPlus { +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java new file mode 100644 index 0000000..60da074 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java @@ -0,0 +1,43 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.vo.SysPostVo; + +import java.util.List; + +/** + * 岗位信息 数据层 + * + * @author Lion Li + */ +public interface SysPostMapper extends BaseMapperPlus { + + /** + * 分页查询岗位列表 + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 包含岗位信息的分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + Page selectPagePostList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + List selectPostsByUserId(Long userId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 0000000..3de0bb6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRoleDept; + +/** + * 角色与部门关联表 数据层 + * + * @author Lion Li + */ +public interface SysRoleDeptMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..9cb1ea5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java @@ -0,0 +1,75 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.vo.SysRoleVo; + +import java.util.List; + +/** + * 角色表 数据层 + * + * @author Lion Li + */ +public interface SysRoleMapper extends BaseMapperPlus { + + /** + * 分页查询角色列表 + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 包含角色信息的分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "r.create_by") + }) + Page selectPageRoleList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询角色数据 + * + * @param queryWrapper 查询条件 + * @return 角色数据集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "r.create_by") + }) + List selectRoleList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据角色ID查询角色信息 + * + * @param roleId 角色ID + * @return 对应的角色信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "r.create_by") + }) + SysRoleVo selectRoleById(Long roleId); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolePermissionByUserId(Long userId); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesByUserId(Long userId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..0a657b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRoleMenu; + +/** + * 角色与菜单关联表 数据层 + * + * @author Lion Li + */ +public interface SysRoleMenuMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java new file mode 100644 index 0000000..b942061 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysSocial; +import org.dromara.system.domain.vo.SysSocialVo; + +/** + * 社会化关系Mapper接口 + * + * @author thiszhc + */ +public interface SysSocialMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java new file mode 100644 index 0000000..7e1167a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.system.domain.SysTenant; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 租户Mapper接口 + * + * @author Michelle.Chung + */ +public interface SysTenantMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java new file mode 100644 index 0000000..10ca170 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysTenantPackage; +import org.dromara.system.domain.vo.SysTenantPackageVo; + +/** + * 租户套餐Mapper接口 + * + * @author Michelle.Chung + */ +public interface SysTenantPackageMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserFileMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserFileMapper.java new file mode 100644 index 0000000..8e6944e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserFileMapper.java @@ -0,0 +1,15 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUserFile; +import org.dromara.system.domain.vo.SysUserFileVo; + +/** + * 用户文件关联Mapper接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface SysUserFileMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..46695aa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java @@ -0,0 +1,123 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysUserExportVo; +import org.dromara.system.domain.vo.SysUserVo; + +import java.util.List; + +/** + * 用户表 数据层 + * + * @author Lion Li + */ +public interface SysUserMapper extends BaseMapperPlus { + + /** + * 分页查询用户列表,并进行数据权限控制 + * + * @param page 分页参数 + * @param queryWrapper 查询条件 + * @return 分页的用户信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "u.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectPageUserList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 查询用户列表,并进行数据权限控制 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + List selectUserList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询用户列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + List selectUserExportList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询已配用户角色列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectAllocatedList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectUnallocatedList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据用户ID统计用户数量 + * + * @param userId 用户ID + * @return 用户数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + long countUserById(Long userId); + + /** + * 根据条件更新用户数据 + * + * @param user 要更新的用户实体 + * @param updateWrapper 更新条件封装器 + * @return 更新操作影响的行数 + */ + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper updateWrapper); + + /** + * 根据用户ID更新用户数据 + * + * @param user 要更新的用户实体 + * @return 更新操作影响的行数 + */ + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int updateById(@Param(Constants.ENTITY) SysUser user); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java new file mode 100644 index 0000000..07c1371 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUserPost; + +/** + * 用户与岗位关联表 数据层 + * + * @author Lion Li + */ +public interface SysUserPostMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..8340348 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,23 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUserRole; + +import java.util.List; + +/** + * 用户与角色关联表 数据层 + * + * @author Lion Li + */ +public interface SysUserRoleMapper extends BaseMapperPlus { + + /** + * 根据角色ID查询关联的用户ID列表 + * + * @param roleId 角色ID + * @return 关联到指定角色的用户ID列表 + */ + List selectUserIdsByRoleId(Long roleId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java new file mode 100644 index 0000000..27dad7d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java @@ -0,0 +1,28 @@ +package org.dromara.system.runner; + +import org.dromara.system.service.ISysOssConfigService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * 初始化 system 模块对应业务数据 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class SystemApplicationRunner implements ApplicationRunner { + + private final ISysOssConfigService ossConfigService; + + @Override + public void run(ApplicationArguments args) throws Exception { + ossConfigService.init(); + log.info("初始化OSS配置成功"); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java new file mode 100644 index 0000000..546c3f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java @@ -0,0 +1,60 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 客户端管理Service接口 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +public interface ISysClientService { + + /** + * 查询客户端管理 + */ + SysClientVo queryById(Long id); + + /** + * 查询客户端信息基于客户端id + */ + SysClientVo queryByClientId(String clientId); + + /** + * 查询客户端管理列表 + */ + TableDataInfo queryPageList(SysClientBo bo, PageQuery pageQuery); + + /** + * 查询客户端管理列表 + */ + List queryList(SysClientBo bo); + + /** + * 新增客户端管理 + */ + Boolean insertByBo(SysClientBo bo); + + /** + * 修改客户端管理 + */ + Boolean updateByBo(SysClientBo bo); + + /** + * 修改状态 + */ + int updateClientStatus(String clientId, String status); + + /** + * 校验并批量删除客户端管理信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java new file mode 100644 index 0000000..f7efda7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java @@ -0,0 +1,87 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; + +import java.util.List; + +/** + * 参数配置 服务层 + * + * @author Lion Li + */ +public interface ISysConfigService { + + + TableDataInfo selectPageConfigList(SysConfigBo config, PageQuery pageQuery); + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + SysConfigVo selectConfigById(Long configId); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + String selectConfigByKey(String configKey); + + /** + * 获取注册开关 + * @param tenantId 租户id + * @return true开启,false关闭 + */ + boolean selectRegisterEnabled(String tenantId); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + List selectConfigList(SysConfigBo config); + + /** + * 新增参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + String insertConfig(SysConfigBo bo); + + /** + * 修改参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + String updateConfig(SysConfigBo bo); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + void deleteConfigByIds(Long[] configIds); + + /** + * 重置参数缓存数据 + */ + void resetConfigCache(); + + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + boolean checkConfigKeyUnique(SysConfigBo config); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java new file mode 100644 index 0000000..3f252f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java @@ -0,0 +1,26 @@ +package org.dromara.system.service; + +/** + * 通用 数据权限 服务 + * + * @author Lion Li + */ +public interface ISysDataScopeService { + + /** + * 获取角色自定义权限 + * + * @param roleId 角色id + * @return 部门id组 + */ + String getRoleCustom(Long roleId); + + /** + * 获取部门及以下权限 + * + * @param deptId 部门id + * @return 部门id组 + */ + String getDeptAndChild(Long deptId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java new file mode 100644 index 0000000..ab62e8a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java @@ -0,0 +1,165 @@ +package org.dromara.system.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; + +import java.util.List; + +/** + * 部门管理 服务层 + * + * @author Lion Li + */ +public interface ISysDeptService { + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + List selectDeptList(SysDeptBo dept); + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + List> selectDeptTreeList(SysDeptBo dept); + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + List> buildDeptTreeSelect(List depts); + + /** + * 构建前端所需要下拉树结构 + * + * @param projectId 项目id + * @return 下拉树结构列表 + */ + List> buildDeptTreeByProjectId(Long projectId); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + List selectDeptListByRoleId(Long roleId); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + SysDeptVo selectDeptById(Long deptId); + +// /** +// * 根据部门ID查询信息 +// * +// * @return 部门信息 +// */ +// SysDeptBo selectDeptByIdBo(SysDeptBo dept); + + /** + * 根据部门ID查询所属项目ID列表 + * + * @param deptId 部门id + * @return 项目id列表 + */ + List selectProjectIdById(Long deptId); + + + /** + * 通过部门名称查询部门ID + * + * @param deptName 部门名称 + * @return 部门ID + */ + Long selectIdByDeptName(String deptName); + + /** + * 通过部门ID串查询部门 + * + * @param deptIds 部门id串 + * @return 部门列表信息 + */ + List selectDeptByIds(List deptIds); + + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + long selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在部门子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + boolean hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + boolean checkDeptNameUnique(SysDeptBo dept); + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + void checkDeptDataScope(Long deptId); + + /** + * 校验部门和角色是否匹配 + * + * @param deptId 部门id + * @param roleIds 角色id列表 + */ + void checkDeptMatchRole(Long deptId, List roleIds); + + /** + * 新增保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + int insertDept(SysDeptBo bo); + + /** + * 修改保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + int updateDept(SysDeptBo bo); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + int deleteDeptById(Long deptId); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java new file mode 100644 index 0000000..0e697db --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java @@ -0,0 +1,76 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author Lion Li + */ +public interface ISysDictDataService { + + + TableDataInfo selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery); + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + List selectDictDataList(SysDictDataBo dictData); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + String selectDictLabel(String dictType, String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + SysDictDataVo selectDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + void deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + List insertDictData(SysDictDataBo bo); + + /** + * 修改保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + List updateDictData(SysDictDataBo bo); + + /** + * 校验字典键值是否唯一 + * + * @param dict 字典数据 + * @return 结果 + */ + boolean checkDictDataUnique(SysDictDataBo dict); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java new file mode 100644 index 0000000..3b32d6c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java @@ -0,0 +1,95 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysDictTypeVo; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author Lion Li + */ +public interface ISysDictTypeService { + + + TableDataInfo selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery); + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + List selectDictTypeList(SysDictTypeBo dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + List selectDictTypeAll(); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + List selectDictDataByType(String dictType); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + SysDictTypeVo selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + SysDictTypeVo selectDictTypeByType(String dictType); + + /** + * 批量删除字典信息 + * + * @param dictIds 需要删除的字典ID + */ + void deleteDictTypeByIds(Long[] dictIds); + + /** + * 重置字典缓存数据 + */ + void resetDictCache(); + + /** + * 新增保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + List insertDictType(SysDictTypeBo bo); + + /** + * 修改保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + List updateDictType(SysDictTypeBo bo); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + boolean checkDictTypeUnique(SysDictTypeBo dictType); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java new file mode 100644 index 0000000..6b3b7a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java @@ -0,0 +1,47 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysLogininforBo; +import org.dromara.system.domain.vo.SysLogininforVo; + +import java.util.List; + +/** + * 系统访问日志情况信息 服务层 + * + * @author Lion Li + */ +public interface ISysLogininforService { + + + TableDataInfo selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery); + + /** + * 新增系统登录日志 + * + * @param bo 访问日志对象 + */ + void insertLogininfor(SysLogininforBo bo); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + List selectLogininforList(SysLogininforBo logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + */ + void cleanLogininfor(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java new file mode 100644 index 0000000..72d705e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java @@ -0,0 +1,147 @@ +package org.dromara.system.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; + +import java.util.List; +import java.util.Set; + +/** + * 菜单 业务层 + * + * @author Lion Li + */ +public interface ISysMenuService { + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(Long userId); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(SysMenuBo menu, Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + Set selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + List selectMenuListByRoleId(Long roleId); + + /** + * 根据租户套餐ID查询菜单树信息 + * + * @param packageId 租户套餐ID + * @return 选中菜单列表 + */ + List selectMenuListByPackageId(Long packageId); + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + List buildMenus(List menus); + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + List> buildMenuTreeSelect(List menus); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + SysMenuVo selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean hasChildByMenuId(Long menuId); + + /** + * 查询菜单是否存在角色 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkMenuExistRole(Long menuId); + + /** + * 新增保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + int insertMenu(SysMenuBo bo); + + /** + * 修改保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + int updateMenu(SysMenuBo bo); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + boolean checkMenuNameUnique(SysMenuBo menu); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java new file mode 100644 index 0000000..8ec999d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java @@ -0,0 +1,67 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; + +import java.util.List; + +/** + * 公告 服务层 + * + * @author Lion Li + */ +public interface ISysNoticeService { + + + TableDataInfo selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery); + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + SysNoticeVo selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + List selectNoticeList(SysNoticeBo notice); + + /** + * 新增公告 + * + * @param bo 公告信息 + * @return 结果 + */ + int insertNotice(SysNoticeBo bo); + + /** + * 修改公告 + * + * @param bo 公告信息 + * @return 结果 + */ + int updateNotice(SysNoticeBo bo); + + /** + * 删除公告信息 + * + * @param noticeId 公告ID + * @return 结果 + */ + int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java new file mode 100644 index 0000000..9573510 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java @@ -0,0 +1,54 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; + +import java.util.List; + +/** + * 操作日志 服务层 + * + * @author Lion Li + */ +public interface ISysOperLogService { + + TableDataInfo selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery); + + /** + * 新增操作日志 + * + * @param bo 操作日志对象 + */ + void insertOperlog(SysOperLogBo bo); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + List selectOperLogList(SysOperLogBo operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + SysOperLogVo selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + void cleanOperLog(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java new file mode 100644 index 0000000..2f6dfc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java @@ -0,0 +1,64 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; + +import java.util.Collection; + +/** + * 对象存储配置Service接口 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +public interface ISysOssConfigService { + + /** + * 初始化OSS配置 + */ + void init(); + + /** + * 查询单个 + */ + SysOssConfigVo queryById(Long ossConfigId); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(SysOssConfigBo bo, PageQuery pageQuery); + + /** + * 根据新增业务对象插入对象存储配置 + * + * @param bo 对象存储配置新增业务对象 + * @return 结果 + */ + Boolean insertByBo(SysOssConfigBo bo); + + /** + * 根据编辑业务对象修改对象存储配置 + * + * @param bo 对象存储配置编辑业务对象 + * @return 结果 + */ + Boolean updateByBo(SysOssConfigBo bo); + + /** + * 校验并删除数据 + * + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return 结果 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 启用停用状态 + */ + int updateOssConfigStatus(SysOssConfigBo bo); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java new file mode 100644 index 0000000..8b0ee97 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java @@ -0,0 +1,140 @@ +package org.dromara.system.service; + +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.List; + +/** + * 文件上传 服务层 + * + * @author Lion Li + */ +public interface ISysOssService { + + /** + * 查询OSS对象存储列表 + * + * @param sysOss OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ + TableDataInfo queryPageList(SysOssBo sysOss, PageQuery pageQuery); + + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ + List listByIds(Collection ossIds); + + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ + SysOssVo getById(Long ossId); + + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssVo upload(MultipartFile file); + + /** + * 上传 MultipartFile 到对象存储服务,不保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssUploadVo uploadWithNoSave(MultipartFile file); + + /** + * 上传 MultipartFile 到对象存储服务,不保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @param filePath 文件路径 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssUploadVo uploadWithNoSave(MultipartFile file, String filePath); + + /** + * 通过 url 上传到对象存储服务,不保存文件信息到数据库 + * + * @param fileUrl 要上传的文件url + * @param filePath 文件路径 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssUploadVo uploadFileUrlWithNoSave(String fileUrl, String filePath); + + /** + * 通过输入流上传到对象存储服务,不保存文件信息到数据库 + * + * @param inputStream 要上传的文件输入流 + * @param originalFileName 文件名 + * @param contentType 文件类型 + * @param length 文件长度 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssVo upload(InputStream inputStream, String originalFileName, String contentType, long length); + + /** + * 通过输入流上传到对象存储服务,不保存文件信息到数据库 + * + * @param inputStream 要上传的文件输入流 + * @param filePath 文件路径 + * @param contentType 文件类型 + * @param length 文件长度 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssUploadVo uploadFileUrlWithNoSave(InputStream inputStream, String filePath, String contentType, long length); + + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssVo upload(File file); + + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + * @param response HttpServletResponse对象,用于设置响应头和向客户端发送文件内容 + */ + void download(Long ossId, HttpServletResponse response) throws IOException; + + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + + /** + * MinioFileName 获取minio的即将存储文件的路径 + * + * @param prefix 前缀(举例:prefix) + * @param file 为了获取后缀(举例:.png) + * @return 返回全路径 + */ + String minioFileName(String prefix, MultipartFile file); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java new file mode 100644 index 0000000..0116df5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java @@ -0,0 +1,28 @@ +package org.dromara.system.service; + +import java.util.Set; + +/** + * 用户权限处理 + * + * @author Lion Li + */ +public interface ISysPermissionService { + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + Set getRolePermission(Long userId); + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + Set getMenuPermission(Long userId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java new file mode 100644 index 0000000..68f430b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java @@ -0,0 +1,146 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; + +import java.util.List; + +/** + * 岗位信息 服务层 + * + * @author Lion Li + */ +public interface ISysPostService { + + + TableDataInfo selectPagePostList(SysPostBo post, PageQuery pageQuery); + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位列表 + */ + List selectPostList(SysPostBo post); + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 岗位ID + */ + List selectPostsByUserId(Long userId); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + List selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + SysPostVo selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + List selectPostListByUserId(Long userId); + + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + List selectPostByIds(List postIds); + + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 结果 + */ + boolean checkPostNameUnique(SysPostBo post); + + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 结果 + */ + boolean checkPostCodeUnique(SysPostBo post); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + long countUserPostById(Long postId); + + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 结果 + */ + long countPostByDeptId(Long deptId); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + int deletePostByIds(Long[] postIds); + + /** + * 新增保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + int insertPost(SysPostBo bo); + + /** + * 批量新增岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + Boolean insertPost(List bo); + + /** + * 通过部门id批量新增默认岗位信息 + * + * @param deptId 部门id + * @return 结果 + */ + Boolean insertPostByDeptId(Long deptId); + + /** + * 修改保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + int updatePost(SysPostBo bo); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java new file mode 100644 index 0000000..cec4bf7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java @@ -0,0 +1,202 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; + +import java.util.List; +import java.util.Set; + +/** + * 角色业务层 + * + * @author Lion Li + */ +public interface ISysRoleService { + + + TableDataInfo selectPageRoleList(SysRoleBo role, PageQuery pageQuery); + + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + List selectRoleList(SysRoleBo role); + + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesByUserId(Long userId); + + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesAuthByUserId(Long userId); + + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + List selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + List selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + SysRoleVo selectRoleById(Long roleId); + + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + List selectRoleByIds(List roleIds); + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + boolean checkRoleNameUnique(SysRoleBo role); + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + boolean checkRoleKeyUnique(SysRoleBo role); + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + void checkRoleAllowed(SysRoleBo role); + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + void checkRoleDataScope(Long roleId); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + long countUserRoleByRoleId(Long roleId); + + /** + * 新增保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + int insertRole(SysRoleBo bo); + + /** + * 修改保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + int updateRole(SysRoleBo bo); + + /** + * 修改角色状态 + * + * @param roleId 角色ID + * @param status 角色状态 + * @return 结果 + */ + int updateRoleStatus(Long roleId, String status); + + /** + * 修改数据权限信息 + * + * @param bo 角色信息 + * @return 结果 + */ + int authDataScope(SysRoleBo bo); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + int deleteRoleByIds(Long[] roleIds); + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + int deleteAuthUser(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + int deleteAuthUsers(Long roleId, Long[] userIds); + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + int insertAuthUsers(Long roleId, Long[] userIds); + + void cleanOnlineUserByRole(Long roleId); + + void cleanOnlineUser(List userIds); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java new file mode 100644 index 0000000..cc7016e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java @@ -0,0 +1,53 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.SysSocialVo; + +import java.util.List; + +/** + * 社会化关系Service接口 + * + * @author thiszhc + */ +public interface ISysSocialService { + + + /** + * 查询社会化关系 + */ + SysSocialVo queryById(String id); + + /** + * 查询社会化关系列表 + */ + List queryList(SysSocialBo bo); + + /** + * 查询社会化关系列表 + */ + List queryListByUserId(Long userId); + + /** + * 新增授权关系 + */ + Boolean insertByBo(SysSocialBo bo); + + /** + * 更新社会化关系 + */ + Boolean updateByBo(SysSocialBo bo); + + /** + * 删除社会化关系信息 + */ + Boolean deleteWithValidById(Long id); + + + /** + * 根据 authId 查询 + */ + List selectByAuthId(String authId); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java new file mode 100644 index 0000000..d060b68 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java @@ -0,0 +1,62 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysTenantPackageBo; +import org.dromara.system.domain.vo.SysTenantPackageVo; + +import java.util.Collection; +import java.util.List; + +/** + * 租户套餐Service接口 + * + * @author Michelle.Chung + */ +public interface ISysTenantPackageService { + + /** + * 查询租户套餐 + */ + SysTenantPackageVo queryById(Long packageId); + + /** + * 查询租户套餐列表 + */ + TableDataInfo queryPageList(SysTenantPackageBo bo, PageQuery pageQuery); + + /** + * 查询租户套餐已启用列表 + */ + List selectList(); + + /** + * 查询租户套餐列表 + */ + List queryList(SysTenantPackageBo bo); + + /** + * 新增租户套餐 + */ + Boolean insertByBo(SysTenantPackageBo bo); + + /** + * 修改租户套餐 + */ + Boolean updateByBo(SysTenantPackageBo bo); + + /** + * 校验套餐名称是否唯一 + */ + boolean checkPackageNameUnique(SysTenantPackageBo bo); + + /** + * 修改套餐状态 + */ + int updatePackageStatus(SysTenantPackageBo bo); + + /** + * 校验并批量删除租户套餐信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java new file mode 100644 index 0000000..f697829 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java @@ -0,0 +1,87 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 租户Service接口 + * + * @author Michelle.Chung + */ +public interface ISysTenantService { + + /** + * 查询租户 + */ + SysTenantVo queryById(Long id); + + /** + * 基于租户ID查询租户 + */ + SysTenantVo queryByTenantId(String tenantId); + + /** + * 查询租户列表 + */ + TableDataInfo queryPageList(SysTenantBo bo, PageQuery pageQuery); + + /** + * 查询租户列表 + */ + List queryList(SysTenantBo bo); + + /** + * 新增租户 + */ + Boolean insertByBo(SysTenantBo bo); + + /** + * 修改租户 + */ + Boolean updateByBo(SysTenantBo bo); + + /** + * 修改租户状态 + */ + int updateTenantStatus(SysTenantBo bo); + + /** + * 校验租户是否允许操作 + */ + void checkTenantAllowed(String tenantId); + + /** + * 校验并批量删除租户信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 校验企业名称是否唯一 + */ + boolean checkCompanyNameUnique(SysTenantBo bo); + + /** + * 校验账号余额 + */ + boolean checkAccountBalance(String tenantId); + + /** + * 校验有效期 + */ + boolean checkExpireTime(String tenantId); + + /** + * 同步租户套餐 + */ + Boolean syncTenantPackage(String tenantId, Long packageId); + + /** + * 同步租户字典 + */ + void syncTenantDict(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserFileService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserFileService.java new file mode 100644 index 0000000..5c2a2ba --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserFileService.java @@ -0,0 +1,103 @@ +package org.dromara.system.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysUserFile; +import org.dromara.system.domain.dto.userfile.SysUserFileCreateReq; +import org.dromara.system.domain.dto.userfile.SysUserFileQueryReq; +import org.dromara.system.domain.vo.SysUserFileVo; + +import java.util.List; + +/** + * 用户文件关联Service接口 + * + * @author lilemy + * @date 2025-06-25 + */ +public interface ISysUserFileService extends IService { + + /** + * 查询用户文件关联 + * + * @param id 主键 + * @return 用户文件关联 + */ + SysUserFileVo queryById(Long id); + + /** + * 分页查询用户文件关联列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 用户文件关联分页列表 + */ + TableDataInfo queryPageList(SysUserFileQueryReq req, PageQuery pageQuery); + + /** + * 查询符合条件的用户文件关联列表 + * + * @param req 查询条件 + * @return 用户文件关联列表 + */ + List queryList(SysUserFileQueryReq req); + + /** + * 根据用户ID查询用户文件关联列表 + * + * @param userId 用户ID + * @return 用户文件关联列表 + */ + List queryListByUserId(Long userId); + + /** + * 当前登录用户文件关联列表 + * + * @return 用户文件关联列表 + */ + List queryListByLoginUser(); + + /** + * 新增用户文件关联 + * + * @param req 用户文件关联 + * @return 是否新增成功 + */ + Boolean insertByBo(SysUserFileCreateReq req); + + /** + * 删除用户文件关联信息 + * + * @param id 待删除的主键 + * @return 是否删除成功 + */ + Boolean deleteById(Long id); + + /** + * 获取用户文件视图 + * + * @param userFile 用户文件 + * @return 用户文件视图 + */ + SysUserFileVo getVo(SysUserFile userFile); + + /** + * 获取用户和项目关联对象查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + LambdaQueryWrapper buildQueryWrapper(SysUserFileQueryReq req); + + /** + * 获取用户文件分页视图 + * + * @param userFilePage 用户文件分页 + * @return 用户文件分页视图 + */ + Page getVoPage(Page userFilePage); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java new file mode 100644 index 0000000..66e8388 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java @@ -0,0 +1,230 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserExportVo; +import org.dromara.system.domain.vo.SysUserVo; + +import java.util.List; + +/** + * 用户 业务层 + * + * @author Lion Li + */ +public interface ISysUserService { + + + TableDataInfo selectPageUserList(SysUserBo user, PageQuery pageQuery); + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + List selectUserExportList(SysUserBo user); + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + TableDataInfo selectAllocatedList(SysUserBo user, PageQuery pageQuery); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + TableDataInfo selectUnallocatedList(SysUserBo user, PageQuery pageQuery); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + SysUserVo selectUserByUserName(String userName); + + /** + * 通过手机号查询用户 + * + * @param phonenumber 手机号 + * @return 用户对象信息 + */ + SysUserVo selectUserByPhonenumber(String phonenumber); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + SysUserVo selectUserById(Long userId); + + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + List selectUserByIds(List userIds, Long deptId); + + /** + * 根据用户ID查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + String selectUserRoleGroup(Long userId); + + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + String selectUserPostGroup(Long userId); + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkUserNameUnique(SysUserBo user); + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkPhoneUnique(SysUserBo user); + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkEmailUnique(SysUserBo user); + + /** + * 校验用户是否允许操作 + * + * @param userId 用户ID + */ + void checkUserAllowed(Long userId); + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + void checkUserDataScope(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int insertUser(SysUserBo user); + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + boolean registerUser(SysUserBo user, String tenantId); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUser(SysUserBo user); + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + void insertUserAuth(Long userId, Long[] roleIds); + + /** + * 修改用户状态 + * + * @param userId 用户ID + * @param status 帐号状态 + * @return 结果 + */ + int updateUserStatus(Long userId, String status); + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUserProfile(SysUserBo user); + + /** + * 修改用户头像 + * + * @param userId 用户ID + * @param avatar 头像地址 + * @return 结果 + */ + boolean updateUserAvatar(Long userId, Long avatar); + + /** + * 重置用户密码 + * + * @param userId 用户ID + * @param password 密码 + * @return 结果 + */ + int resetUserPwd(Long userId, String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + int deleteUserByIds(Long[] userIds); + + /** + * 通过部门id查询当前部门所有用户 + * + * @param deptId 部门id + * @return 结果 + */ + List selectUserListByDept(Long deptId); + + /** + * 通过岗位id列表查询岗位所有用户 + * + * @param postIds 岗位id列表 + * @return 结果 + */ + List selectUserListByPostList(List postIds); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java new file mode 100644 index 0000000..4f6e676 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java @@ -0,0 +1,151 @@ +package org.dromara.system.service.impl; + +import cn.hutool.crypto.SecureUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.mapper.SysClientMapper; +import org.dromara.system.service.ISysClientService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; + +/** + * 客户端管理Service业务层处理 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysClientServiceImpl implements ISysClientService { + + private final SysClientMapper baseMapper; + + /** + * 查询客户端管理 + */ + @Override + public SysClientVo queryById(Long id) { + SysClientVo vo = baseMapper.selectVoById(id); + vo.setGrantTypeList(List.of(vo.getGrantType().split(","))); + return vo; + } + + + /** + * 查询客户端管理 + */ + @Cacheable(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") + @Override + public SysClientVo queryByClientId(String clientId) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysClient::getClientId, clientId)); + } + + /** + * 查询客户端管理列表 + */ + @Override + public TableDataInfo queryPageList(SysClientBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + result.getRecords().forEach(r -> r.setGrantTypeList(List.of(r.getGrantType().split(",")))); + return TableDataInfo.build(result); + } + + /** + * 查询客户端管理列表 + */ + @Override + public List queryList(SysClientBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysClientBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getClientId()), SysClient::getClientId, bo.getClientId()); + lqw.eq(StringUtils.isNotBlank(bo.getClientKey()), SysClient::getClientKey, bo.getClientKey()); + lqw.eq(StringUtils.isNotBlank(bo.getClientSecret()), SysClient::getClientSecret, bo.getClientSecret()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysClient::getStatus, bo.getStatus()); + lqw.orderByAsc(SysClient::getId); + return lqw; + } + + /** + * 新增客户端管理 + */ + @Override + public Boolean insertByBo(SysClientBo bo) { + SysClient add = MapstructUtils.convert(bo, SysClient.class); + validEntityBeforeSave(add); + add.setGrantType(String.join(",", bo.getGrantTypeList())); + // 生成clientid + String clientKey = bo.getClientKey(); + String clientSecret = bo.getClientSecret(); + add.setClientId(SecureUtil.md5(clientKey + clientSecret)); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改客户端管理 + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#bo.clientId") + @Override + public Boolean updateByBo(SysClientBo bo) { + SysClient update = MapstructUtils.convert(bo, SysClient.class); + validEntityBeforeSave(update); + update.setGrantType(String.join(",", bo.getGrantTypeList())); + return baseMapper.updateById(update) > 0; + } + + /** + * 修改状态 + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") + @Override + public int updateClientStatus(String clientId, String status) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysClient::getStatus, status) + .eq(SysClient::getClientId, clientId)); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysClient entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除客户端管理 + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, allEntries = true) + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..d92647c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,217 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.ConfigService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysConfig; +import org.dromara.system.domain.bo.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; +import org.dromara.system.mapper.SysConfigMapper; +import org.dromara.system.service.ISysConfigService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * 参数配置 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysConfigServiceImpl implements ISysConfigService, ConfigService { + + private final SysConfigMapper baseMapper; + + @Override + public TableDataInfo selectPageConfigList(SysConfigBo config, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(config); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + @Override + @DS("master") + public SysConfigVo selectConfigById(Long configId) { + return baseMapper.selectVoById(configId); + } + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数key + * @return 参数键值 + */ + @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey") + @Override + public String selectConfigByKey(String configKey) { + SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, configKey)); + return ObjectUtils.notNullGetter(retConfig, SysConfig::getConfigValue, StringUtils.EMPTY); + } + + /** + * 获取注册开关 + * @param tenantId 租户id + * @return true开启,false关闭 + */ + @Override + public boolean selectRegisterEnabled(String tenantId) { + SysConfig retConfig = TenantHelper.dynamic(tenantId, () -> { + return baseMapper.selectOne(new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, "sys.account.registerUser")); + }); + if (ObjectUtil.isNull(retConfig)) { + return false; + } + return Convert.toBool(retConfig.getConfigValue()); + } + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List selectConfigList(SysConfigBo config) { + LambdaQueryWrapper lqw = buildQueryWrapper(config); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysConfigBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getConfigName()), SysConfig::getConfigName, bo.getConfigName()); + lqw.eq(StringUtils.isNotBlank(bo.getConfigType()), SysConfig::getConfigType, bo.getConfigType()); + lqw.like(StringUtils.isNotBlank(bo.getConfigKey()), SysConfig::getConfigKey, bo.getConfigKey()); + lqw.between(params.get("beginTime") != null && params.get("endTime") != null, + SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime")); + lqw.orderByAsc(SysConfig::getConfigId); + return lqw; + } + + /** + * 新增参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey") + @Override + public String insertConfig(SysConfigBo bo) { + SysConfig config = MapstructUtils.convert(bo, SysConfig.class); + int row = baseMapper.insert(config); + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey") + @Override + public String updateConfig(SysConfigBo bo) { + int row = 0; + SysConfig config = MapstructUtils.convert(bo, SysConfig.class); + if (config.getConfigId() != null) { + SysConfig temp = baseMapper.selectById(config.getConfigId()); + if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) { + CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey()); + } + row = baseMapper.updateById(config); + } else { + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); + row = baseMapper.update(config, new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, config.getConfigKey())); + } + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + @Override + public void deleteConfigByIds(Long[] configIds) { + for (Long configId : configIds) { + SysConfig config = baseMapper.selectById(configId); + if (StringUtils.equals(SystemConstants.YES, config.getConfigType())) { + throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey())); + } + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); + } + baseMapper.deleteByIds(Arrays.asList(configIds)); + } + + /** + * 重置参数缓存数据 + */ + @Override + public void resetConfigCache() { + CacheUtils.clear(CacheNames.SYS_CONFIG); + } + + /** + * 校验参数键名是否唯一 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public boolean checkConfigKeyUnique(SysConfigBo config) { + long configId = ObjectUtils.notNull(config.getConfigId(), -1L); + SysConfig info = baseMapper.selectOne(new LambdaQueryWrapper().eq(SysConfig::getConfigKey, config.getConfigKey())); + if (ObjectUtil.isNotNull(info) && info.getConfigId() != configId) { + return false; + } + return true; + } + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + @Override + public String getConfigValue(String configKey) { + return SpringUtils.getAopProxy(this).selectConfigByKey(configKey); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java new file mode 100644 index 0000000..12a5072 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java @@ -0,0 +1,78 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysRoleDept; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysRoleDeptMapper; +import org.dromara.system.service.ISysDataScopeService; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 数据权限 实现 + *

+ * 注意: 此Service内不允许调用标注`数据权限`注解的方法 + * 例如: deptMapper.selectList 此 selectList 方法标注了`数据权限`注解 会出现循环解析的问题 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service("sdss") +public class SysDataScopeServiceImpl implements ISysDataScopeService { + + private final SysRoleDeptMapper roleDeptMapper; + private final SysDeptMapper deptMapper; + + /** + * 获取角色自定义权限 + * + * @param roleId 角色Id + * @return 部门Id组 + */ + @Cacheable(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId", condition = "#roleId != null") + @Override + public String getRoleCustom(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return "-1"; + } + List list = roleDeptMapper.selectList( + new LambdaQueryWrapper() + .select(SysRoleDept::getDeptId) + .eq(SysRoleDept::getRoleId, roleId)); + if (CollUtil.isNotEmpty(list)) { + return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId())); + } + return "-1"; + } + + /** + * 获取部门及以下权限 + * + * @param deptId 部门Id + * @return 部门Id组 + */ + @Cacheable(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId", condition = "#deptId != null") + @Override + public String getDeptAndChild(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return "-1"; + } + List deptList = deptMapper.selectListByParentId(deptId); + List ids = StreamUtils.toList(deptList, SysDept::getDeptId); + ids.add(deptId); + if (CollUtil.isNotEmpty(ids)) { + return StreamUtils.join(ids, Convert::toStr); + } + return "-1"; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 0000000..5e9301c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,746 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.dto.DeptDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DeptService; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.contractor.domain.SubContractor; +import org.dromara.contractor.domain.vo.contractor.SubContractorVo; +import org.dromara.contractor.service.ISubContractorService; +import org.dromara.project.domain.BusProject; +import org.dromara.project.domain.vo.project.BusProjectVo; +import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.IBusUserProjectRelevancyService; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.enums.SysDeptTypeEnum; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysPostMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysDeptService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 部门管理 服务实现 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysDeptServiceImpl implements ISysDeptService, DeptService { + + private final SysDeptMapper baseMapper; + private final SysRoleMapper roleMapper; + private final SysUserMapper userMapper; + private final SysPostMapper postMapper; + private final IBusProjectService projectService; + private final ISubContractorService contractorService; + private final IBusUserProjectRelevancyService userProjectRelevancyService; + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + public List selectDeptList(SysDeptBo dept) { + LambdaQueryWrapper lqw = buildQueryWrapper(dept); + return baseMapper.selectDeptList(lqw); + } + + /** + * 查询部门树结构信息 + * + * @param bo 部门信息 + * @return 部门树信息集合 + */ + @Override + public List> selectDeptTreeList(SysDeptBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List depts = baseMapper.selectDeptList(lqw); + return buildDeptTreeSelect(depts); + } + + private LambdaQueryWrapper buildQueryWrapper(SysDeptBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL); + lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId()); + lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId()); + lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName()); + lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptCategory, bo.getDeptCategory()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getIsShow()), SysDept::getIsShow, bo.getIsShow()); + lqw.eq(StringUtils.isNotBlank(bo.getDeptType()), SysDept::getDeptType, bo.getDeptType()); + lqw.orderByAsc(SysDept::getAncestors); + lqw.orderByAsc(SysDept::getParentId); + lqw.orderByAsc(SysDept::getOrderNum); + lqw.orderByAsc(SysDept::getDeptId); + return lqw; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildDeptTreeSelect(List depts) { + if (CollUtil.isEmpty(depts)) { + return CollUtil.newArrayList(); + } + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (SysDeptVo d : depts) { + Long parentId = d.getParentId(); + SysDeptVo sysDeptVo = StreamUtils.findFirst(depts, it -> it.getDeptId().longValue() == parentId); + if (ObjectUtil.isNull(sysDeptVo)) { + List> trees = TreeBuildUtils.build(depts, parentId, (dept, tree) -> { + tree.setId(dept.getDeptId()) + .setParentId(dept.getParentId()) + .setName(dept.getDeptName()) + .setWeight(dept.getOrderNum()) + .putExtra("disabled", SystemConstants.DISABLE.equals(dept.getStatus())); + tree.putExtra("deptType", dept.getDeptType()); + } + ); + Tree tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId()); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param projectId 项目id + * @return 下拉树结构列表 + */ + @Override + public List> buildDeptTreeByProjectId(Long projectId) { + SysDept dept = baseMapper.selectOne( + new LambdaQueryWrapper<>(SysDept.class) + .eq(SysDept::getProjectId, projectId) + .eq(SysDept::getDeptType, SysDeptTypeEnum.PROJECT.getCode()) + .eq(SysDept::getStatus, SystemConstants.NORMAL) + ); + if (dept == null) { + return List.of(); + } + List deptIds = Stream.concat( + Arrays.stream(dept.getAncestors().split(",")) + .filter(StringUtils::isNotBlank) + .map(Long::parseLong), + Stream.of(dept.getDeptId()) + ).toList(); + List deptVoList = baseMapper.selectVoByIds(deptIds); + List postVos = postMapper.selectVoList( + new LambdaQueryWrapper<>(SysPost.class) + .in(SysPost::getDeptId, deptIds) + .eq(SysPost::getStatus, SystemConstants.NORMAL) + ); + Map> postVoMap = postVos.stream().collect(Collectors.groupingBy(SysPostVo::getDeptId)); + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (SysDeptVo d : deptVoList) { + Long parentId = d.getParentId(); + SysDeptVo sysDeptVo = StreamUtils.findFirst(deptVoList, it -> it.getDeptId().longValue() == parentId); + if (ObjectUtil.isNull(sysDeptVo)) { + List> trees = TreeBuildUtils.build(deptVoList, parentId, (deptVo, tree) -> { + Long deptId = deptVo.getDeptId(); + tree.setId(deptId) + .setParentId(deptVo.getParentId()) + .setName(deptVo.getDeptName()) + .setWeight(deptVo.getOrderNum()) + .putExtra("disabled", SystemConstants.DISABLE.equals(deptVo.getStatus())); + tree.putExtra("deptType", deptVo.getDeptType()); + tree.putExtra("postVoList", postVoMap.get(deptId)); + } + ); + Tree tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId()); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + @Override + public List selectDeptListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + return baseMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly()); + } + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DEPT, key = "#deptId") + @Override + public SysDeptVo selectDeptById(Long deptId) { + SysDeptVo dept = baseMapper.selectVoById(deptId); + if (ObjectUtil.isNull(dept)) { + return null; + } + SysDeptVo parentDept = baseMapper.selectVoOne(new LambdaQueryWrapper() + .select(SysDept::getDeptName).eq(SysDept::getDeptId, dept.getParentId())); + dept.setParentName(ObjectUtils.notNullGetter(parentDept, SysDeptVo::getDeptName)); + dept.setParent(parentDept); + String deptType = dept.getDeptType(); + // 获取未绑定项目信息 + List projectVos = new ArrayList<>(projectService.queryListNoDept()); + // 获取项目部门绑定的项目信息 + if (deptType.equals(SysDeptTypeEnum.PROJECT.getCode()) && dept.getProjectId() != null) { + BusProjectVo vo = projectService.getVo(projectService.getById(dept.getProjectId())); + projectVos.add(vo); + } + dept.setProjectList(projectVos); + // 如果为分包部门,获取分包部门信息 + if (deptType.equals(SysDeptTypeEnum.CONTRACT.getCode())) { + List contractorVos = new ArrayList<>(contractorService.queryListNoDept(dept.getProjectId())); + SubContractorVo vo = contractorService.getVo(contractorService.getById(dept.getContractorId())); + contractorVos.add(vo); + dept.setContractorList(contractorVos); + } + return dept; + } + + /** + * 根据部门ID查询所属项目ID列表 + * + * @param deptId 部门id + * @return 项目id列表 + */ + @Override + public List selectProjectIdById(Long deptId) { + return baseMapper.getProjectIdsByDept(deptId); + } + +// /** +// * 根据部门ID查询信息 +// * +// * @return 部门信息 +// */ +// @Cacheable(cacheNames = CacheNames.SYS_DEPT, key = "#deptId") +// @Override +// public SysDeptBo selectDeptByIdBo(SysDeptBo bo) { +// SysDeptBo sysDeptBo = new SysDeptBo(); +// SysDeptVo dept = baseMapper.selectVoById(bo.getDeptId()); +// if (ObjectUtil.isNull(dept)) { +// return null; +// } +// SysDeptVo parentDept = baseMapper.selectVoOne(new LambdaQueryWrapper() +// .select(SysDept::getDeptName).eq(SysDept::getDeptId, dept.getParentId())); +// dept.setParentName(ObjectUtils.notNullGetter(parentDept, SysDeptVo::getDeptName)); +// +// //cory 获取角色信息 +// roleService.checkRoleDataScope(bo.getRoleId()); +// SysRoleVo sysRoleVo = roleService.selectRoleById(bo.getRoleId()); +// BeanUtils.copyProperties(dept,sysDeptBo); +// BeanUtils.copyProperties(sysRoleVo,sysDeptBo); +// sysDeptBo.setRoleSort(sysRoleVo.getRoleSort()); +// return sysDeptBo; +// } + + /** + * 通过部门名称查询部门ID + * + * @param deptName 部门名称 + * @return 部门ID + */ + @Override + public Long selectIdByDeptName(String deptName) { + SysDept dept = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysDept::getDeptId) + .eq(SysDept::getDeptName, deptName)); + return dept.getDeptId(); + } + + @Override + public List selectDeptByIds(List deptIds) { + return baseMapper.selectDeptList(new LambdaQueryWrapper() + .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getLeader) + .eq(SysDept::getStatus, SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(deptIds), SysDept::getDeptId, deptIds)); + } + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + @Override + public String selectDeptNameByIds(String deptIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(deptIds, Convert::toLong)) { + SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(id); + if (ObjectUtil.isNotNull(vo)) { + list.add(vo.getDeptName()); + } + } + return String.join(StringUtils.SEPARATOR, list); + } + + /** + * 根据部门ID查询部门负责人 + * + * @param deptId 部门ID,用于指定需要查询的部门 + * @return 返回该部门的负责人ID + */ + @Override + public Long selectDeptLeaderById(Long deptId) { + SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(deptId); + return vo.getLeader(); + } + + /** + * 查询部门 + * + * @return 部门列表 + */ + @Override + public List selectDeptsByList() { + List list = baseMapper.selectDeptList(new LambdaQueryWrapper() + .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId) + .eq(SysDept::getStatus, SystemConstants.NORMAL)); + return BeanUtil.copyToList(list, DeptDTO.class); + } + + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + @Override + public long selectNormalChildrenDeptById(Long deptId) { + return baseMapper.selectCount(new LambdaQueryWrapper() + .eq(SysDept::getStatus, SystemConstants.NORMAL) + .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); + } + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public boolean hasChildByDeptId(Long deptId) { + return baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDept::getParentId, deptId)); + } + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkDeptExistUser(Long deptId) { + return userMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getDeptId, deptId)); + } + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public boolean checkDeptNameUnique(SysDeptBo dept) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDept::getDeptName, dept.getDeptName()) + .eq(SysDept::getParentId, dept.getParentId()) + .ne(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId())); + return !exist; + } + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + @Override + public void checkDeptDataScope(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (baseMapper.countDeptById(deptId) == 0) { + throw new ServiceException("没有权限访问部门数据!"); + } + } + + /** + * 校验部门和角色是否匹配 + * + * @param deptId 部门id + * @param roleIds 角色id列表 + */ + @Override + public void checkDeptMatchRole(Long deptId, List roleIds) { + if (ObjectUtil.isNull(deptId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + List roleList = roleMapper.selectByIds(roleIds); + for (SysRole role : roleList) { + if (!role.getStatus().equals(SystemConstants.NORMAL)) { + throw new ServiceException("角色停用,不允许分配", HttpStatus.BAD_REQUEST); + } + if (!role.getDeptId().equals(deptId)) { + throw new ServiceException("角色部门与部门不匹配", HttpStatus.BAD_REQUEST); + } + } + } + + /** + * 新增保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) + @Override + @Transactional + public int insertDept(SysDeptBo bo) { + SysDept info = baseMapper.selectById(bo.getParentId()); + // 如果父节点不为正常状态,则不允许新增子节点 + if (!SystemConstants.NORMAL.equals(info.getStatus())) { + throw new ServiceException("部门停用,不允许新增"); + } + String pDeptType = info.getDeptType(); + String deptType = bo.getDeptType(); + if (SysDeptTypeEnum.SPECIAL.getCode().equals(pDeptType) || SysDeptTypeEnum.CONTRACT.getCode().equals(pDeptType)) { + // 父部门为特殊部门或者项目部门,不允许新增子部门 + throw new ServiceException("当前部门不允许有子部门"); + } else if (SysDeptTypeEnum.PROJECT.getCode().equals(pDeptType) && !SysDeptTypeEnum.CONTRACT.getCode().equals(deptType)) { + // 父部门为项目部门,只能新增分包部门 + throw new ServiceException("项目部门只能新增分包部门"); + } + SysDept dept = MapstructUtils.convert(bo, SysDept.class); + if (dept == null) { + throw new ServiceException("新增部门参数异常", HttpStatus.BAD_REQUEST); + } + dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId()); + if (SysDeptTypeEnum.PROJECT.getCode().equals(deptType)) { + // 项目部门 + Long projectId = bo.getProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + // 判断该项目是否被绑定 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysDept::getProjectId, projectId); + Long l = baseMapper.selectCount(queryWrapper); + if (l > 0) { + throw new ServiceException("该项目已被其他部门绑定", HttpStatus.CONFLICT); + } + dept.setProjectId(projectId); + // 判断是否有需要新增项目关联的用户 + List deptIds = this.getParentAndSiblingDeptIds(dept); + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.select(SysUser::getUserId); + lqw.in(SysUser::getDeptId, deptIds); + List userIds = userMapper.selectList(lqw).stream() + .map(SysUser::getUserId) + .filter(userId -> !LoginHelper.isSuperAdmin(userId)) + .toList(); + if (CollUtil.isNotEmpty(userIds)) { + userProjectRelevancyService.saveBatchByUserList(projectId, userIds); + } + } else if (SysDeptTypeEnum.CONTRACT.getCode().equals(deptType)) { + // 分包部门 + Long projectId = bo.getRowProjectId(); + BusProject project = projectService.getById(projectId); + if (project == null) { + throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND); + } + Long contractorId = bo.getContractorId(); + SubContractor contractor = contractorService.getById(contractorId); + if (contractor == null) { + throw new ServiceException("分包方不存在", HttpStatus.NOT_FOUND); + } + if (!contractor.getProjectId().equals(projectId)) { + throw new ServiceException("分包方不属于当前项目,请重新选择", HttpStatus.BAD_REQUEST); + } + // 判断该项目是否被绑定 + Long projectCount = baseMapper.selectCount( + new LambdaQueryWrapper() + .eq(SysDept::getProjectId, projectId) + ); + if (projectCount <= 0) { + throw new ServiceException("所选项目未绑定部门,请先将项目绑定部门", HttpStatus.BAD_REQUEST); + } + // 判断该分包方是否被绑定 + Long contractorCount = baseMapper.selectCount( + new LambdaQueryWrapper() + .eq(SysDept::getContractorId, contractorId) + ); + if (contractorCount > 0) { + throw new ServiceException("该分包方已被其他部门绑定", HttpStatus.CONFLICT); + } + dept.setProjectId(projectId); + dept.setContractorId(contractorId); + } + return baseMapper.insert(dept); + } + + /** + * 修改保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + @Caching(evict = { + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#bo.deptId"), + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) + }) + @Override + @Transactional(rollbackFor = Exception.class) + public int updateDept(SysDeptBo bo) { + SysDept dept = MapstructUtils.convert(bo, SysDept.class); + SysDept oldDept = baseMapper.selectById(dept.getDeptId()); + if (ObjectUtil.isNull(oldDept)) { + throw new ServiceException("部门不存在,无法修改"); + } + if (!oldDept.getParentId().equals(dept.getParentId())) { + // 如果是新父部门 则校验是否具有新父部门权限 避免越权 + this.checkDeptDataScope(dept.getParentId()); + SysDept newParentDept = baseMapper.selectById(dept.getParentId()); + if (ObjectUtil.isNotNull(newParentDept)) { + String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId(); + String oldAncestors = oldDept.getAncestors(); + dept.setAncestors(newAncestors); + updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); + } + } else { + dept.setAncestors(oldDept.getAncestors()); + } + String deptType = dept.getDeptType(); + if (SysDeptTypeEnum.PROJECT.getCode().equals(deptType)) { + // 判断是否需要更新用户与项目的关联 + Long oldProjectId = oldDept.getProjectId(); + Long newProjectId = dept.getProjectId(); + if (newProjectId != null && !Objects.equals(oldProjectId, newProjectId)) { + // 检查新项目是否存在 + BusProject project = projectService.getById(newProjectId); + if (project == null) { + throw new ServiceException("关联项目不存在", HttpStatus.NOT_FOUND); + } + // 判断新项目是否被绑定 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysDept::getProjectId, newProjectId); + Long l = baseMapper.selectCount(queryWrapper); + if (l > 0) { + throw new ServiceException("该项目已被其他部门绑定", HttpStatus.CONFLICT); + } + // 获取当前部门及其上级部门 ID 列表 + List deptIds = this.getParentAndSiblingDeptIds(dept); + // 获取部门用户 ID + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.select(SysUser::getUserId); + lqw.in(SysUser::getDeptId, deptIds); + List userIds = userMapper.selectList(lqw).stream() + .map(SysUser::getUserId) + .filter(userId -> !LoginHelper.isSuperAdmin(userId)) + .toList(); + if (CollUtil.isNotEmpty(userIds)) { + // 情况 1:原本有项目,且项目 ID 改变 → 删除旧的,添加新的 + if (oldProjectId != null) { + userProjectRelevancyService.deleteByProjectAndUserIds(oldProjectId, userIds); + userProjectRelevancyService.saveBatchByUserList(newProjectId, userIds); + } else { + // 情况 2:原本没有项目,现在新增了 → 直接添加 + userProjectRelevancyService.saveBatchByUserList(newProjectId, userIds); + } + } + dept.setProjectId(newProjectId); + } + } else if (SysDeptTypeEnum.CONTRACT.getCode().equals(deptType)) { + Long oldContractorId = oldDept.getContractorId(); + Long newContractorId = dept.getContractorId(); + if (!oldDept.getProjectId().equals(dept.getProjectId())) { + throw new ServiceException("分包方不属于当前项目,请重新选择", HttpStatus.BAD_REQUEST); + } + if (newContractorId != null && !Objects.equals(oldContractorId, newContractorId)) { + SubContractor contractor = contractorService.getById(newContractorId); + // 检查分包方是否存在 + if (contractor == null) { + throw new ServiceException("关联分包方不存在", HttpStatus.NOT_FOUND); + } + // 检查分包方所属项目是否与当前部门所属项目一致 + if (!contractor.getProjectId().equals(dept.getProjectId())) { + throw new ServiceException("分包方不属于当前项目,请重新选择", HttpStatus.BAD_REQUEST); + } + // 判断新选择分包方是否被绑定 + Long contractorCount = baseMapper.selectCount( + new LambdaQueryWrapper() + .eq(SysDept::getContractorId, newContractorId) + ); + if (contractorCount > 0) { + throw new ServiceException("该分包方已被其他部门绑定", HttpStatus.CONFLICT); + } + dept.setContractorId(newContractorId); + } + } + int result = baseMapper.updateById(dept); + if (SystemConstants.NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) + && !StringUtils.equals(SystemConstants.NORMAL, dept.getAncestors())) { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + updateParentDeptStatusNormal(dept); + } + return result; + } + + /** + * 修改该部门的父级部门状态 + * + * @param dept 当前部门 + */ + private void updateParentDeptStatusNormal(SysDept dept) { + String ancestors = dept.getAncestors(); + Long[] deptIds = Convert.toLongArray(ancestors); + baseMapper.update(null, new LambdaUpdateWrapper() + .set(SysDept::getStatus, SystemConstants.NORMAL) + .in(SysDept::getDeptId, Arrays.asList(deptIds))); + } + + /** + * 修改子元素关系 + * + * @param deptId 被修改的部门ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + private void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) { + List children = baseMapper.selectList(new LambdaQueryWrapper() + .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); + List list = new ArrayList<>(); + for (SysDept child : children) { + SysDept dept = new SysDept(); + dept.setDeptId(child.getDeptId()); + dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + list.add(dept); + } + if (CollUtil.isNotEmpty(list)) { + if (baseMapper.updateBatchById(list)) { + list.forEach(dept -> CacheUtils.evict(CacheNames.SYS_DEPT, dept.getDeptId())); + } + } + } + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @Caching(evict = { + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId"), + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId") + }) + @Override + public int deleteDeptById(Long deptId) { + return baseMapper.deleteById(deptId); + } + + /** + * 获取当前部门的祖先ID、自己ID、以及所有祖先的“同级部门ID” + * + * @param dept 当前部门 + * @return 部门ID列表(祖先、自身、父级的同级) + */ + public List getParentAndSiblingDeptIds(SysDept dept) { + Set deptIds = new LinkedHashSet<>(); + // 同级是否有特殊部门 + Long parentId = dept.getParentId(); + if (parentId != null) { + // 获取父级部门同级特殊部门(不包括它自己) + List siblingDepts = baseMapper.selectList( + new LambdaQueryWrapper() + .eq(SysDept::getParentId, parentId) + .eq(SysDept::getDeptType, SysDeptTypeEnum.SPECIAL.getCode()) + .ne(SysDept::getDeptId, dept.getDeptId()) + ); + if (CollUtil.isNotEmpty(siblingDepts)) { + for (SysDept sibling : siblingDepts) { + deptIds.add(sibling.getDeptId()); + } + } + } + // 祖先ID列表 + if (StringUtils.isNotBlank(dept.getAncestors())) { + String[] ancestorIds = dept.getAncestors().split(","); + for (String ancestorIdStr : ancestorIds) { + if (!"0".equals(ancestorIdStr)) { + Long ancestorId = Long.parseLong(ancestorIdStr); + deptIds.add(ancestorId); + // 获取该父级的同级部门(不包括它自己) + List siblingDepts = baseMapper.selectList( + new LambdaQueryWrapper() + .eq(SysDept::getParentId, baseMapper.selectById(ancestorId).getParentId()) + .ne(SysDept::getDeptId, ancestorId) + ); + for (SysDept sibling : siblingDepts) { + deptIds.add(sibling.getDeptId()); + } + } + } + } + // 加上自己 + deptIds.add(dept.getDeptId()); + return new ArrayList<>(deptIds); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 0000000..e44fdbc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,157 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.SysDictData; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.mapper.SysDictDataMapper; +import org.dromara.system.service.ISysDictDataService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDictDataServiceImpl implements ISysDictDataService { + + private final SysDictDataMapper baseMapper; + + @Override + public TableDataInfo selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictData); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataList(SysDictDataBo dictData) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictData); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysDictDataBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getDictSort() != null, SysDictData::getDictSort, bo.getDictSort()); + lqw.like(StringUtils.isNotBlank(bo.getDictLabel()), SysDictData::getDictLabel, bo.getDictLabel()); + lqw.eq(StringUtils.isNotBlank(bo.getDictType()), SysDictData::getDictType, bo.getDictType()); + lqw.orderByAsc(SysDictData::getDictSort); + return lqw; + } + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + @Override + public String selectDictLabel(String dictType, String dictValue) { + return baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysDictData::getDictLabel) + .eq(SysDictData::getDictType, dictType) + .eq(SysDictData::getDictValue, dictValue)) + .getDictLabel(); + } + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + @Override + public SysDictDataVo selectDictDataById(Long dictCode) { + return baseMapper.selectVoById(dictCode); + } + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + @Override + public void deleteDictDataByIds(Long[] dictCodes) { + for (Long dictCode : dictCodes) { + SysDictData data = baseMapper.selectById(dictCode); + baseMapper.deleteById(dictCode); + CacheUtils.evict(CacheNames.SYS_DICT, data.getDictType()); + } + } + + /** + * 新增保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List insertDictData(SysDictDataBo bo) { + SysDictData data = MapstructUtils.convert(bo, SysDictData.class); + int row = baseMapper.insert(data); + if (row > 0) { + return baseMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List updateDictData(SysDictDataBo bo) { + SysDictData data = MapstructUtils.convert(bo, SysDictData.class); + int row = baseMapper.updateById(data); + if (row > 0) { + return baseMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 校验字典键值是否唯一 + * + * @param dict 字典数据 + * @return 结果 + */ + @Override + public boolean checkDictDataUnique(SysDictDataBo dict) { + Long dictCode = ObjectUtils.notNull(dict.getDictCode(), -1L); + SysDictData entity = baseMapper.selectOne(new LambdaQueryWrapper() + .eq(SysDictData::getDictType, dict.getDictType()).eq(SysDictData::getDictValue, dict.getDictValue())); + if (ObjectUtil.isNotNull(entity) && !dictCode.equals(entity.getDictCode())) { + return false; + } + return true; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000..29f64ab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,285 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.dto.DictDataDTO; +import org.dromara.common.core.domain.dto.DictTypeDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.system.domain.SysDictData; +import org.dromara.system.domain.SysDictType; +import org.dromara.system.domain.bo.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysDictTypeVo; +import org.dromara.system.mapper.SysDictDataMapper; +import org.dromara.system.mapper.SysDictTypeMapper; +import org.dromara.system.service.ISysDictTypeService; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 字典 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService { + + private final SysDictTypeMapper baseMapper; + private final SysDictDataMapper dictDataMapper; + + @Override + public TableDataInfo selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictType); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeList(SysDictTypeBo dictType) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictType); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysDictTypeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getDictName()), SysDictType::getDictName, bo.getDictName()); + lqw.like(StringUtils.isNotBlank(bo.getDictType()), SysDictType::getDictType, bo.getDictType()); + lqw.between(params.get("beginTime") != null && params.get("endTime") != null, + SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime")); + lqw.orderByAsc(SysDictType::getDictId); + return lqw; + } + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeAll() { + return baseMapper.selectVoList(); + } + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType") + @Override + public List selectDictDataByType(String dictType) { + List dictDatas = dictDataMapper.selectDictDataByType(dictType); + if (CollUtil.isNotEmpty(dictDatas)) { + return dictDatas; + } + return null; + } + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + @Override + public SysDictTypeVo selectDictTypeById(Long dictId) { + return baseMapper.selectVoById(dictId); + } + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + @Override + public SysDictTypeVo selectDictTypeByType(String dictType) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysDictType::getDictType, dictType)); + } + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + */ + @Override + public void deleteDictTypeByIds(Long[] dictIds) { + for (Long dictId : dictIds) { + SysDictType dictType = baseMapper.selectById(dictId); + if (dictDataMapper.exists(new LambdaQueryWrapper() + .eq(SysDictData::getDictType, dictType.getDictType()))) { + throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName())); + } + CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType()); + } + baseMapper.deleteByIds(Arrays.asList(dictIds)); + } + + /** + * 重置字典缓存数据 + */ + @Override + public void resetDictCache() { + CacheUtils.clear(CacheNames.SYS_DICT); + } + + /** + * 新增保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List insertDictType(SysDictTypeBo bo) { + SysDictType dict = MapstructUtils.convert(bo, SysDictType.class); + int row = baseMapper.insert(dict); + if (row > 0) { + // 新增 type 下无 data 数据 返回空防止缓存穿透 + return new ArrayList<>(); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + @Transactional(rollbackFor = Exception.class) + public List updateDictType(SysDictTypeBo bo) { + SysDictType dict = MapstructUtils.convert(bo, SysDictType.class); + SysDictType oldDict = baseMapper.selectById(dict.getDictId()); + dictDataMapper.update(null, new LambdaUpdateWrapper() + .set(SysDictData::getDictType, dict.getDictType()) + .eq(SysDictData::getDictType, oldDict.getDictType())); + int row = baseMapper.updateById(dict); + if (row > 0) { + CacheUtils.evict(CacheNames.SYS_DICT, oldDict.getDictType()); + return dictDataMapper.selectDictDataByType(dict.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + @Override + public boolean checkDictTypeUnique(SysDictTypeBo dictType) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDictType::getDictType, dictType.getDictType()) + .ne(ObjectUtil.isNotNull(dictType.getDictId()), SysDictType::getDictId, dictType.getDictId())); + return !exist; + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + @Override + public String getDictLabel(String dictType, String dictValue, String separator) { + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); + if (StringUtils.containsAny(dictValue, separator)) { + return Arrays.stream(dictValue.split(separator)) + .map(v -> map.getOrDefault(v, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictValue, StringUtils.EMPTY); + } + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + @Override + public String getDictValue(String dictType, String dictLabel, String separator) { + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue); + if (StringUtils.containsAny(dictLabel, separator)) { + return Arrays.stream(dictLabel.split(separator)) + .map(l -> map.getOrDefault(l, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictLabel, StringUtils.EMPTY); + } + } + + @Override + public Map getAllDictByDictType(String dictType) { + List list = selectDictDataByType(dictType); + return StreamUtils.toMap(list, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); + } + + /** + * 根据字典类型查询详细信息 + * + * @param dictType 字典类型 + * @return 字典类型详细信息 + */ + @Override + public DictTypeDTO getDictType(String dictType) { + SysDictTypeVo vo = SpringUtils.getAopProxy(this).selectDictTypeByType(dictType); + return BeanUtil.toBean(vo, DictTypeDTO.class); + } + + /** + * 根据字典类型查询字典数据列表 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + @Override + public List getDictData(String dictType) { + List list = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + return BeanUtil.copyToList(list, DictDataDTO.class); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java new file mode 100644 index 0000000..72b497e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java @@ -0,0 +1,175 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysLogininfor; +import org.dromara.system.domain.bo.SysLogininforBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysLogininforVo; +import org.dromara.system.mapper.SysLogininforMapper; +import org.dromara.system.service.ISysClientService; +import org.dromara.system.service.ISysLogininforService; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 系统访问日志情况信息 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLogininforServiceImpl implements ISysLogininforService { + + private final SysLogininforMapper baseMapper; + + private final ISysClientService clientService; + + /** + * 记录登录信息 + * + * @param logininforEvent 登录事件 + */ + @Async + @EventListener + public void recordLogininfor(LogininforEvent logininforEvent) { + HttpServletRequest request = logininforEvent.getRequest(); + final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent")); + final String ip = ServletUtils.getClientIP(request); + // 客户端信息 + String clientId = request.getHeader(LoginHelper.CLIENT_KEY); + SysClientVo client = null; + if (StringUtils.isNotBlank(clientId)) { + client = clientService.queryByClientId(clientId); + } + + String address = AddressUtils.getRealAddressByIP(ip); + StringBuilder s = new StringBuilder(); + s.append(getBlock(ip)); + s.append(address); + s.append(getBlock(logininforEvent.getUsername())); + s.append(getBlock(logininforEvent.getStatus())); + s.append(getBlock(logininforEvent.getMessage())); + // 打印信息到日志 + log.info(s.toString(), logininforEvent.getArgs()); + // 获取客户端操作系统 + String os = userAgent.getOs().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + // 封装对象 + SysLogininforBo logininfor = new SysLogininforBo(); + logininfor.setTenantId(logininforEvent.getTenantId()); + logininfor.setUserName(logininforEvent.getUsername()); + if (ObjectUtil.isNotNull(client)) { + logininfor.setClientKey(client.getClientKey()); + logininfor.setDeviceType(client.getDeviceType()); + } + logininfor.setIpaddr(ip); + logininfor.setLoginLocation(address); + logininfor.setBrowser(browser); + logininfor.setOs(os); + logininfor.setMsg(logininforEvent.getMessage()); + // 日志状态 + if (StringUtils.equalsAny(logininforEvent.getStatus(), Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) { + logininfor.setStatus(Constants.SUCCESS); + } else if (Constants.LOGIN_FAIL.equals(logininforEvent.getStatus())) { + logininfor.setStatus(Constants.FAIL); + } + // 插入数据 + insertLogininfor(logininfor); + } + + private String getBlock(Object msg) { + if (msg == null) { + msg = ""; + } + return "[" + msg.toString() + "]"; + } + + @Override + public TableDataInfo selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery) { + Map params = logininfor.getParams(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr()) + .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus()) + .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime")); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + lqw.orderByDesc(SysLogininfor::getInfoId); + } + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 新增系统登录日志 + * + * @param bo 访问日志对象 + */ + @Override + public void insertLogininfor(SysLogininforBo bo) { + SysLogininfor logininfor = MapstructUtils.convert(bo, SysLogininfor.class); + logininfor.setLoginTime(new Date()); + baseMapper.insert(logininfor); + } + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List selectLogininforList(SysLogininforBo logininfor) { + Map params = logininfor.getParams(); + return baseMapper.selectVoList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr()) + .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus()) + .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime")) + .orderByDesc(SysLogininfor::getInfoId)); + } + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + @Override + public int deleteLogininforByIds(Long[] infoIds) { + return baseMapper.deleteByIds(Arrays.asList(infoIds)); + } + + /** + * 清空系统登录日志 + */ + @Override + public void cleanLogininfor() { + baseMapper.delete(new LambdaQueryWrapper<>()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..40643e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,372 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.TreeBuildUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleMenu; +import org.dromara.system.domain.SysTenantPackage; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.MetaVo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; +import org.dromara.system.mapper.SysMenuMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysRoleMenuMapper; +import org.dromara.system.mapper.SysTenantPackageMapper; +import org.dromara.system.service.ISysMenuService; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 菜单 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysMenuServiceImpl implements ISysMenuService { + + private final SysMenuMapper baseMapper; + private final SysRoleMapper roleMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysTenantPackageMapper tenantPackageMapper; + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + @Override + public List selectMenuList(Long userId) { + return selectMenuList(new SysMenuBo(), userId); + } + + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + @Override + public List selectMenuList(SysMenuBo menu, Long userId) { + List menuList; + // 管理员显示所有菜单信息 + if (LoginHelper.isSuperAdmin(userId)) { + menuList = baseMapper.selectVoList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName()) + .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible()) + .eq(StringUtils.isNotBlank(menu.getStatus()), SysMenu::getStatus, menu.getStatus()) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum)); + } else { + QueryWrapper wrapper = Wrappers.query(); + wrapper.inSql("r.role_id", "select role_id from sys_user_role where user_id = " + userId) + .like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName()) + .eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible()) + .eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus()) + .orderByAsc("m.parent_id") + .orderByAsc("m.order_num"); + List list = baseMapper.selectMenuListByUserId(wrapper); + menuList = MapstructUtils.convert(list, SysMenuVo.class); + } + return menuList; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByUserId(Long userId) { + List perms = baseMapper.selectMenuPermsByUserId(userId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(StringUtils.splitList(perm.trim())); + } + } + return permsSet; + } + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByRoleId(Long roleId) { + List perms = baseMapper.selectMenuPermsByRoleId(roleId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(StringUtils.splitList(perm.trim())); + } + } + return permsSet; + } + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户名称 + * @return 菜单列表 + */ + @Override + public List selectMenuTreeByUserId(Long userId) { + List menus; + if (LoginHelper.isSuperAdmin(userId)) { + menus = baseMapper.selectMenuTreeAll(); + } else { + menus = baseMapper.selectMenuTreeByUserId(userId); + } + return getChildPerms(menus, 0); + } + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + return baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly()); + } + + /** + * 根据租户套餐ID查询菜单树信息 + * + * @param packageId 租户套餐ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByPackageId(Long packageId) { + SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); + List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); + if (CollUtil.isEmpty(menuIds)) { + return List.of(); + } + List parentIds = null; + if (tenantPackage.getMenuCheckStrictly()) { + parentIds = baseMapper.selectObjs(new LambdaQueryWrapper() + .select(SysMenu::getParentId) + .in(SysMenu::getMenuId, menuIds), x -> {return Convert.toLong(x);}); + } + return baseMapper.selectObjs(new LambdaQueryWrapper() + .in(SysMenu::getMenuId, menuIds) + .notIn(CollUtil.isNotEmpty(parentIds), SysMenu::getMenuId, parentIds), x -> {return Convert.toLong(x);}); + } + + /** + * 构建前端路由所需要的菜单 + * 路由name命名规则 path首字母转大写 + id + * + * @param menus 菜单列表 + * @return 路由列表 + */ + @Override + public List buildMenus(List menus) { + List routers = new LinkedList<>(); + for (SysMenu menu : menus) { + String name = menu.getRouteName() + menu.getMenuId(); + RouterVo router = new RouterVo(); + router.setHidden("1".equals(menu.getVisible())); + router.setName(name); + router.setPath(menu.getRouterPath()); + router.setComponent(menu.getComponentInfo()); + router.setQuery(menu.getQueryParam()); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + List cMenus = menu.getChildren(); + if (CollUtil.isNotEmpty(cMenus) && SystemConstants.TYPE_DIR.equals(menu.getMenuType())) { + router.setAlwaysShow(true); + router.setRedirect("noRedirect"); + router.setChildren(buildMenus(cMenus)); + } else if (menu.isMenuFrame()) { + String frameName = StringUtils.capitalize(menu.getPath()) + menu.getMenuId(); + router.setMeta(null); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + children.setPath(menu.getPath()); + children.setComponent(menu.getComponent()); + children.setName(frameName); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + children.setQuery(menu.getQueryParam()); + childrenList.add(children); + router.setChildren(childrenList); + } else if (menu.getParentId().intValue() == 0 && menu.isInnerLink()) { + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); + router.setPath("/"); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + String routerPath = SysMenu.innerLinkReplaceEach(menu.getPath()); + String innerLinkName = StringUtils.capitalize(routerPath) + menu.getMenuId(); + children.setPath(routerPath); + children.setComponent(SystemConstants.INNER_LINK); + children.setName(innerLinkName); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); + childrenList.add(children); + router.setChildren(childrenList); + } + routers.add(router); + } + return routers; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildMenuTreeSelect(List menus) { + if (CollUtil.isEmpty(menus)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.build(menus, (menu, tree) -> { + Tree menuTree = tree.setId(menu.getMenuId()) + .setParentId(menu.getParentId()) + .setName(menu.getMenuName()) + .setWeight(menu.getOrderNum()); + menuTree.put("menuType", menu.getMenuType()); + menuTree.put("icon", menu.getIcon()); + }); + } + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenuVo selectMenuById(Long menuId) { + return baseMapper.selectVoById(menuId); + } + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Long menuId) { + return baseMapper.exists(new LambdaQueryWrapper().eq(SysMenu::getParentId, menuId)); + } + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean checkMenuExistRole(Long menuId) { + return roleMenuMapper.exists(new LambdaQueryWrapper().eq(SysRoleMenu::getMenuId, menuId)); + } + + /** + * 新增保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + @Override + public int insertMenu(SysMenuBo bo) { + SysMenu menu = MapstructUtils.convert(bo, SysMenu.class); + return baseMapper.insert(menu); + } + + /** + * 修改保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + @Override + public int updateMenu(SysMenuBo bo) { + SysMenu menu = MapstructUtils.convert(bo, SysMenu.class); + return baseMapper.updateById(menu); + } + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) { + return baseMapper.deleteById(menuId); + } + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public boolean checkMenuNameUnique(SysMenuBo menu) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysMenu::getMenuName, menu.getMenuName()) + .eq(SysMenu::getParentId, menu.getParentId()) + .ne(ObjectUtil.isNotNull(menu.getMenuId()), SysMenu::getMenuId, menu.getMenuId())); + return !exist; + } + + /** + * 根据父节点的ID获取所有子节点 + * + * @param list 分类表 + * @param parentId 传入的父节点ID + * @return String + */ + private List getChildPerms(List list, int parentId) { + List returnList = new ArrayList<>(); + for (SysMenu t : list) { + // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 + if (t.getParentId() == parentId) { + recursionFn(list, t); + returnList.add(t); + } + } + return returnList; + } + + /** + * 递归列表 + */ + private void recursionFn(List list, SysMenu t) { + // 得到子节点列表 + List childList = StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId())); + t.setChildren(childList); + for (SysMenu tChild : childList) { + // 判断是否有子节点 + if (list.stream().anyMatch(n -> n.getParentId().equals(tChild.getMenuId()))) { + recursionFn(list, tChild); + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 0000000..19a3ff5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,124 @@ +package org.dromara.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysNotice; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysNoticeMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysNoticeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +/** + * 公告 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysNoticeServiceImpl implements ISysNoticeService { + + private final SysNoticeMapper baseMapper; + private final SysUserMapper userMapper; + + @Override + public TableDataInfo selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(notice); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + @Override + public SysNoticeVo selectNoticeById(Long noticeId) { + return baseMapper.selectVoById(noticeId); + } + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + @Override + public List selectNoticeList(SysNoticeBo notice) { + LambdaQueryWrapper lqw = buildQueryWrapper(notice); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysNoticeBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getNoticeTitle()), SysNotice::getNoticeTitle, bo.getNoticeTitle()); + lqw.eq(StringUtils.isNotBlank(bo.getNoticeType()), SysNotice::getNoticeType, bo.getNoticeType()); + if (StringUtils.isNotBlank(bo.getCreateByName())) { + SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, bo.getCreateByName())); + lqw.eq(SysNotice::getCreateBy, ObjectUtils.notNullGetter(sysUser, SysUserVo::getUserId)); + } + lqw.orderByAsc(SysNotice::getNoticeId); + return lqw; + } + + /** + * 新增公告 + * + * @param bo 公告信息 + * @return 结果 + */ + @Override + public int insertNotice(SysNoticeBo bo) { + SysNotice notice = MapstructUtils.convert(bo, SysNotice.class); + return baseMapper.insert(notice); + } + + /** + * 修改公告 + * + * @param bo 公告信息 + * @return 结果 + */ + @Override + public int updateNotice(SysNoticeBo bo) { + SysNotice notice = MapstructUtils.convert(bo, SysNotice.class); + return baseMapper.updateById(notice); + } + + /** + * 删除公告对象 + * + * @param noticeId 公告ID + * @return 结果 + */ + @Override + public int deleteNoticeById(Long noticeId) { + return baseMapper.deleteById(noticeId); + } + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(Long[] noticeIds) { + return baseMapper.deleteByIds(Arrays.asList(noticeIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 0000000..27c2f32 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,134 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ArrayUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysOperLog; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; +import org.dromara.system.mapper.SysOperLogMapper; +import org.dromara.system.service.ISysOperLogService; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 操作日志 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysOperLogServiceImpl implements ISysOperLogService { + + private final SysOperLogMapper baseMapper; + + /** + * 操作日志记录 + * + * @param operLogEvent 操作日志事件 + */ + @Async + @EventListener + public void recordOper(OperLogEvent operLogEvent) { + SysOperLogBo operLog = MapstructUtils.convert(operLogEvent, SysOperLogBo.class); + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + insertOperlog(operLog); + } + + @Override + public TableDataInfo selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(operLog); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + lqw.orderByDesc(SysOperLog::getOperId); + } + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + private LambdaQueryWrapper buildQueryWrapper(SysOperLogBo operLog) { + Map params = operLog.getParams(); + return new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp()) + .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()) + .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, + SysOperLog::getBusinessType, operLog.getBusinessType()) + .func(f -> { + if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) { + f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes())); + } + }) + .eq(operLog.getStatus() != null, + SysOperLog::getStatus, operLog.getStatus()) + .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime")); + } + + /** + * 新增操作日志 + * + * @param bo 操作日志对象 + */ + @Override + public void insertOperlog(SysOperLogBo bo) { + SysOperLog operLog = MapstructUtils.convert(bo, SysOperLog.class); + operLog.setOperTime(new Date()); + baseMapper.insert(operLog); + } + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List selectOperLogList(SysOperLogBo operLog) { + LambdaQueryWrapper lqw = buildQueryWrapper(operLog); + return baseMapper.selectVoList(lqw.orderByDesc(SysOperLog::getOperId)); + } + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + @Override + public int deleteOperLogByIds(Long[] operIds) { + return baseMapper.deleteByIds(Arrays.asList(operIds)); + } + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLogVo selectOperLogById(Long operId) { + return baseMapper.selectVoById(operId); + } + + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() { + baseMapper.delete(new LambdaQueryWrapper<>()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java new file mode 100644 index 0000000..a67b04e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java @@ -0,0 +1,177 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.constant.OssConstant; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.system.domain.SysOssConfig; +import org.dromara.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; +import org.dromara.system.mapper.SysOssConfigMapper; +import org.dromara.system.service.ISysOssConfigService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 对象存储配置Service业务层处理 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysOssConfigServiceImpl implements ISysOssConfigService { + + private final SysOssConfigMapper baseMapper; + + /** + * 项目启动时,初始化参数到缓存,加载配置类 + */ + @Override + public void init() { + List list = baseMapper.selectList(); + // 加载OSS初始化配置 + for (SysOssConfig config : list) { + String configKey = config.getConfigKey(); + if ("0".equals(config.getStatus())) { + RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey); + } + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); + } + } + + @Override + public SysOssConfigVo queryById(Long ossConfigId) { + return baseMapper.selectVoById(ossConfigId); + } + + @Override + public TableDataInfo queryPageList(SysOssConfigBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + + private LambdaQueryWrapper buildQueryWrapper(SysOssConfigBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getConfigKey()), SysOssConfig::getConfigKey, bo.getConfigKey()); + lqw.like(StringUtils.isNotBlank(bo.getBucketName()), SysOssConfig::getBucketName, bo.getBucketName()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysOssConfig::getStatus, bo.getStatus()); + lqw.orderByAsc(SysOssConfig::getOssConfigId); + return lqw; + } + + @Override + public Boolean insertByBo(SysOssConfigBo bo) { + SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class); + validEntityBeforeSave(config); + boolean flag = baseMapper.insert(config) > 0; + if (flag) { + // 从数据库查询完整的数据做缓存 + config = baseMapper.selectById(config.getOssConfigId()); + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); + } + return flag; + } + + @Override + public Boolean updateByBo(SysOssConfigBo bo) { + SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class); + validEntityBeforeSave(config); + LambdaUpdateWrapper luw = new LambdaUpdateWrapper<>(); + luw.set(ObjectUtil.isNull(config.getPrefix()), SysOssConfig::getPrefix, ""); + luw.set(ObjectUtil.isNull(config.getRegion()), SysOssConfig::getRegion, ""); + luw.set(ObjectUtil.isNull(config.getExt1()), SysOssConfig::getExt1, ""); + luw.set(ObjectUtil.isNull(config.getRemark()), SysOssConfig::getRemark, ""); + luw.eq(SysOssConfig::getOssConfigId, config.getOssConfigId()); + boolean flag = baseMapper.update(config, luw) > 0; + if (flag) { + // 从数据库查询完整的数据做缓存 + config = baseMapper.selectById(config.getOssConfigId()); + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); + } + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysOssConfig entity) { + if (StringUtils.isNotEmpty(entity.getConfigKey()) + && !checkConfigKeyUnique(entity)) { + throw new ServiceException("操作配置'" + entity.getConfigKey() + "'失败, 配置key已存在!"); + } + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + if (CollUtil.containsAny(ids, OssConstant.SYSTEM_DATA_IDS)) { + throw new ServiceException("系统内置, 不可删除!"); + } + } + List list = CollUtil.newArrayList(); + for (Long configId : ids) { + SysOssConfig config = baseMapper.selectById(configId); + list.add(config); + } + boolean flag = baseMapper.deleteByIds(ids) > 0; + if (flag) { + list.forEach(sysOssConfig -> + CacheUtils.evict(CacheNames.SYS_OSS_CONFIG, sysOssConfig.getConfigKey())); + } + return flag; + } + + /** + * 判断configKey是否唯一 + */ + private boolean checkConfigKeyUnique(SysOssConfig sysOssConfig) { + long ossConfigId = ObjectUtils.notNull(sysOssConfig.getOssConfigId(), -1L); + SysOssConfig info = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysOssConfig::getOssConfigId, SysOssConfig::getConfigKey) + .eq(SysOssConfig::getConfigKey, sysOssConfig.getConfigKey())); + if (ObjectUtil.isNotNull(info) && info.getOssConfigId() != ossConfigId) { + return false; + } + return true; + } + + /** + * 启用禁用状态 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateOssConfigStatus(SysOssConfigBo bo) { + SysOssConfig sysOssConfig = MapstructUtils.convert(bo, SysOssConfig.class); + int row = baseMapper.update(null, new LambdaUpdateWrapper() + .set(SysOssConfig::getStatus, "1")); + row += baseMapper.updateById(sysOssConfig); + if (row > 0) { + RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, sysOssConfig.getConfigKey()); + } + return row; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java new file mode 100644 index 0000000..56f5277 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java @@ -0,0 +1,435 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.dto.OssDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.OssService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.common.oss.enumd.AccessPolicyType; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.system.domain.SysOss; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.mapper.SysOssMapper; +import org.dromara.system.service.ISysOssService; +import org.jetbrains.annotations.NotNull; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 文件上传 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysOssServiceImpl implements ISysOssService, OssService { + + private final SysOssMapper baseMapper; + + /** + * 查询OSS对象存储列表 + * + * @param bo OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ + @Override + public TableDataInfo queryPageList(SysOssBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + List filterResult = StreamUtils.toList(result.getRecords(), this::matchingUrl); + result.setRecords(filterResult); + return TableDataInfo.build(result); + } + + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ + @Override + public List listByIds(Collection ossIds) { + List list = new ArrayList<>(); + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); + for (Long id : ossIds) { + SysOssVo vo = ossService.getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + list.add(this.matchingUrl(vo)); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + list.add(vo); + } + } + } + return list; + } + + /** + * 根据一组 ossIds 获取对应文件的 URL 列表 + * + * @param ossIds 以逗号分隔的 ossId 字符串 + * @return 以逗号分隔的文件 URL 字符串 + */ + @Override + public String selectUrlByIds(String ossIds) { + List list = new ArrayList<>(); + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); + for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { + SysOssVo vo = ossService.getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + list.add(this.matchingUrl(vo).getUrl()); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + list.add(vo.getUrl()); + } + } + } + return String.join(StringUtils.SEPARATOR, list); + } + + @Override + public List selectByIds(String ossIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { + SysOssVo vo = SpringUtils.getAopProxy(this).getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + vo.setUrl(this.matchingUrl(vo).getUrl()); + list.add(BeanUtil.toBean(vo, OssDTO.class)); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + list.add(BeanUtil.toBean(vo, OssDTO.class)); + } + } + } + return list; + } + + private LambdaQueryWrapper buildQueryWrapper(SysOssBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName()); + lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName()); + lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix()); + lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + lqw.eq(ObjectUtil.isNotNull(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy()); + lqw.eq(StringUtils.isNotBlank(bo.getService()), SysOss::getService, bo.getService()); + lqw.orderByAsc(SysOss::getOssId); + return lqw; + } + + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId") + @Override + public SysOssVo getById(Long ossId) { + return baseMapper.selectVoById(ossId); + } + + + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + * @param response HttpServletResponse对象,用于设置响应头和向客户端发送文件内容 + */ + @Override + public void download(Long ossId, HttpServletResponse response) throws IOException { + SysOssVo sysOss = SpringUtils.getAopProxy(this).getById(ossId); + if (ObjectUtil.isNull(sysOss)) { + throw new ServiceException("文件数据不存在!"); + } + FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + OssClient storage = OssFactory.instance(sysOss.getService()); + storage.download(sysOss.getFileName(), response.getOutputStream(), response::setContentLengthLong); + } + + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + * @throws ServiceException 如果上传过程中发生异常,则抛出 ServiceException 异常 + */ + @Override + public SysOssVo upload(MultipartFile file) { + String originalfileName = file.getOriginalFilename(); + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + OssClient storage = OssFactory.instance(); + UploadResult uploadResult; + try { + uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType()); + } catch (IOException e) { + throw new ServiceException(e.getMessage()); + } + // 保存文件信息 + return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult); + } + + /** + * 上传 MultipartFile 到对象存储服务,不保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssUploadVo uploadWithNoSave(MultipartFile file) { + String originalFilename = file.getOriginalFilename(); + String suffix = StringUtils.substring(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length()); + OssClient storage = OssFactory.instance(); + UploadResult uploadResult; + try { + uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType()); + } catch (IOException e) { + throw new ServiceException(e.getMessage()); + } + SysOssUploadVo uploadVo = new SysOssUploadVo(); + uploadVo.setUrl(uploadResult.getUrl()); + uploadVo.setFileName(originalFilename); + return uploadVo; + } + + /** + * 上传 MultipartFile 到对象存储服务,不保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @param filePath 文件路径 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssUploadVo uploadWithNoSave(MultipartFile file, String filePath) { + String originalFilename = file.getOriginalFilename(); + OssClient storage = OssFactory.instance(); + UploadResult uploadResult; + try { + uploadResult = storage.uploadFilePath(file.getBytes(), filePath, file.getContentType()); + } catch (IOException e) { + throw new ServiceException(e.getMessage()); + } + SysOssUploadVo uploadVo = new SysOssUploadVo(); + uploadVo.setUrl(uploadResult.getUrl()); + uploadVo.setFileName(originalFilename); + return uploadVo; + } + + /** + * 通过 url 上传到对象存储服务,不保存文件信息到数据库 + * + * @param fileUrl 要上传的文件url + * @param filePath 文件路径 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssUploadVo uploadFileUrlWithNoSave(String fileUrl, String filePath) { + UploadResult uploadResult; + try { + // 1. 打开远程连接获取 InputStream + URI uri = URI.create(fileUrl); + URL url = uri.toURL(); + URLConnection conn = url.openConnection(); + InputStream inputStream = conn.getInputStream(); + // 2. 获取内容长度和类型(部分服务器可能返回为 -1) + long length = conn.getContentLengthLong(); // 有些服务可能为 -1,需要兜底处理 + String contentType = conn.getContentType(); + if (length <= 0) { + byte[] bytes = IoUtil.readBytes(inputStream); + length = bytes.length; + inputStream = new ByteArrayInputStream(bytes); // 重置为 ByteArrayInputStream + } + // 3. 上传 + OssClient storage = OssFactory.instance(); + uploadResult = storage.upload(inputStream, filePath, length, contentType); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + SysOssUploadVo uploadVo = new SysOssUploadVo(); + uploadVo.setUrl(uploadResult.getUrl()); + return uploadVo; + } + + /** + * 通过输入流上传到对象存储服务,不保存文件信息到数据库 + * + * @param inputStream 要上传的文件输入流 + * @param originalFileName 文件名 + * @param contentType 文件类型 + * @param length 文件长度 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssVo upload(InputStream inputStream, String originalFileName, String contentType, long length) { + String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length()); + UploadResult uploadResult; + // 上传 + OssClient storage = OssFactory.instance(); + try { + // 如果 length 不确定(如传 -1),就读取整个流算长度 + if (length <= 0) { + byte[] bytes = IoUtil.readBytes(inputStream); + length = bytes.length; + inputStream = new ByteArrayInputStream(bytes); // 重置 InputStream + } + uploadResult = storage.uploadSuffix(inputStream, suffix, length, contentType); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + // 保存文件信息 + return buildResultEntity(originalFileName, suffix, storage.getConfigKey(), uploadResult); + } + + /** + * 通过 url 上传到对象存储服务,不保存文件信息到数据库 + * + * @param inputStream 要上传的文件输入流 + * @param filePath 文件路径 + * @param contentType 文件类型 + * @param length 文件长度 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssUploadVo uploadFileUrlWithNoSave(InputStream inputStream, String filePath, String contentType, long length) { + UploadResult uploadResult; + try { + // 如果 length 不确定(如传 -1),就读取整个流算长度 + if (length <= 0) { + byte[] bytes = IoUtil.readBytes(inputStream); + length = bytes.length; + inputStream = new ByteArrayInputStream(bytes); // 重置 InputStream + } + // 上传 + OssClient storage = OssFactory.instance(); + uploadResult = storage.upload(inputStream, filePath, length, contentType); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + // 构建返回值 + SysOssUploadVo uploadVo = new SysOssUploadVo(); + uploadVo.setUrl(uploadResult.getUrl()); + return uploadVo; + } + + + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssVo upload(File file) { + String originalfileName = file.getName(); + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + OssClient storage = OssFactory.instance(); + UploadResult uploadResult = storage.uploadSuffix(file, suffix); + // 保存文件信息 + return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult); + } + + @NotNull + private SysOssVo buildResultEntity(String originalfileName, String suffix, String configKey, UploadResult uploadResult) { + SysOss oss = new SysOss(); + oss.setUrl(uploadResult.getUrl()); + oss.setFileSuffix(suffix); + oss.setFileName(uploadResult.getFilename()); + oss.setOriginalName(originalfileName); + oss.setService(configKey); + baseMapper.insert(oss); + SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class); + return this.matchingUrl(sysOssVo); + } + + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + } + List list = baseMapper.selectByIds(ids); + for (SysOss sysOss : list) { + OssClient storage = OssFactory.instance(sysOss.getService()); + storage.delete(sysOss.getUrl()); + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 桶类型为 private 的URL 修改为临时URL时长为120s + * + * @param oss OSS对象 + * @return oss 匹配Url的OSS对象 + */ + private SysOssVo matchingUrl(SysOssVo oss) { + OssClient storage = OssFactory.instance(oss.getService()); + // 仅修改桶类型为 private 的URL,临时URL时长为120s + if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) { + oss.setUrl(storage.getPrivateUrl(oss.getFileName(), Duration.ofSeconds(120))); + } + return oss; + } + + + /** + * MinioFileName 获取minio的即将存储文件的路径 + * + * @param prefix 前缀(举例:prefix) + * @param file 为了获取后缀(举例:.png) + * @return 返回全路径 + */ + @Override + public String minioFileName(String prefix, MultipartFile file) { + String originalFilename = file.getOriginalFilename(); + String suffix = StringUtils.substring(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length()); + OssClient storage = OssFactory.instance(); + return storage.getPath(prefix, suffix); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java new file mode 100644 index 0000000..9852821 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java @@ -0,0 +1,61 @@ +package org.dromara.system.service.impl; + +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.service.ISysMenuService; +import org.dromara.system.service.ISysPermissionService; +import org.dromara.system.service.ISysRoleService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.Set; + +/** + * 用户权限处理 + * + * @author ruoyi + */ +@RequiredArgsConstructor +@Service +public class SysPermissionServiceImpl implements ISysPermissionService { + + private final ISysRoleService roleService; + private final ISysMenuService menuService; + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + @Override + public Set getRolePermission(Long userId) { + Set roles = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + roles.add(TenantConstants.SUPER_ADMIN_ROLE_KEY); + } else { + roles.addAll(roleService.selectRolePermissionByUserId(userId)); + } + return roles; + } + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + @Override + public Set getMenuPermission(Long userId) { + Set perms = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + perms.add("*:*:*"); + } else { + perms.addAll(menuService.selectMenuPermsByUserId(userId)); + } + return perms; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 0000000..0a75eed --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,284 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.PostService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.SysUserPost; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.enums.SysPostManagerEnum; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysPostMapper; +import org.dromara.system.mapper.SysUserPostMapper; +import org.dromara.system.service.ISysPostService; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 岗位信息 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysPostServiceImpl implements ISysPostService, PostService { + + private final SysPostMapper baseMapper; + private final SysDeptMapper deptMapper; + private final SysUserPostMapper userPostMapper; + + @Override + public TableDataInfo selectPagePostList(SysPostBo post, PageQuery pageQuery) { + Page page = baseMapper.selectPagePostList(pageQuery.build(), buildQueryWrapper(post)); + return TableDataInfo.build(page); + } + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List selectPostList(SysPostBo post) { + return baseMapper.selectVoList(buildQueryWrapper(post)); + } + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 岗位ID + */ + @Override + public List selectPostsByUserId(Long userId) { + return baseMapper.selectPostsByUserId(userId); + } + + /** + * 根据查询条件构建查询包装器 + * + * @param bo 查询条件对象 + * @return 构建好的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysPostBo bo) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StringUtils.isNotBlank(bo.getPostCode()), SysPost::getPostCode, bo.getPostCode()) + .like(StringUtils.isNotBlank(bo.getPostCategory()), SysPost::getPostCategory, bo.getPostCategory()) + .like(StringUtils.isNotBlank(bo.getPostName()), SysPost::getPostName, bo.getPostName()) + .eq(StringUtils.isNotBlank(bo.getStatus()), SysPost::getStatus, bo.getStatus()) + .orderByAsc(SysPost::getPostSort); + if (ObjectUtil.isNotNull(bo.getDeptId())) { + //优先单部门搜索 + wrapper.eq(SysPost::getDeptId, bo.getDeptId()); + } else if (ObjectUtil.isNotNull(bo.getBelongDeptId())) { + //部门树搜索 + wrapper.and(x -> { + List deptList = deptMapper.selectListByParentId(bo.getBelongDeptId()); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(bo.getBelongDeptId()); + x.in(SysPost::getDeptId, deptIds); + }); + } + return wrapper; + } + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List selectPostAll() { + return baseMapper.selectVoList(new QueryWrapper<>()); + } + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPostVo selectPostById(Long postId) { + return baseMapper.selectVoById(postId); + } + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + @Override + public List selectPostListByUserId(Long userId) { + List list = baseMapper.selectPostsByUserId(userId); + return StreamUtils.toList(list, SysPostVo::getPostId); + } + + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + @Override + public List selectPostByIds(List postIds) { + return baseMapper.selectVoList(new LambdaQueryWrapper() + .select(SysPost::getPostId, SysPost::getPostName, SysPost::getPostCode) + .eq(SysPost::getStatus, SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(postIds), SysPost::getPostId, postIds)); + } + + /** + * 校验岗位名称是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostNameUnique(SysPostBo post) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysPost::getPostName, post.getPostName()) + .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId())); + return !exist; + } + + /** + * 校验岗位编码是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostCodeUnique(SysPostBo post) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysPost::getPostCode, post.getPostCode()) + .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId())); + return !exist; + } + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public long countUserPostById(Long postId) { + return userPostMapper.selectCount(new LambdaQueryWrapper().eq(SysUserPost::getPostId, postId)); + } + + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 结果 + */ + @Override + public long countPostByDeptId(Long deptId) { + return baseMapper.selectCount(new LambdaQueryWrapper().eq(SysPost::getDeptId, deptId)); + } + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int deletePostById(Long postId) { + return baseMapper.deleteById(postId); + } + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + @Override + public int deletePostByIds(Long[] postIds) { + for (Long postId : postIds) { + SysPost post = baseMapper.selectById(postId); + if (countUserPostById(postId) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除!", post.getPostName())); + } + } + return baseMapper.deleteByIds(Arrays.asList(postIds)); + } + + /** + * 新增保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + @Override + public int insertPost(SysPostBo bo) { + SysPost post = MapstructUtils.convert(bo, SysPost.class); + return baseMapper.insert(post); + } + + /** + * 批量新增岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + @Override + public Boolean insertPost(List bo) { + List postList = bo.stream().map(b -> MapstructUtils.convert(b, SysPost.class)).toList(); + return baseMapper.insertBatch(postList); + } + + /** + * 通过部门id批量新增默认岗位信息 + * + * @param deptId 部门id + * @return 结果 + */ + @Override + public Boolean insertPostByDeptId(Long deptId) { + List managerEnumList = SysPostManagerEnum.toList(); + AtomicInteger counter = new AtomicInteger(1); + List postBoList = managerEnumList.stream().map(managerEnum -> { + SysPostBo postBo = new SysPostBo(); + postBo.setDeptId(deptId); + postBo.setPostName(managerEnum.getName()); + postBo.setPostCode(managerEnum.getCode()); + postBo.setPostSort(counter.getAndIncrement()); + return postBo; + }).toList(); + return insertPost(postBoList); + } + + /** + * 修改保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + @Override + public int updatePost(SysPostBo bo) { + SysPost post = MapstructUtils.convert(bo, SysPost.class); + return baseMapper.updateById(post); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..505d895 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,554 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.RoleService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleDept; +import org.dromara.system.domain.SysRoleMenu; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.mapper.SysRoleDeptMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysRoleMenuMapper; +import org.dromara.system.mapper.SysUserRoleMapper; +import org.dromara.system.service.ISysRoleService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 角色 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysRoleServiceImpl implements ISysRoleService, RoleService { + + private final SysRoleMapper baseMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysRoleDeptMapper roleDeptMapper; + + @Override + public TableDataInfo selectPageRoleList(SysRoleBo role, PageQuery pageQuery) { + Page page = baseMapper.selectPageRoleList(pageQuery.build(), this.buildQueryWrapper(role)); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + @Override + public List selectRoleList(SysRoleBo role) { + return baseMapper.selectRoleList(this.buildQueryWrapper(role)); + } + + private Wrapper buildQueryWrapper(SysRoleBo bo) { + Map params = bo.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("r.del_flag", SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(bo.getDeptId()), "r.dept_id", bo.getDeptId()) + .eq(ObjectUtil.isNotNull(bo.getIsSpecial()), "r.is_special", bo.getIsSpecial()) + .eq(ObjectUtil.isNotNull(bo.getRoleId()), "r.role_id", bo.getRoleId()) + .like(StringUtils.isNotBlank(bo.getRoleName()), "r.role_name", bo.getRoleName()) + .eq(StringUtils.isNotBlank(bo.getStatus()), "r.status", bo.getStatus()) + .like(StringUtils.isNotBlank(bo.getRoleKey()), "r.role_key", bo.getRoleKey()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "r.create_time", params.get("beginTime"), params.get("endTime")) + .orderByAsc("r.role_sort").orderByAsc("r.create_time"); + return wrapper; + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesByUserId(Long userId) { + return baseMapper.selectRolesByUserId(userId); + } + + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesAuthByUserId(Long userId) { + List userRoles = baseMapper.selectRolesByUserId(userId); + List roles = selectRoleAll(); + // 使用HashSet提高查找效率 + Set userRoleIds = StreamUtils.toSet(userRoles, SysRoleVo::getRoleId); + for (SysRoleVo role : roles) { + if (userRoleIds.contains(role.getRoleId())) { + role.setFlag(true); + } + } + return roles; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectRolePermissionByUserId(Long userId) { + List perms = baseMapper.selectRolesByUserId(userId); + Set permsSet = new HashSet<>(); + for (SysRoleVo perm : perms) { + if (ObjectUtil.isNotNull(perm)) { + permsSet.addAll(StringUtils.splitList(perm.getRoleKey().trim())); + } + } + return permsSet; + } + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List selectRoleAll() { + return this.selectRoleList(new SysRoleBo()); + } + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + @Override + public List selectRoleListByUserId(Long userId) { + List list = baseMapper.selectRolesByUserId(userId); + return StreamUtils.toList(list, SysRoleVo::getRoleId); + } + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRoleVo selectRoleById(Long roleId) { + return baseMapper.selectRoleById(roleId); + } + + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + @Override + public List selectRoleByIds(List roleIds) { + return baseMapper.selectRoleList(new QueryWrapper() + .eq("r.status", SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(roleIds), "r.role_id", roleIds)); + } + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleNameUnique(SysRoleBo role) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysRole::getRoleName, role.getRoleName()) + .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId())); + return !exist; + } + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleKeyUnique(SysRoleBo role) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysRole::getRoleKey, role.getRoleKey()) + .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId())); + return !exist; + } + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + @Override + public void checkRoleAllowed(SysRoleBo role) { + if (ObjectUtil.isNotNull(role.getRoleId()) && LoginHelper.isSuperAdmin(role.getRoleId())) { + throw new ServiceException("不允许操作超级管理员角色"); + } + String[] keys = new String[]{TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.TENANT_ADMIN_ROLE_KEY}; + // 新增不允许使用 管理员标识符 + if (ObjectUtil.isNull(role.getRoleId()) + && StringUtils.equalsAny(role.getRoleKey(), keys)) { + throw new ServiceException("不允许使用系统内置管理员角色标识符!"); + } + // 修改不允许修改 管理员标识符 + if (ObjectUtil.isNotNull(role.getRoleId())) { + SysRole sysRole = baseMapper.selectById(role.getRoleId()); + // 如果标识符不相等 判断为修改了管理员标识符 + if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) { + if (StringUtils.equalsAny(sysRole.getRoleKey(), keys)) { + throw new ServiceException("不允许修改系统内置管理员角色标识符!"); + } else if (StringUtils.equalsAny(role.getRoleKey(), keys)) { + throw new ServiceException("不允许使用系统内置管理员角色标识符!"); + } + } + } + } + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + @Override + public void checkRoleDataScope(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + List roles = this.selectRoleList(new SysRoleBo(roleId)); + if (CollUtil.isEmpty(roles)) { + throw new ServiceException("没有权限访问角色数据!"); + } + + } + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public long countUserRoleByRoleId(Long roleId) { + return userRoleMapper.selectCount(new LambdaQueryWrapper().eq(SysUserRole::getRoleId, roleId)); + } + + /** + * 新增保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertRole(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + // 新增角色信息 + baseMapper.insert(role); + bo.setRoleId(role.getRoleId()); + return insertRoleMenu(bo); + } + + /** + * 修改保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateRole(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + + if (SystemConstants.DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } + // 修改角色信息 + baseMapper.updateById(role); + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, role.getRoleId())); + return insertRoleMenu(bo); + } + + /** + * 修改角色状态 + * + * @param roleId 角色ID + * @param status 角色状态 + * @return 结果 + */ + @Override + public int updateRoleStatus(Long roleId, String status) { + if (SystemConstants.DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysRole::getStatus, status) + .eq(SysRole::getRoleId, roleId)); + } + + /** + * 修改数据权限信息 + * + * @param bo 角色信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#bo.roleId") + @Override + @Transactional(rollbackFor = Exception.class) + public int authDataScope(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + // 修改角色信息 + baseMapper.updateById(role); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().eq(SysRoleDept::getRoleId, role.getRoleId())); + // 新增角色和部门信息(数据权限) + return insertRoleDept(bo); + } + + /** + * 新增角色菜单信息 + * + * @param role 角色对象 + */ + private int insertRoleMenu(SysRoleBo role) { + int rows = 1; + // 新增用户与角色管理 + List list = new ArrayList<>(); + for (Long menuId : role.getMenuIds()) { + SysRoleMenu rm = new SysRoleMenu(); + rm.setRoleId(role.getRoleId()); + rm.setMenuId(menuId); + list.add(rm); + } + if (list.size() > 0) { + rows = roleMenuMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + + /** + * 新增角色部门信息(数据权限) + * + * @param role 角色对象 + */ + private int insertRoleDept(SysRoleBo role) { + int rows = 1; + // 新增角色与部门(数据权限)管理 + List list = new ArrayList<>(); + for (Long deptId : role.getDeptIds()) { + SysRoleDept rd = new SysRoleDept(); + rd.setRoleId(role.getRoleId()); + rd.setDeptId(deptId); + list.add(rd); + } + if (list.size() > 0) { + rows = roleDeptMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId") + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleById(Long roleId) { + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, roleId)); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().eq(SysRoleDept::getRoleId, roleId)); + return baseMapper.deleteById(roleId); + } + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, allEntries = true) + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleByIds(Long[] roleIds) { + for (Long roleId : roleIds) { + SysRole role = baseMapper.selectById(roleId); + checkRoleAllowed(BeanUtil.toBean(role, SysRoleBo.class)); + checkRoleDataScope(roleId); + if (countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除!", role.getRoleName())); + } + } + List ids = Arrays.asList(roleIds); + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().in(SysRoleMenu::getRoleId, ids)); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().in(SysRoleDept::getRoleId, ids)); + return baseMapper.deleteByIds(ids); + } + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) { + int rows = userRoleMapper.delete(new LambdaQueryWrapper() + .eq(SysUserRole::getRoleId, userRole.getRoleId()) + .eq(SysUserRole::getUserId, userRole.getUserId())); + if (rows > 0) { + cleanOnlineUser(List.of(userRole.getUserId())); + } + return rows; + } + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + @Override + public int deleteAuthUsers(Long roleId, Long[] userIds) { + List ids = List.of(userIds); + int rows = userRoleMapper.delete(new LambdaQueryWrapper() + .eq(SysUserRole::getRoleId, roleId) + .in(SysUserRole::getUserId, ids)); + if (rows > 0) { + cleanOnlineUser(ids); + } + return rows; + } + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, Long[] userIds) { + // 新增用户与角色管理 + int rows = 1; + List ids = List.of(userIds); + List list = StreamUtils.toList(ids, userId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + if (CollUtil.isNotEmpty(list)) { + rows = userRoleMapper.insertBatch(list) ? list.size() : 0; + } + if (rows > 0) { + cleanOnlineUser(ids); + } + return rows; + } + + @Override + public void cleanOnlineUserByRole(Long roleId) { + // 如果角色未绑定用户 直接返回 + Long num = userRoleMapper.selectCount(new LambdaQueryWrapper().eq(SysUserRole::getRoleId, roleId)); + if (num == 0) { + return; + } + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (ObjectUtil.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoles())) { + return; + } + if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } + + @Override + public void cleanOnlineUser(List userIds) { + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (ObjectUtil.isNull(loginUser)) { + return; + } + if (userIds.contains(loginUser.getUserId())) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java new file mode 100644 index 0000000..8a0d45e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java @@ -0,0 +1,47 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ArrayUtil; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sensitive.core.SensitiveService; +import org.dromara.common.tenant.helper.TenantHelper; +import org.springframework.stereotype.Service; + +/** + * 脱敏服务 + * 默认管理员不过滤 + * 需自行根据业务重写实现 + * + * @author Lion Li + * @version 3.6.0 + */ +@Service +public class SysSensitiveServiceImpl implements SensitiveService { + + /** + * 是否脱敏 + */ + @Override + public boolean isSensitive(String[] roleKey, String[] perms) { + if (!LoginHelper.isLogin()) { + return true; + } + boolean roleExist = ArrayUtil.isNotEmpty(roleKey); + boolean permsExist = ArrayUtil.isNotEmpty(perms); + if (roleExist && permsExist) { + if (StpUtil.hasRoleOr(roleKey) && StpUtil.hasPermissionOr(perms)) { + return false; + } + } else if (roleExist && StpUtil.hasRoleOr(roleKey)) { + return false; + } else if (permsExist && StpUtil.hasPermissionOr(perms)) { + return false; + } + + if (TenantHelper.isEnable()) { + return !LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin(); + } + return !LoginHelper.isSuperAdmin(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java new file mode 100644 index 0000000..9c54cbc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java @@ -0,0 +1,112 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.domain.SysSocial; +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.mapper.SysSocialMapper; +import org.dromara.system.service.ISysSocialService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 社会化关系Service业务层处理 + * + * @author thiszhc + * @date 2023-06-12 + */ +@RequiredArgsConstructor +@Service +public class SysSocialServiceImpl implements ISysSocialService { + + private final SysSocialMapper baseMapper; + + + /** + * 查询社会化关系 + */ + @Override + public SysSocialVo queryById(String id) { + return baseMapper.selectVoById(id); + } + + /** + * 授权列表 + */ + @Override + public List queryList(SysSocialBo bo) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .eq(ObjectUtil.isNotNull(bo.getUserId()), SysSocial::getUserId, bo.getUserId()) + .eq(StringUtils.isNotBlank(bo.getAuthId()), SysSocial::getAuthId, bo.getAuthId()) + .eq(StringUtils.isNotBlank(bo.getSource()), SysSocial::getSource, bo.getSource()); + return baseMapper.selectVoList(lqw); + } + + @Override + public List queryListByUserId(Long userId) { + return baseMapper.selectVoList(new LambdaQueryWrapper().eq(SysSocial::getUserId, userId)); + } + + + /** + * 新增社会化关系 + */ + @Override + public Boolean insertByBo(SysSocialBo bo) { + SysSocial add = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + if (add != null) { + bo.setId(add.getId()); + } else { + return false; + } + } + return flag; + } + + /** + * 更新社会化关系 + */ + @Override + public Boolean updateByBo(SysSocialBo bo) { + SysSocial update = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysSocial entity) { + //TODO 做一些数据校验,如唯一约束 + } + + + /** + * 删除社会化关系 + */ + @Override + public Boolean deleteWithValidById(Long id) { + return baseMapper.deleteById(id) > 0; + } + + + /** + * 根据 authId 查询用户信息 + * + * @param authId 认证id + * @return 授权信息 + */ + @Override + public List selectByAuthId(String authId) { + return baseMapper.selectVoList(new LambdaQueryWrapper().eq(SysSocial::getAuthId, authId)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java new file mode 100644 index 0000000..23dd052 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java @@ -0,0 +1,168 @@ +package org.dromara.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.dto.TaskAssigneeDTO; +import org.dromara.common.core.domain.model.TaskAssigneeBody; +import org.dromara.common.core.service.TaskAssigneeService; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysPostMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 工作流设计器获取任务执行人 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysTaskAssigneeServiceImpl implements TaskAssigneeService { + + private final SysPostMapper postMapper; + private final SysDeptMapper deptMapper; + private final SysUserMapper userMapper; + private final SysRoleMapper roleMapper; + + /** + * 查询角色并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("r.del_flag", SystemConstants.NORMAL) + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "r.role_name", taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "r.role_key", taskQuery.getHandlerName()) + .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()), + "r.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime()) + .orderByAsc("r.role_sort").orderByAsc("r.create_time"); + Page page = roleMapper.selectPageRoleList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysRoleVo::getRoleId, SysRoleVo::getRoleKey, SysRoleVo::getRoleName, null, SysRoleVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 查询岗位并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysPost::getPostCategory, taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysPost::getPostName, taskQuery.getHandlerName()) + .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()), + SysPost::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime()); + if (StringUtils.isNotBlank(taskQuery.getGroupId())) { + Long belongDeptId = Long.valueOf(taskQuery.getGroupId()); + wrapper.and(x -> { + List deptList = deptMapper.selectListByParentId(belongDeptId); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(belongDeptId); + x.in(SysPost::getDeptId, deptIds); + }); + } + Page page = postMapper.selectPagePostList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysPostVo::getPostId, SysPostVo::getPostCategory, SysPostVo::getPostName, SysPostVo::getDeptId, SysPostVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 查询部门并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SysDept::getDelFlag, SystemConstants.NORMAL) + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysDept::getDeptCategory, taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysDept::getDeptName, taskQuery.getHandlerName()) + .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()), + SysDept::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime()) + .orderByAsc(SysDept::getAncestors) + .orderByAsc(SysDept::getParentId) + .orderByAsc(SysDept::getOrderNum) + .orderByAsc(SysDept::getDeptId); + if (StringUtils.isNotBlank(taskQuery.getGroupId())) { + //部门树搜索 + wrapper.and(x -> { + Long parentId = Long.valueOf(taskQuery.getGroupId()); + List deptList = deptMapper.selectListByParentId(parentId); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(parentId); + x.in(SysDept::getDeptId, deptIds); + }); + } + Page page = deptMapper.selectPageDeptList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysDeptVo::getDeptId, SysDeptVo::getDeptCategory, SysDeptVo::getDeptName, SysDeptVo::getParentId, SysDeptVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + + /** + * 查询用户并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "u.user_name", taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "u.nick_name", taskQuery.getHandlerName()) + .between(taskQuery.getBeginTime() != null && taskQuery.getEndTime() != null, + "u.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime()) + .orderByAsc("u.user_id"); + if (StringUtils.isNotBlank(taskQuery.getGroupId())) { + //部门树搜索 + wrapper.and(x -> { + Long parentId = Long.valueOf(taskQuery.getGroupId()); + List deptList = deptMapper.selectListByParentId(parentId); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(parentId); + x.in("u.dept_id", deptIds); + }); + } + Page page = userMapper.selectPageUserList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysUserVo::getUserId, SysUserVo::getUserName, SysUserVo::getNickName, SysUserVo::getDeptId, SysUserVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java new file mode 100644 index 0000000..8d69e96 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java @@ -0,0 +1,157 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysTenant; +import org.dromara.system.domain.SysTenantPackage; +import org.dromara.system.domain.bo.SysTenantPackageBo; +import org.dromara.system.domain.vo.SysTenantPackageVo; +import org.dromara.system.mapper.SysTenantMapper; +import org.dromara.system.mapper.SysTenantPackageMapper; +import org.dromara.system.service.ISysTenantPackageService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * 租户套餐Service业务层处理 + * + * @author Michelle.Chung + */ +@RequiredArgsConstructor +@Service +public class SysTenantPackageServiceImpl implements ISysTenantPackageService { + + private final SysTenantPackageMapper baseMapper; + private final SysTenantMapper tenantMapper; + + /** + * 查询租户套餐 + */ + @Override + public SysTenantPackageVo queryById(Long packageId){ + return baseMapper.selectVoById(packageId); + } + + /** + * 查询租户套餐列表 + */ + @Override + public TableDataInfo queryPageList(SysTenantPackageBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @Override + public List selectList() { + return baseMapper.selectVoList(new LambdaQueryWrapper() + .eq(SysTenantPackage::getStatus, SystemConstants.NORMAL)); + } + + /** + * 查询租户套餐列表 + */ + @Override + public List queryList(SysTenantPackageBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysTenantPackageBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getPackageName()), SysTenantPackage::getPackageName, bo.getPackageName()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenantPackage::getStatus, bo.getStatus()); + lqw.orderByAsc(SysTenantPackage::getPackageId); + return lqw; + } + + /** + * 新增租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(SysTenantPackageBo bo) { + SysTenantPackage add = MapstructUtils.convert(bo, SysTenantPackage.class); + // 保存菜单id + List menuIds = Arrays.asList(bo.getMenuIds()); + if (CollUtil.isNotEmpty(menuIds)) { + add.setMenuIds(StringUtils.join(menuIds, ", ")); + } else { + add.setMenuIds(""); + } + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setPackageId(add.getPackageId()); + } + return flag; + } + + /** + * 修改租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(SysTenantPackageBo bo) { + SysTenantPackage update = MapstructUtils.convert(bo, SysTenantPackage.class); + // 保存菜单id + List menuIds = Arrays.asList(bo.getMenuIds()); + if (CollUtil.isNotEmpty(menuIds)) { + update.setMenuIds(StringUtils.join(menuIds, ", ")); + } else { + update.setMenuIds(""); + } + return baseMapper.updateById(update) > 0; + } + + /** + * 校验套餐名称是否唯一 + */ + @Override + public boolean checkPackageNameUnique(SysTenantPackageBo bo) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysTenantPackage::getPackageName, bo.getPackageName()) + .ne(ObjectUtil.isNotNull(bo.getPackageId()), SysTenantPackage::getPackageId, bo.getPackageId())); + return !exist; + } + + /** + * 修改套餐状态 + * + * @param bo 套餐信息 + * @return 结果 + */ + @Override + public int updatePackageStatus(SysTenantPackageBo bo) { + SysTenantPackage tenantPackage = MapstructUtils.convert(bo, SysTenantPackage.class); + return baseMapper.updateById(tenantPackage); + } + + /** + * 批量删除租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + boolean exists = tenantMapper.exists(new LambdaQueryWrapper().in(SysTenant::getPackageId, ids)); + if (exists) { + throw new ServiceException("租户套餐已被使用"); + } + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java new file mode 100644 index 0000000..f31bd30 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java @@ -0,0 +1,477 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.tenant.core.TenantEntity; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.*; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.mapper.*; +import org.dromara.system.service.ISysTenantService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 租户Service业务层处理 + * + * @author Michelle.Chung + */ +@RequiredArgsConstructor +@Service +public class SysTenantServiceImpl implements ISysTenantService { + + private final SysTenantMapper baseMapper; + private final SysTenantPackageMapper tenantPackageMapper; + private final SysUserMapper userMapper; + private final SysDeptMapper deptMapper; + private final SysRoleMapper roleMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysRoleDeptMapper roleDeptMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysDictTypeMapper dictTypeMapper; + private final SysDictDataMapper dictDataMapper; + private final SysConfigMapper configMapper; + + /** + * 查询租户 + */ + @Override + public SysTenantVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 基于租户ID查询租户 + */ + @Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId") + @Override + public SysTenantVo queryByTenantId(String tenantId) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysTenant::getTenantId, tenantId)); + } + + /** + * 查询租户列表 + */ + @Override + public TableDataInfo queryPageList(SysTenantBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询租户列表 + */ + @Override + public List queryList(SysTenantBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysTenantBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()); + lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName()); + lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone()); + lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName()); + lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber()); + lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress()); + lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro()); + lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain()); + lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId()); + lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime()); + lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus()); + lqw.orderByAsc(SysTenant::getId); + return lqw; + } + + /** + * 新增租户 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(SysTenantBo bo) { + SysTenant add = MapstructUtils.convert(bo, SysTenant.class); + + // 获取所有租户编号 + List tenantIds = baseMapper.selectObjs( + new LambdaQueryWrapper().select(SysTenant::getTenantId), x -> { + return Convert.toStr(x); + }); + String tenantId = generateTenantId(tenantIds); + add.setTenantId(tenantId); + boolean flag = baseMapper.insert(add) > 0; + if (!flag) { + throw new ServiceException("创建租户失败"); + } + bo.setId(add.getId()); + + // 根据套餐创建角色 + Long roleId = createTenantRole(tenantId, bo.getPackageId()); + + // 创建部门: 公司名是部门名称 + SysDept dept = new SysDept(); + dept.setTenantId(tenantId); + dept.setDeptName(bo.getCompanyName()); + dept.setParentId(Constants.TOP_PARENT_ID); + dept.setAncestors(Constants.TOP_PARENT_ID.toString()); + deptMapper.insert(dept); + Long deptId = dept.getDeptId(); + + // 角色和部门关联表 + SysRoleDept roleDept = new SysRoleDept(); + roleDept.setRoleId(roleId); + roleDept.setDeptId(deptId); + roleDeptMapper.insert(roleDept); + + // 创建系统用户 + SysUser user = new SysUser(); + user.setTenantId(tenantId); + user.setUserName(bo.getUsername()); + user.setNickName(bo.getUsername()); + user.setPassword(BCrypt.hashpw(bo.getPassword())); + user.setDeptId(deptId); + userMapper.insert(user); + //新增系统用户后,默认当前用户为部门的负责人 + SysDept sd = new SysDept(); + sd.setLeader(user.getUserId()); + sd.setDeptId(deptId); + deptMapper.updateById(sd); + + // 用户和角色关联表 + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(user.getUserId()); + userRole.setRoleId(roleId); + userRoleMapper.insert(userRole); + + String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID; + List dictTypeList = dictTypeMapper.selectList( + new LambdaQueryWrapper().eq(SysDictType::getTenantId, defaultTenantId)); + List dictDataList = dictDataMapper.selectList( + new LambdaQueryWrapper().eq(SysDictData::getTenantId, defaultTenantId)); + for (SysDictType dictType : dictTypeList) { + dictType.setDictId(null); + dictType.setTenantId(tenantId); + } + for (SysDictData dictData : dictDataList) { + dictData.setDictCode(null); + dictData.setTenantId(tenantId); + } + dictTypeMapper.insertBatch(dictTypeList); + dictDataMapper.insertBatch(dictDataList); + + List sysConfigList = configMapper.selectList( + new LambdaQueryWrapper().eq(SysConfig::getTenantId, defaultTenantId)); + for (SysConfig config : sysConfigList) { + config.setConfigId(null); + config.setTenantId(tenantId); + } + configMapper.insertBatch(sysConfigList); + + // 未开启工作流不执行下方操作 + if (SpringUtils.getProperty("warm-flow.enabled", Boolean.class, false)) { + WorkflowService workflowService = SpringUtils.getBean(WorkflowService.class); + // 新增租户流程定义 + workflowService.syncDef(tenantId); + } + return true; + } + + /** + * 生成租户id + * + * @param tenantIds 已有租户id列表 + * @return 租户id + */ + private String generateTenantId(List tenantIds) { + // 随机生成6位 + String numbers = RandomUtil.randomNumbers(6); + // 判断是否存在,如果存在则重新生成 + if (tenantIds.contains(numbers)) { + return generateTenantId(tenantIds); + } + return numbers; + } + + /** + * 根据租户菜单创建租户角色 + * + * @param tenantId 租户编号 + * @param packageId 租户套餐id + * @return 角色id + */ + private Long createTenantRole(String tenantId, Long packageId) { + // 获取租户套餐 + SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); + if (ObjectUtil.isNull(tenantPackage)) { + throw new ServiceException("套餐不存在"); + } + // 获取套餐菜单id + List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); + + // 创建角色 + SysRole role = new SysRole(); + role.setTenantId(tenantId); + role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME); + role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY); + role.setRoleSort(1); + role.setStatus(SystemConstants.NORMAL); + roleMapper.insert(role); + Long roleId = role.getRoleId(); + + // 创建角色菜单 + List roleMenus = new ArrayList<>(menuIds.size()); + menuIds.forEach(menuId -> { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenus.add(roleMenu); + }); + roleMenuMapper.insertBatch(roleMenus); + + return roleId; + } + + /** + * 修改租户 + */ + @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") + @Override + public Boolean updateByBo(SysTenantBo bo) { + SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class); + tenant.setTenantId(null); + tenant.setPackageId(null); + return baseMapper.updateById(tenant) > 0; + } + + /** + * 修改租户状态 + * + * @param bo 租户信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") + @Override + public int updateTenantStatus(SysTenantBo bo) { + SysTenant tenant = new SysTenant(); + tenant.setId(bo.getId()); + tenant.setStatus(bo.getStatus()); + return baseMapper.updateById(tenant); + } + + /** + * 校验租户是否允许操作 + * + * @param tenantId 租户ID + */ + @Override + public void checkTenantAllowed(String tenantId) { + if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + throw new ServiceException("不允许操作管理租户"); + } + } + + /** + * 批量删除租户 + */ + @CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true) + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) { + throw new ServiceException("超管租户不能删除"); + } + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 校验企业名称是否唯一 + */ + @Override + public boolean checkCompanyNameUnique(SysTenantBo bo) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysTenant::getCompanyName, bo.getCompanyName()) + .ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId())); + return !exist; + } + + /** + * 校验账号余额 + */ + @Override + public boolean checkAccountBalance(String tenantId) { + SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId); + // 如果余额为-1代表不限制 + if (tenant.getAccountCount() == -1) { + return true; + } + Long userNumber = userMapper.selectCount(new LambdaQueryWrapper<>()); + // 如果余额大于0代表还有可用名额 + return tenant.getAccountCount() - userNumber > 0; + } + + /** + * 校验有效期 + */ + @Override + public boolean checkExpireTime(String tenantId) { + SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId); + // 如果未设置过期时间代表不限制 + if (ObjectUtil.isNull(tenant.getExpireTime())) { + return true; + } + // 如果当前时间在过期时间之前则通过 + return new Date().before(tenant.getExpireTime()); + } + + /** + * 同步租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean syncTenantPackage(String tenantId, Long packageId) { + SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); + List roles = roleMapper.selectList( + new LambdaQueryWrapper().eq(SysRole::getTenantId, tenantId)); + List roleIds = new ArrayList<>(roles.size() - 1); + List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); + roles.forEach(item -> { + if (TenantConstants.TENANT_ADMIN_ROLE_KEY.equals(item.getRoleKey())) { + List roleMenus = new ArrayList<>(menuIds.size()); + menuIds.forEach(menuId -> { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(item.getRoleId()); + roleMenu.setMenuId(menuId); + roleMenus.add(roleMenu); + }); + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, item.getRoleId())); + roleMenuMapper.insertBatch(roleMenus); + } else { + roleIds.add(item.getRoleId()); + } + }); + if (!roleIds.isEmpty()) { + roleMenuMapper.delete( + new LambdaQueryWrapper().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds)); + } + return true; + } + + /** + * 同步租户字典 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void syncTenantDict() { + // 查询超管 所有字典数据 + List dictTypeList = new ArrayList<>(); + List dictDataList = new ArrayList<>(); + TenantHelper.ignore(() -> { + dictTypeList.addAll(dictTypeMapper.selectList()); + dictDataList.addAll(dictDataMapper.selectList()); + }); + Map> typeMap = StreamUtils.groupByKey(dictTypeList, TenantEntity::getTenantId); + Map>> typeDataMap = StreamUtils.groupBy2Key( + dictDataList, TenantEntity::getTenantId, SysDictData::getDictType); + // 管理租户字典数据 + List defaultTypeMap = typeMap.get(TenantConstants.DEFAULT_TENANT_ID); + Map> defaultTypeDataMap = typeDataMap.get(TenantConstants.DEFAULT_TENANT_ID); + + // 获取所有租户编号 + List tenantIds = baseMapper.selectObjs( + new LambdaQueryWrapper().select(SysTenant::getTenantId) + .eq(SysTenant::getStatus, SystemConstants.NORMAL), x -> { + return Convert.toStr(x); + }); + List saveTypeList = new ArrayList<>(); + List saveDataList = new ArrayList<>(); + Set set = new HashSet<>(); + for (String tenantId : tenantIds) { + if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + continue; + } + for (SysDictType dictType : defaultTypeMap) { + List typeList = StreamUtils.toList(typeMap.get(tenantId), SysDictType::getDictType); + List dataList = defaultTypeDataMap.get(dictType.getDictType()); + if (typeList.contains(dictType.getDictType())) { + List dataListTenant = typeDataMap.get(tenantId).get(dictType.getDictType()); + Map map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue); + for (SysDictData dictData : dataList) { + if (!map.containsKey(dictData.getDictValue())) { + SysDictData data = BeanUtil.toBean(dictData, SysDictData.class); + // 设置字典编码为 null + data.setDictCode(null); + data.setTenantId(tenantId); + data.setCreateTime(null); + data.setUpdateTime(null); + set.add(tenantId); + saveDataList.add(data); + } + } + } else { + SysDictType type = BeanUtil.toBean(dictType, SysDictType.class); + type.setDictId(null); + type.setTenantId(tenantId); + type.setCreateTime(null); + type.setUpdateTime(null); + set.add(tenantId); + saveTypeList.add(type); + if (CollUtil.isNotEmpty(dataList)) { + // 筛选出 dictType 对应的 data + for (SysDictData dictData : dataList) { + SysDictData data = BeanUtil.toBean(dictData, SysDictData.class); + // 设置字典编码为 null + data.setDictCode(null); + data.setTenantId(tenantId); + data.setCreateTime(null); + data.setUpdateTime(null); + set.add(tenantId); + saveDataList.add(data); + } + } + } + } + } + TenantHelper.ignore(() -> { + if (CollUtil.isNotEmpty(saveTypeList)) { + dictTypeMapper.insertBatch(saveTypeList); + } + if (CollUtil.isNotEmpty(saveDataList)) { + dictDataMapper.insertBatch(saveDataList); + } + }); + for (String tenantId : set) { + TenantHelper.dynamic(tenantId, () -> CacheUtils.clear(CacheNames.SYS_DICT)); + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserFileServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserFileServiceImpl.java new file mode 100644 index 0000000..853d51a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserFileServiceImpl.java @@ -0,0 +1,245 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysUserFile; +import org.dromara.system.domain.dto.userfile.SysUserFileCreateReq; +import org.dromara.system.domain.dto.userfile.SysUserFileQueryReq; +import org.dromara.system.domain.vo.SysUserFileVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserFileMapper; +import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysUserFileService; +import org.dromara.system.service.ISysUserService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; + +/** + * 用户文件关联Service业务层处理 + * + * @author lilemy + * @date 2025-06-25 + */ +@Service +public class SysUserFileServiceImpl extends ServiceImpl + implements ISysUserFileService { + + @Resource + private ISysUserService userService; + + @Resource + private ISysOssService ossService; + + /** + * 查询用户文件关联 + * + * @param id 主键 + * @return 用户文件关联 + */ + @Override + public SysUserFileVo queryById(Long id) { + SysUserFile userFile = getById(id); + if (userFile == null) { + throw new ServiceException("对应用户文件关联信息不存在", HttpStatus.NOT_FOUND); + } + return this.getVo(userFile); + } + + /** + * 分页查询用户文件关联列表 + * + * @param req 查询条件 + * @param pageQuery 分页参数 + * @return 用户文件关联分页列表 + */ + @Override + public TableDataInfo queryPageList(SysUserFileQueryReq req, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(req); + Page result = this.page(pageQuery.build(), lqw); + return TableDataInfo.build(this.getVoPage(result)); + } + + /** + * 查询符合条件的用户文件关联列表 + * + * @param req 查询条件 + * @return 用户文件关联列表 + */ + @Override + public List queryList(SysUserFileQueryReq req) { + LambdaQueryWrapper lqw = this.buildQueryWrapper(req); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 根据用户ID查询用户文件关联列表 + * + * @param userId 用户ID + * @return 用户文件关联列表 + */ + @Override + public List queryListByUserId(Long userId) { + SysUserVo user = userService.selectUserById(userId); + if (user == null) { + throw new ServiceException("用户不存在", HttpStatus.NOT_FOUND); + } + return baseMapper.selectVoList(new LambdaQueryWrapper() + .eq(SysUserFile::getUserId, userId)); + } + + /** + * 当前登录用户文件关联列表 + * + * @return 用户文件关联列表 + */ + @Override + public List queryListByLoginUser() { + Long userId = LoginHelper.getUserId(); + return baseMapper.selectVoList(new LambdaQueryWrapper() + .eq(SysUserFile::getUserId, userId)); + } + + /** + * 新增用户文件关联 + * + * @param req 用户文件关联 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(SysUserFileCreateReq req) { + SysUserFile userFile = new SysUserFile(); + BeanUtils.copyProperties(req, userFile); + validEntityBeforeSave(userFile); + String fileId = req.getFileId(); + if (StringUtils.isBlank(fileId)) { + throw new ServiceException("用户文件不能为空", HttpStatus.BAD_REQUEST); + } + List fileIdList = Arrays.stream(fileId.split(",")).map(Long::parseLong).toList(); + List newUserFileList = fileIdList.stream().map(id -> { + SysUserFile newUserFile = new SysUserFile(); + newUserFile.setUserId(userFile.getUserId()); + newUserFile.setFileId(id); + return newUserFile; + }).toList(); + boolean save = this.saveOrUpdateBatch(newUserFileList); + if (!save) { + throw new ServiceException("保存用户文件关联失败,数据库异常", HttpStatus.ERROR); + } + return true; + } + + /** + * 删除用户文件关联信息 + * + * @param id 待删除的主键 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteById(Long id) { + SysUserFile userFile = this.getById(id); + if (userFile == null) { + throw new ServiceException("用户文件关联不存在", HttpStatus.BAD_REQUEST); + } + Long fileId = userFile.getFileId(); + // 删除文件 + Boolean result = ossService.deleteWithValidByIds(List.of(fileId), true); + if (!result) { + throw new ServiceException("用户文件删除失败", HttpStatus.ERROR); + } + boolean remove = this.removeById(id); + if (!remove) { + throw new ServiceException("用户文件关联删除失败", HttpStatus.ERROR); + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysUserFile entity) { + // TODO 做一些数据校验,如唯一约束 + Long userId = entity.getUserId(); + if (userId == null) { + throw new ServiceException("用户ID不能为空", HttpStatus.NOT_FOUND); + } + if (userService.selectUserById(userId) == null) { + throw new ServiceException("对应用户不存在", HttpStatus.NOT_FOUND); + } + } + + /** + * 获取用户文件视图 + * + * @param userFile 用户文件 + * @return 用户文件视图 + */ + @Override + public SysUserFileVo getVo(SysUserFile userFile) { + SysUserFileVo userFileVo = new SysUserFileVo(); + if (userFile == null) { + return userFileVo; + } + BeanUtils.copyProperties(userFile, userFileVo); + return userFileVo; + } + + /** + * 获取用户和项目关联对象查询条件封装 + * + * @param req 查询条件 + * @return 查询条件封装 + */ + @Override + public LambdaQueryWrapper buildQueryWrapper(SysUserFileQueryReq req) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + if (req == null) { + return lqw; + } + Long userId = req.getUserId(); + Long fileId = req.getFileId(); + lqw.eq(ObjectUtils.isNotEmpty(userId), SysUserFile::getUserId, userId); + lqw.eq(ObjectUtils.isNotEmpty(fileId), SysUserFile::getFileId, fileId); + return lqw; + } + + /** + * 获取用户文件分页视图 + * + * @param userFilePage 用户文件分页 + * @return 用户文件分页视图 + */ + @Override + public Page getVoPage(Page userFilePage) { + List userFileList = userFilePage.getRecords(); + Page userFileVoPage = new Page<>( + userFilePage.getCurrent(), + userFilePage.getSize(), + userFilePage.getTotal()); + if (CollUtil.isEmpty(userFileList)) { + return userFileVoPage; + } + List userFileVoList = userFileList.stream().map(userFile -> { + SysUserFileVo userFileVo = new SysUserFileVo(); + BeanUtils.copyProperties(userFile, userFileVo); + return userFileVo; + }).toList(); + userFileVoPage.setRecords(userFileVoList); + return userFileVoPage; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..3af324d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,879 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyCreateReq; +import org.dromara.project.service.IBusUserProjectRelevancyService; +import org.dromara.system.domain.*; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.enums.SysDeptTypeEnum; +import org.dromara.system.domain.vo.*; +import org.dromara.system.mapper.*; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysUserFileService; +import org.dromara.system.service.ISysUserService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 用户 业务层处理 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysUserServiceImpl implements ISysUserService, UserService { + + private final SysUserMapper baseMapper; + private final SysDeptMapper deptMapper; + private final SysRoleMapper roleMapper; + private final SysPostMapper postMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysUserPostMapper userPostMapper; + private final ISysDeptService deptService; + private final IBusUserProjectRelevancyService userProjectRelevancyService; + + @Lazy + @Resource + private ISysUserFileService userFileService; + + @Override + public TableDataInfo selectPageUserList(SysUserBo user, PageQuery pageQuery) { + Page page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user)); + List userVoList = page.getRecords(); + List userIdList = userVoList.stream().map(SysUserVo::getUserId).toList(); + if (CollUtil.isNotEmpty(userIdList)) { + List userFileList = userFileService.lambdaQuery() + .in(SysUserFile::getUserId, userIdList) + .list(); + Map> userFileMap = userFileList.stream().collect(Collectors.groupingBy(SysUserFile::getUserId)); + userVoList.forEach(userVo -> { + Long userId = userVo.getUserId(); + if (userFileMap.containsKey(userId)) { + List fileList = userFileMap.get(userId); + String fileIdStr = fileList.stream() + .map(file -> String.valueOf(file.getFileId())) + .collect(Collectors.joining(",")); + userVo.setFilePath(fileIdStr); + } + }); + page.setRecords(userVoList); + } + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public List selectUserExportList(SysUserBo user) { + return baseMapper.selectUserExportList(this.buildQueryWrapper(user)); + } + + private Wrapper buildQueryWrapper(SysUserBo user) { + Map params = user.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "u.create_time", params.get("beginTime"), params.get("endTime")) + .and(ObjectUtil.isNotNull(user.getDeptId()), w -> { + List deptList = deptMapper.selectListByParentId(user.getDeptId()); + List ids = StreamUtils.toList(deptList, SysDept::getDeptId); + ids.add(user.getDeptId()); + w.in("u.dept_id", ids); + }).orderByAsc("u.user_id"); + if (StringUtils.isNotBlank(user.getExcludeUserIds())) { + wrapper.notIn("u.user_id", StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong)); + } + return wrapper; + } + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public TableDataInfo selectAllocatedList(SysUserBo user, PageQuery pageQuery) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .orderByAsc("u.user_id"); + Page page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public TableDataInfo selectUnallocatedList(SysUserBo user, PageQuery pageQuery) { + List userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId()); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id")) + .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .orderByAsc("u.user_id"); + Page page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper); + return TableDataInfo.build(page); + } + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserByUserName(String userName) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, userName)); + } + + /** + * 通过手机号查询用户 + * + * @param phonenumber 手机号 + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserByPhonenumber(String phonenumber) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getPhonenumber, phonenumber)); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserById(Long userId) { + SysUserVo user = baseMapper.selectVoById(userId); + if (ObjectUtil.isNull(user)) { + return user; + } + user.setRoles(roleMapper.selectRolesByUserId(user.getUserId())); + return user; + } + + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + @Override + public List selectUserByIds(List userIds, Long deptId) { + return baseMapper.selectUserList(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId) + .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds)); + } + + /** + * 查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserRoleGroup(Long userId) { + List list = roleMapper.selectRolesByUserId(userId); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysRoleVo::getRoleName); + } + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserPostGroup(Long userId) { + List list = postMapper.selectPostsByUserId(userId); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysPostVo::getPostName); + } + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean checkUserNameUnique(SysUserBo user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getUserName, user.getUserName()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkPhoneUnique(SysUserBo user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getPhonenumber, user.getPhonenumber()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkEmailUnique(SysUserBo user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getEmail, user.getEmail()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + + /** + * 校验用户是否允许操作 + * + * @param userId 用户ID + */ + @Override + public void checkUserAllowed(Long userId) { + if (ObjectUtil.isNotNull(userId) && LoginHelper.isSuperAdmin(userId)) { + throw new ServiceException("不允许操作超级管理员用户"); + } + } + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + @Override + public void checkUserDataScope(Long userId) { + if (ObjectUtil.isNull(userId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (baseMapper.countUserById(userId) == 0) { + throw new ServiceException("没有权限访问用户数据!"); + } + } + + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertUser(SysUserBo user) { + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + // 新增用户信息 + int rows = baseMapper.insert(sysUser); + user.setUserId(sysUser.getUserId()); + // 新增用户岗位关联 + insertUserPost(user, false); + // 新增用户与角色管理 + insertUserRole(user, false); + Long deptId = user.getDeptId(); + SysDeptVo deptVo = deptService.selectDeptById(deptId); + if (deptVo.getDeptType().equals(SysDeptTypeEnum.CONTRACT.getCode())) { + // 关联分包部门所属项目 + BusUserProjectRelevancyCreateReq req = new BusUserProjectRelevancyCreateReq(); + req.setUserId(user.getUserId()); + req.setProjectId(deptVo.getProjectId()); + userProjectRelevancyService.insertByBo(req); + } else { + // 关联部门所属项目 + List projectIds = deptService.selectProjectIdById(deptId); + userProjectRelevancyService.saveBatchByProjectList(projectIds, user.getUserId()); + } + return rows; + } + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean registerUser(SysUserBo user, String tenantId) { + user.setCreateBy(0L); + user.setUpdateBy(0L); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + sysUser.setTenantId(tenantId); + return baseMapper.insert(sysUser) > 0; + } + + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId") + @Transactional(rollbackFor = Exception.class) + public int updateUser(SysUserBo user) { + // 新增用户与角色管理 + insertUserRole(user, true); + // 新增用户与岗位管理 + insertUserPost(user, true); + // 获取旧的系统用户 + SysUser oldUser = baseMapper.selectById(user.getUserId()); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + // 防止错误更新后导致的数据误删除 + int flag = baseMapper.updateById(sysUser); + if (flag < 1) { + throw new ServiceException("修改用户" + user.getUserName() + "信息失败"); + } + // 没有修改部门则不需要修改用户与项目的关联 + if (oldUser.getDeptId().equals(user.getDeptId())) { + return flag; + } + Long deptId = user.getDeptId(); + SysDeptVo deptVo = deptService.selectDeptById(deptId); + if (deptVo.getDeptType().equals(SysDeptTypeEnum.CONTRACT.getCode())) { + // 先删除旧关联 + userProjectRelevancyService.deleteByUserId(user.getUserId()); + // 添加新关联 + BusUserProjectRelevancyCreateReq req = new BusUserProjectRelevancyCreateReq(); + req.setUserId(user.getUserId()); + req.setProjectId(deptVo.getProjectId()); + userProjectRelevancyService.insertByBo(req); + } else { + // 先删除旧关联 + userProjectRelevancyService.deleteByUserId(user.getUserId()); + // 添加新关联 + List projectIds = deptService.selectProjectIdById(user.getDeptId()); + userProjectRelevancyService.saveBatchByProjectList(projectIds, user.getUserId()); + } + return flag; + } + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertUserAuth(Long userId, Long[] roleIds) { + insertUserRole(userId, roleIds, true); + } + + /** + * 修改用户状态 + * + * @param userId 用户ID + * @param status 帐号状态 + * @return 结果 + */ + @Override + public int updateUserStatus(Long userId, String status) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getStatus, status) + .eq(SysUser::getUserId, userId)); + } + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId") + @Override + public int updateUserProfile(SysUserBo user) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName()) + .set(SysUser::getPhonenumber, user.getPhonenumber()) + .set(SysUser::getEmail, user.getEmail()) + .set(SysUser::getSex, user.getSex()) + .eq(SysUser::getUserId, user.getUserId())); + } + + /** + * 修改用户头像 + * + * @param userId 用户ID + * @param avatar 头像地址 + * @return 结果 + */ + @Override + public boolean updateUserAvatar(Long userId, Long avatar) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getAvatar, avatar) + .eq(SysUser::getUserId, userId)) > 0; + } + + /** + * 重置用户密码 + * + * @param userId 用户ID + * @param password 密码 + * @return 结果 + */ + @Override + public int resetUserPwd(Long userId, String password) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getPassword, password) + .eq(SysUser::getUserId, userId)); + } + + /** + * 新增用户角色信息 + * + * @param user 用户对象 + * @param clear 清除已存在的关联数据 + */ + private void insertUserRole(SysUserBo user, boolean clear) { + this.insertUserRole(user.getUserId(), user.getRoleIds(), clear); + } + + /** + * 新增用户岗位信息 + * + * @param user 用户对象 + * @param clear 清除已存在的关联数据 + */ + private void insertUserPost(SysUserBo user, boolean clear) { + Long[] posts = user.getPostIds(); + if (ArrayUtil.isNotEmpty(posts)) { + if (clear) { + // 删除用户与岗位关联 + userPostMapper.delete(new LambdaQueryWrapper().eq(SysUserPost::getUserId, user.getUserId())); + } + // 新增用户与岗位管理 + List list = StreamUtils.toList(List.of(posts), postId -> { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + return up; + }); + userPostMapper.insertBatch(list); + } + } + + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + * @param clear 清除已存在的关联数据 + */ + private void insertUserRole(Long userId, Long[] roleIds, boolean clear) { + if (ArrayUtil.isNotEmpty(roleIds)) { + List roleList = new ArrayList<>(List.of(roleIds)); + if (!LoginHelper.isSuperAdmin(userId)) { + roleList.remove(SystemConstants.SUPER_ADMIN_ID); + } + // 判断是否具有此角色的操作权限 + List roles = roleMapper.selectRoleList( + new QueryWrapper().in("r.role_id", roleList)); + if (CollUtil.isEmpty(roles)) { + throw new ServiceException("没有权限访问角色的数据"); + } + if (clear) { + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); + } + // 新增用户与角色管理 + List list = StreamUtils.toList(roleList, roleId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + userRoleMapper.insertBatch(list); + } + } + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserById(Long userId) { + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); + // 删除用户与岗位表 + userPostMapper.delete(new LambdaQueryWrapper().eq(SysUserPost::getUserId, userId)); + // 防止更新失败导致的数据删除 + int flag = baseMapper.deleteById(userId); + if (flag < 1) { + throw new ServiceException("删除用户失败!"); + } + return flag; + } + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserByIds(Long[] userIds) { + for (Long userId : userIds) { + checkUserAllowed(userId); + checkUserDataScope(userId); + } + List ids = List.of(userIds); + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().in(SysUserRole::getUserId, ids)); + // 删除用户与岗位表 + userPostMapper.delete(new LambdaQueryWrapper().in(SysUserPost::getUserId, ids)); + // 防止更新失败导致的数据删除 + int flag = baseMapper.deleteByIds(ids); + if (flag < 1) { + throw new ServiceException("删除用户失败!"); + } + return flag; + } + + /** + * 通过部门id查询当前部门所有用户 + * + * @param deptId 部门ID + * @return 用户信息集合信息 + */ + @Override + public List selectUserListByDept(Long deptId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysUser::getDeptId, deptId); + lqw.orderByAsc(SysUser::getUserId); + return baseMapper.selectVoList(lqw); + } + + /** + * 通过岗位id列表查询岗位所有用户 + * + * @param postIds 岗位id列表 + * @return 结果 + */ + @Override + public List selectUserListByPostList(List postIds) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.in(SysUserPost::getPostId, postIds); + List userPostList = userPostMapper.selectList(lqw); + if (CollUtil.isNotEmpty(userPostList)){ + List userIds = userPostList.stream().map(SysUserPost::getUserId).distinct().toList(); + return baseMapper.selectVoByIds(userIds); + } + return List.of(); + } + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId") + @Override + public String selectUserNameById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getUserName).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getUserName); + } + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + @Override + @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId") + public String selectNicknameById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getNickName).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getNickName); + } + + /** + * 通过用户ID查询用户账户 + * + * @param userIds 用户ID 多个用逗号隔开 + * @return 用户账户 + */ + @Override + public String selectNicknameByIds(String userIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(userIds, Convert::toLong)) { + String nickname = SpringUtils.getAopProxy(this).selectNicknameById(id); + if (StringUtils.isNotBlank(nickname)) { + list.add(nickname); + } + } + return String.join(StringUtils.SEPARATOR, list); + } + + /** + * 通过用户ID查询用户手机号 + * + * @param userId 用户id + * @return 用户手机号 + */ + @Override + public String selectPhonenumberById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getPhonenumber).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getPhonenumber); + } + + /** + * 通过用户ID查询用户邮箱 + * + * @param userId 用户id + * @return 用户邮箱 + */ + @Override + public String selectEmailById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getEmail).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getEmail); + } + + /** + * 通过用户ID查询用户列表 + * + * @param userIds 用户ids + * @return 用户列表 + */ + @Override + public List selectListByIds(List userIds) { + if (CollUtil.isEmpty(userIds)) { + return List.of(); + } + List list = baseMapper.selectVoList(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .in(SysUser::getUserId, userIds)); + return BeanUtil.copyToList(list, UserDTO.class); + } + + /** + * 通过角色ID查询用户ID + * + * @param roleIds 角色ids + * @return 用户ids + */ + @Override + public List selectUserIdsByRoleIds(List roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return List.of(); + } + List userRoles = userRoleMapper.selectList( + new LambdaQueryWrapper().in(SysUserRole::getRoleId, roleIds)); + return StreamUtils.toList(userRoles, SysUserRole::getUserId); + } + + /** + * 通过角色ID查询用户 + * + * @param roleIds 角色ids + * @return 用户 + */ + @Override + public List selectUsersByRoleIds(List roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return List.of(); + } + + // 通过角色ID获取用户角色信息 + List userRoles = userRoleMapper.selectList( + new LambdaQueryWrapper().in(SysUserRole::getRoleId, roleIds)); + + // 获取用户ID列表 + Set userIds = StreamUtils.toSet(userRoles, SysUserRole::getUserId); + + return selectListByIds(new ArrayList<>(userIds)); + } + + /** + * 通过部门ID查询用户 + * + * @param deptIds 部门ids + * @return 用户 + */ + @Override + public List selectUsersByDeptIds(List deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return List.of(); + } + List list = baseMapper.selectVoList(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .in(SysUser::getDeptId, deptIds)); + return BeanUtil.copyToList(list, UserDTO.class); + } + + /** + * 通过岗位ID查询用户 + * + * @param postIds 岗位ids + * @return 用户 + */ + @Override + public List selectUsersByPostIds(List postIds) { + if (CollUtil.isEmpty(postIds)) { + return List.of(); + } + + // 通过岗位ID获取用户岗位信息 + List userPosts = userPostMapper.selectList( + new LambdaQueryWrapper().in(SysUserPost::getPostId, postIds)); + + // 获取用户ID列表 + Set userIds = StreamUtils.toSet(userPosts, SysUserPost::getUserId); + + return selectListByIds(new ArrayList<>(userIds)); + } + + /** + * 根据用户 ID 列表查询用户名称映射关系 + * + * @param userIds 用户 ID 列表 + * @return Map,其中 key 为用户 ID,value 为对应的用户名称 + */ + @Override + public Map selectUserNamesByIds(List userIds) { + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyMap(); + } + return baseMapper.selectList( + new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getNickName) + .in(SysUser::getUserId, userIds) + ).stream() + .collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName)); + } + + /** + * 根据角色 ID 列表查询角色名称映射关系 + * + * @param roleIds 角色 ID 列表 + * @return Map,其中 key 为角色 ID,value 为对应的角色名称 + */ + @Override + public Map selectRoleNamesByIds(List roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return Collections.emptyMap(); + } + return roleMapper.selectList( + new LambdaQueryWrapper() + .select(SysRole::getRoleId, SysRole::getRoleName) + .in(SysRole::getRoleId, roleIds) + ).stream() + .collect(Collectors.toMap(SysRole::getRoleId, SysRole::getRoleName)); + } + + /** + * 根据部门 ID 列表查询部门名称映射关系 + * + * @param deptIds 部门 ID 列表 + * @return Map,其中 key 为部门 ID,value 为对应的部门名称 + */ + @Override + public Map selectDeptNamesByIds(List deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return Collections.emptyMap(); + } + return deptMapper.selectList( + new LambdaQueryWrapper() + .select(SysDept::getDeptId, SysDept::getDeptName) + .in(SysDept::getDeptId, deptIds) + ).stream() + .collect(Collectors.toMap(SysDept::getDeptId, SysDept::getDeptName)); + } + + /** + * 根据岗位 ID 列表查询岗位名称映射关系 + * + * @param postIds 岗位 ID 列表 + * @return Map,其中 key 为岗位 ID,value 为对应的岗位名称 + */ + @Override + public Map selectPostNamesByIds(List postIds) { + if (CollUtil.isEmpty(postIds)) { + return Collections.emptyMap(); + } + return postMapper.selectList( + new LambdaQueryWrapper() + .select(SysPost::getPostId, SysPost::getPostName) + .in(SysPost::getPostId, postIds) + ).stream() + .collect(Collectors.toMap(SysPost::getPostId, SysPost::getPostName)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubConstructionUserFileMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubConstructionUserFileMapper.xml new file mode 100644 index 0000000..710ae07 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubConstructionUserFileMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubConstructionUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubConstructionUserMapper.xml new file mode 100644 index 0000000..d530372 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubConstructionUserMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMapper.xml new file mode 100644 index 0000000..1fbee1a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMaterialMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMaterialMapper.xml new file mode 100644 index 0000000..13ad2b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMaterialMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMaterialRecordMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMaterialRecordMapper.xml new file mode 100644 index 0000000..4d5add8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorMaterialRecordMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorToolMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorToolMapper.xml new file mode 100644 index 0000000..76a5fcb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorToolMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorToolRecordMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorToolRecordMapper.xml new file mode 100644 index 0000000..5e97bfa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubContractorToolRecordMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubSubcontractMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubSubcontractMapper.xml new file mode 100644 index 0000000..b946784 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/contractor/SubSubcontractMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/cory/BusContactformtemplateMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/cory/BusContactformtemplateMapper.xml new file mode 100644 index 0000000..75cc9f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/cory/BusContactformtemplateMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/cory/BusContactnoticeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/cory/BusContactnoticeMapper.xml new file mode 100644 index 0000000..339df11 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/cory/BusContactnoticeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesDesignChangeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesDesignChangeMapper.xml new file mode 100644 index 0000000..961b11c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesDesignChangeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesDrawingMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesDrawingMapper.xml new file mode 100644 index 0000000..8fda464 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesDrawingMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesSpecialSchemeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesSpecialSchemeMapper.xml new file mode 100644 index 0000000..b7df880 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesSpecialSchemeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesTechnicalStandardMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesTechnicalStandardMapper.xml new file mode 100644 index 0000000..11f3422 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/design/DesTechnicalStandardMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/drone/DroDroneConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/drone/DroDroneConfigMapper.xml new file mode 100644 index 0000000..6c6418a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/drone/DroDroneConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacBoxTransformerMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacBoxTransformerMapper.xml new file mode 100644 index 0000000..e82d38e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacBoxTransformerMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacInverterMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacInverterMapper.xml new file mode 100644 index 0000000..a5e9c59 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacInverterMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacMatrixMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacMatrixMapper.xml new file mode 100644 index 0000000..fba2f9b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacMatrixMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPercentageFacilityMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPercentageFacilityMapper.xml new file mode 100644 index 0000000..b9f49f9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPercentageFacilityMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelColumnMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelColumnMapper.xml new file mode 100644 index 0000000..5974251 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelColumnMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelMapper.xml new file mode 100644 index 0000000..f4661f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelPointMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelPointMapper.xml new file mode 100644 index 0000000..121e229 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelPointMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelSupportMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelSupportMapper.xml new file mode 100644 index 0000000..4d5278a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/facility/FacPhotovoltaicPanelSupportMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/machinery/EqpMachineryDetailMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/machinery/EqpMachineryDetailMapper.xml new file mode 100644 index 0000000..3218846 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/machinery/EqpMachineryDetailMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/machinery/EqpMachineryMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/machinery/EqpMachineryMapper.xml new file mode 100644 index 0000000..62a8c2a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/machinery/EqpMachineryMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatCompanyMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatCompanyMapper.xml new file mode 100644 index 0000000..4fe9cd1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatCompanyMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialIssueItemMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialIssueItemMapper.xml new file mode 100644 index 0000000..58eaffb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialIssueItemMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialIssueMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialIssueMapper.xml new file mode 100644 index 0000000..ec3b6c4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialIssueMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialReceiveItemMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialReceiveItemMapper.xml new file mode 100644 index 0000000..3ce551d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialReceiveItemMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialReceiveMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialReceiveMapper.xml new file mode 100644 index 0000000..9fa02c7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialReceiveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialsInventoryMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialsInventoryMapper.xml new file mode 100644 index 0000000..ddbdaed --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialsInventoryMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialsMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialsMapper.xml new file mode 100644 index 0000000..1616690 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/materials/MatMaterialsMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthDevicePresetMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthDevicePresetMapper.xml new file mode 100644 index 0000000..d4f5945 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthDevicePresetMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthYs7DeviceImgMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthYs7DeviceImgMapper.xml new file mode 100644 index 0000000..f88a8b3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthYs7DeviceImgMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthYs7DeviceMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthYs7DeviceMapper.xml new file mode 100644 index 0000000..39ddbb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/other/OthYs7DeviceMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressCategoryMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressCategoryMapper.xml new file mode 100644 index 0000000..6852dd5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressCategoryMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressCategoryTemplateMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressCategoryTemplateMapper.xml new file mode 100644 index 0000000..474f74a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressCategoryTemplateMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressPlanDetailMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressPlanDetailMapper.xml new file mode 100644 index 0000000..ec1bcc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressPlanDetailMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressPlanMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressPlanMapper.xml new file mode 100644 index 0000000..0988fe6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/progress/PgsProgressPlanMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusAttendanceMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusAttendanceMapper.xml new file mode 100644 index 0000000..362fa22 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusAttendanceMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusConstructionBlacklistMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusConstructionBlacklistMapper.xml new file mode 100644 index 0000000..ca098ec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusConstructionBlacklistMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusConstructionUserExitMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusConstructionUserExitMapper.xml new file mode 100644 index 0000000..28c0519 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusConstructionUserExitMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusDailyPieceItemMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusDailyPieceItemMapper.xml new file mode 100644 index 0000000..e0cd695 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusDailyPieceItemMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusLeaveMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusLeaveMapper.xml new file mode 100644 index 0000000..df00b72 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusLeaveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectFileMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectFileMapper.xml new file mode 100644 index 0000000..e83c4ac --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectFileMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectMapper.xml new file mode 100644 index 0000000..366b854 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectNewsMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectNewsMapper.xml new file mode 100644 index 0000000..a374e26 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectNewsMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectTeamMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectTeamMapper.xml new file mode 100644 index 0000000..ad5195b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectTeamMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectTeamMemberMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectTeamMemberMapper.xml new file mode 100644 index 0000000..efbba2d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusProjectTeamMemberMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusReissueCardMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusReissueCardMapper.xml new file mode 100644 index 0000000..72043a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusReissueCardMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusUserProjectRelevancyMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusUserProjectRelevancyMapper.xml new file mode 100644 index 0000000..0318b90 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusUserProjectRelevancyMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusWorkWageMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusWorkWageMapper.xml new file mode 100644 index 0000000..58f6b0a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusWorkWageMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusWorkerDailyReportMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusWorkerDailyReportMapper.xml new file mode 100644 index 0000000..468e861 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/project/BusWorkerDailyReportMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltKnowledgeDocumentMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltKnowledgeDocumentMapper.xml new file mode 100644 index 0000000..81c8801 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltKnowledgeDocumentMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltQualityConstructionLogMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltQualityConstructionLogMapper.xml new file mode 100644 index 0000000..8cba3b7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltQualityConstructionLogMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltQualityInspectionMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltQualityInspectionMapper.xml new file mode 100644 index 0000000..15b179e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/quality/QltQualityInspectionMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseDocumentSafetyMeetingMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseDocumentSafetyMeetingMapper.xml new file mode 100644 index 0000000..c419faa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseDocumentSafetyMeetingMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseKnowledgeDocumentMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseKnowledgeDocumentMapper.xml new file mode 100644 index 0000000..7659d9c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseKnowledgeDocumentMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionBankMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionBankMapper.xml new file mode 100644 index 0000000..a713195 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionBankMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionUserAnswerMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionUserAnswerMapper.xml new file mode 100644 index 0000000..8d794e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionUserAnswerMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionsCategoryMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionsCategoryMapper.xml new file mode 100644 index 0000000..fc0b961 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionsCategoryMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionsConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionsConfigMapper.xml new file mode 100644 index 0000000..0d8fbde --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseQuestionsConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseRecognizeRecordMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseRecognizeRecordMapper.xml new file mode 100644 index 0000000..22e0c44 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseRecognizeRecordMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyInspectionMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyInspectionMapper.xml new file mode 100644 index 0000000..184ed8a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyInspectionMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyLogMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyLogMapper.xml new file mode 100644 index 0000000..d0d7496 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyLogMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyWeeklyReportMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyWeeklyReportMapper.xml new file mode 100644 index 0000000..0519d6c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseSafetyWeeklyReportMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseTeamMeetingMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseTeamMeetingMapper.xml new file mode 100644 index 0000000..5988605 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseTeamMeetingMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationLevelMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationLevelMapper.xml new file mode 100644 index 0000000..6bfe818 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationLevelMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationLevelPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationLevelPostMapper.xml new file mode 100644 index 0000000..30d8624 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationLevelPostMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationRecordMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationRecordMapper.xml new file mode 100644 index 0000000..7a4610a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/safety/HseViolationRecordMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml new file mode 100644 index 0000000..fd150ad --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 0000000..e542a10 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 0000000..9057a0e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml new file mode 100644 index 0000000..6bcce51 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml new file mode 100644 index 0000000..6975da4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml new file mode 100644 index 0000000..c64b551 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 0000000..9dd3f2e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml new file mode 100644 index 0000000..43f494d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml new file mode 100644 index 0000000..5ef14ee --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml new file mode 100644 index 0000000..8c2c080 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml new file mode 100644 index 0000000..d9b25bd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml new file mode 100644 index 0000000..322403f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml new file mode 100644 index 0000000..1705bb2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 0000000..819de00 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,64 @@ + + + + + + + + + select distinct r.role_id, + r.role_name, + r.role_key, + r.dept_id, + r.role_sort, + r.data_scope, + r.menu_check_strictly, + r.dept_check_strictly, + r.status, + r.del_flag, + r.create_time, + r.remark, + r.is_special + from sys_role r + left join sys_user_role sur on sur.role_id = r.role_id + left join sys_user u on u.user_id = sur.user_id + left join sys_dept d on u.dept_id = d.dept_id + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 0000000..f01dc5e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml new file mode 100644 index 0000000..baa4b59 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml new file mode 100644 index 0000000..0d96e13 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml new file mode 100644 index 0000000..79cf4c5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserFileMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserFileMapper.xml new file mode 100644 index 0000000..cca197f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserFileMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000..ded6fa8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml new file mode 100644 index 0000000..e9f2496 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 0000000..bc52d1a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/README.md b/ruoyi-modules/ruoyi-workflow/README.md new file mode 100644 index 0000000..59096b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/README.md @@ -0,0 +1,3 @@ +# 工作流说明 + +工作流目前在未成熟阶段 后续仍会经历重构 甚至重写(生产使用前请慎重考虑后续是否要更新维护) \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml new file mode 100644 index 0000000..d195faf --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/pom.xml @@ -0,0 +1,84 @@ + + + + org.dromara + ruoyi-modules + ${revision} + ../pom.xml + + 4.0.0 + jar + ruoyi-workflow + + + 工作流模块 + + + + + + org.dromara + ruoyi-common-sse + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-mail + + + + org.dromara + ruoyi-common-sms + + + + org.dromara + ruoyi-common-mybatis + + + org.dromara + ruoyi-common-web + + + org.dromara + ruoyi-common-log + + + org.dromara + ruoyi-common-idempotent + + + org.dromara + ruoyi-common-excel + + + org.dromara + ruoyi-common-translation + + + org.dromara + ruoyi-common-tenant + + + org.dromara + ruoyi-common-security + + + org.dromara.warm + warm-flow-mybatis-plus-sb3-starter + + + org.dromara.warm + warm-flow-plugin-ui-sb-web + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java new file mode 100644 index 0000000..e844398 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java @@ -0,0 +1,29 @@ +package org.dromara.workflow.common; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义条件注解,用于基于配置启用或禁用特定功能 + *

+ * 该注解只会在配置文件中 `warm-flow.enabled=true` 时,标注了此注解的类或方法才会被 Spring 容器加载 + *

+ * 示例配置: + *

+ * warm-flow:
+ *   enabled: true  # 设置为 true 时,启用工作流功能
+ * 
+ *

+ * 使用此注解时,可以动态控制工作流功能是否启用,而不需要修改代码逻辑 + * + * @author Lion Li + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@ConditionalOnProperty(value = "warm-flow.enabled", havingValue = "true") +public @interface ConditionalOnEnable { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java new file mode 100644 index 0000000..aaa640b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -0,0 +1,81 @@ +package org.dromara.workflow.common.constant; + + +/** + * 工作流常量 + * + * @author may + */ +public interface FlowConstant { + + /** + * 流程发起人 + */ + String INITIATOR = "initiator"; + + /** + * 业务id + */ + String BUSINESS_ID = "businessId"; + + /** + * 委托 + */ + String DELEGATE_TASK = "delegateTask"; + + /** + * 转办 + */ + String TRANSFER_TASK = "transferTask"; + + /** + * 加签 + */ + String ADD_SIGNATURE = "addSignature"; + + /** + * 减签 + */ + String REDUCTION_SIGNATURE = "reductionSignature"; + + /** + * 流程分类Id转名称 + */ + String CATEGORY_ID_TO_NAME = "category_id_to_name"; + + /** + * 流程分类名称 + */ + String FLOW_CATEGORY_NAME = "flow_category_name#30d"; + + /** + * 默认租户OA申请分类id + */ + Long FLOW_CATEGORY_ID = 100L; + + /** + * 是否为申请人提交常量 + */ + String SUBMIT = "submit"; + + /** + * 抄送常量 + */ + String FLOW_COPY_LIST = "flowCopyList"; + + /** + * 消息类型常量 + */ + String MESSAGE_TYPE = "messageType"; + + /** + * 消息通知常量 + */ + String MESSAGE_NOTICE = "messageNotice"; + + /** + * 任务状态 + */ + String WF_TASK_STATUS = "wf_task_status"; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java new file mode 100644 index 0000000..598cd05 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java @@ -0,0 +1,65 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 按钮权限枚举 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum ButtonPermissionEnum implements NodeExtEnum { + + /** + * 是否弹窗选人 + */ + POP("是否弹窗选人", "pop", false), + + /** + * 是否能委托 + */ + TRUST("是否能委托", "trust", false), + + /** + * 是否能转办 + */ + TRANSFER("是否能转办", "transfer", false), + + /** + * 是否能抄送 + */ + COPY("是否能抄送", "copy", false), + + /** + * 是否显示退回 + */ + BACK("是否显示退回", "back", true), + + /** + * 是否能加签 + */ + ADD_SIGN("是否能加签", "addSign", false), + + /** + * 是否能减签 + */ + SUB_SIGN("是否能减签", "subSign", false), + + /** + * 是否能终止 + */ + TERMINATION("是否能终止", "termination", true), + + /** + * 是否能上传附件 + */ + FILE("是否能上传附件", "file", true); + + private final String label; + private final String value; + private final boolean selected; + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FlwDefinitionSuffixTemplateEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FlwDefinitionSuffixTemplateEnum.java new file mode 100644 index 0000000..5424c65 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FlwDefinitionSuffixTemplateEnum.java @@ -0,0 +1,33 @@ +package org.dromara.workflow.common.enums; + +import lombok.Getter; + +/** + * @author lilemy + * @date 2025/7/8 19:22 + */ +@Getter +public enum FlwDefinitionSuffixTemplateEnum { + + FLOW_DESIGN_PHILOSOPHY("设计原则审批", "_principletechnical", ""), + FLOW_REQUIREMENTS_LIST("业主需求清单审批", "_requirementstechnical", ""), + FLOW_SPECIAL_SCHEME("专项方案审批", "_specialscheme", "specialScheme/indexEdit"), + FLOW_PROCESS_DRAWING("过程图纸审批", "_processdrawing", "drawing/indexEdit"), + FLOW_BLUEPRINT_DRAWING("蓝图审批", "_blueprintdrawing", "drawing/indexEdit"), + FLOW_CHANGED_DRAWING("变更图纸审批", "_changedrawing", "drawing/indexEdit"), + FLOW_DESIGN_CHANGED("设计变更审批", "_designchanged", "designChange/indexEdit"), + FLOW_CHANGED_CONTACT("变更联系单审批", "_changecontact", ""), + FLOW_VISA_CONTACT("签证联系单审批", "_visacontact", ""); + + private final String name; + + private final String code; + + private final String path; + + FlwDefinitionSuffixTemplateEnum(String name, String code, String path) { + this.name = name; + this.code = code; + this.path = path; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java new file mode 100644 index 0000000..0fe5cfe --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 消息类型枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum MessageTypeEnum { + + /** + * 站内信 + */ + SYSTEM_MESSAGE("1", "站内信"), + + /** + * 邮箱 + */ + EMAIL_MESSAGE("2", "邮箱"), + + /** + * 短信 + */ + SMS_MESSAGE("3", "短信"); + + private final String code; + + private final String desc; + + private static final Map MESSAGE_TYPE_ENUM_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(MessageTypeEnum::getCode, Function.identity())); + + /** + * 根据消息类型 code 获取 MessageTypeEnum + * + * @param code 消息类型code + * @return MessageTypeEnum + */ + public static MessageTypeEnum getByCode(String code) { + return MESSAGE_TYPE_ENUM_MAP.getOrDefault(code, null); + } + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/NodeExtEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/NodeExtEnum.java new file mode 100644 index 0000000..9926a8e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/NodeExtEnum.java @@ -0,0 +1,32 @@ +package org.dromara.workflow.common.enums; + +/** + * 节点扩展属性枚举 + * + * @author AprilWind + */ +public interface NodeExtEnum { + + /** + * 选项label + * + * @return 选项label + */ + String getLabel(); + + /** + * 选项值 + * + * @return 选项值 + */ + String getValue(); + + /** + * 是否默认选中 + * + * @return 是否默认选中 + */ + boolean isSelected(); + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java new file mode 100644 index 0000000..60be92f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java @@ -0,0 +1,109 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 任务分配人枚举 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum TaskAssigneeEnum { + + /** + * 用户 + */ + USER("用户", ""), + + /** + * 角色 + */ + ROLE("角色", "role:"), + + /** + * 部门 + */ + DEPT("部门", "dept:"), + + /** + * 岗位 + */ + POST("岗位", "post:"); + + private final String desc; + private final String code; + + /** + * 根据描述获取对应的枚举类型 + *

+ * 通过传入描述,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。 + *

+ * + * @param desc 描述,用于匹配对应的枚举项 + * @return TaskAssigneeEnum 返回对应的枚举类型 + * @throws ServiceException 如果未找到匹配的枚举项 + */ + public static TaskAssigneeEnum fromDesc(String desc) { + for (TaskAssigneeEnum type : values()) { + if (type.getDesc().equals(desc)) { + return type; + } + } + throw new ServiceException("未知的办理人类型: " + desc); + } + + /** + * 根据代码获取对应的枚举类型 + *

+ * 通过传入代码,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。 + *

+ * + * @param code 代码,用于匹配对应的枚举项 + * @return TaskAssigneeEnum 返回对应的枚举类型 + * @throws IllegalArgumentException 如果未找到匹配的枚举项 + */ + public static TaskAssigneeEnum fromCode(String code) { + for (TaskAssigneeEnum type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + throw new ServiceException("未知的办理人类型代码: " + code); + } + + /** + * 获取所有办理人类型的描述列表 + *

+ * 获取当前枚举类所有项的描述字段列表,通常用于展示选择项。 + *

+ * + * @return List 返回所有办理人类型的描述列表 + */ + public static List getAssigneeTypeList() { + return Arrays.stream(values()) + .map(TaskAssigneeEnum::getDesc) + .collect(Collectors.toList()); + } + + /** + * 获取所有办理人类型的代码列表 + *

+ * 获取当前枚举类所有项的代码字段列表,通常用于程序内部逻辑的判断。 + *

+ * + * @return List 返回所有办理人类型的代码列表 + */ + public static List getAssigneeCodeList() { + return Arrays.stream(values()) + .map(TaskAssigneeEnum::getCode) + .collect(Collectors.toList()); + } +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java new file mode 100644 index 0000000..eed1b91 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 人员类型 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum TaskAssigneeType { + + /** + * 待办任务的审批人权限 + *

该权限表示用户是待办任务的审批人,负责审核任务的执行情况。

+ */ + APPROVER("1", "待办任务的审批人权限"), + + /** + * 待办任务的转办人权限 + *

该权限表示用户是待办任务的转办人,负责将任务分配给其他人员。

+ */ + TRANSFER("2", "待办任务的转办人权限"), + + /** + * 待办任务的委托人权限 + *

该权限表示用户是待办任务的委托人,能够委托其他人代为处理任务。

+ */ + DELEGATE("3", "待办任务的委托人权限"), + + /** + * 待办任务的抄送人权限 + *

该权限表示用户是待办任务的抄送人,仅接收任务信息的通知,不参与任务的审批或处理。

+ */ + COPY("4", "待办任务的抄送人权限"); + + /** + * 类型 + */ + private final String code; + + /** + * 描述 + */ + private final String description; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java new file mode 100644 index 0000000..d18ebb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java @@ -0,0 +1,104 @@ +package org.dromara.workflow.common.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 任务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum TaskStatusEnum { + + /** + * 撤销 + */ + CANCEL("cancel", "撤销"), + + /** + * 通过 + */ + PASS("pass", "通过"), + + /** + * 待审核 + */ + WAITING("waiting", "待审核"), + + /** + * 作废 + */ + INVALID("invalid", "作废"), + + /** + * 退回 + */ + BACK("back", "退回"), + + /** + * 终止 + */ + TERMINATION("termination", "终止"), + + /** + * 转办 + */ + TRANSFER("transfer", "转办"), + + /** + * 委托 + */ + DEPUTE("depute", "委托"), + + /** + * 抄送 + */ + COPY("copy", "抄送"), + + /** + * 加签 + */ + SIGN("sign", "加签"), + + /** + * 减签 + */ + SIGN_OFF("sign_off", "减签"), + + /** + * 超时 + */ + TIMEOUT("timeout", "超时"); + + /** + * 状态 + */ + private final String status; + + /** + * 描述 + */ + private final String desc; + + private static final Map STATUS_DESC_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(TaskStatusEnum::getStatus, TaskStatusEnum::getDesc)); + + /** + * 任务业务状态 + * + * @param status 状态 + */ + public static String findByStatus(String status) { + // 从缓存中直接获取描述 + return STATUS_DESC_MAP.getOrDefault(status, StrUtil.EMPTY); + } + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java new file mode 100644 index 0000000..08f1808 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java @@ -0,0 +1,16 @@ +package org.dromara.workflow.config; + +import org.dromara.workflow.common.ConditionalOnEnable; +import org.springframework.context.annotation.Configuration; + +/** + * warmFlow配置 + * + * @author may + */ +@ConditionalOnEnable +@Configuration +public class WarmFlowConfig { + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java new file mode 100644 index 0000000..3018b08 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java @@ -0,0 +1,136 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 流程分类 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/category") +public class FlwCategoryController extends BaseController { + + private final IFlwCategoryService flwCategoryService; + + /** + * 查询流程分类列表 + */ + @SaCheckPermission("workflow:category:list") + @GetMapping("/list") + public R> list(FlowCategoryBo bo) { + List list = flwCategoryService.queryList(bo); + return R.ok(list); + } + + /** + * 导出流程分类列表 + */ + @SaCheckPermission("workflow:category:export") + @Log(title = "流程分类", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FlowCategoryBo bo, HttpServletResponse response) { + List list = flwCategoryService.queryList(bo); + ExcelUtil.exportExcel(list, "流程分类", FlowCategoryVo.class, response); + } + + /** + * 获取流程分类详细信息 + * + * @param categoryId 主键 + */ + @SaCheckPermission("workflow:category:query") + @GetMapping("/{categoryId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long categoryId) { + flwCategoryService.checkCategoryDataScope(categoryId); + return R.ok(flwCategoryService.queryById(categoryId)); + } + + /** + * 新增流程分类 + */ + @SaCheckPermission("workflow:category:add") + @Log(title = "流程分类", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FlowCategoryBo category) { + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("新增流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } + return toAjax(flwCategoryService.insertByBo(category)); + } + + /** + * 修改流程分类 + */ + @SaCheckPermission("workflow:category:edit") + @Log(title = "流程分类", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) { + Long categoryId = category.getCategoryId(); + flwCategoryService.checkCategoryDataScope(categoryId); + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } else if (category.getParentId().equals(categoryId)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,上级流程分类不能是自己"); + } + return toAjax(flwCategoryService.updateByBo(category)); + } + + /** + * 删除流程分类 + * + * @param categoryId 主键 + */ + @SaCheckPermission("workflow:category:remove") + @Log(title = "流程分类", businessType = BusinessType.DELETE) + @DeleteMapping("/{categoryId}") + public R remove(@PathVariable Long categoryId) { + if (FlowConstant.FLOW_CATEGORY_ID.equals(categoryId)) { + return R.warn("默认流程分类,不允许删除"); + } + if (flwCategoryService.hasChildByCategoryId(categoryId)) { + return R.warn("存在下级流程分类,不允许删除"); + } + if (flwCategoryService.checkCategoryExistDefinition(categoryId)) { + return R.warn("流程分类存在流程定义,不允许删除"); + } + return toAjax(flwCategoryService.deleteWithValidById(categoryId)); + } + + /** + * 获取流程分类树列表 + * + * @param categoryBo 流程分类 + */ + @GetMapping("/categoryTree") + public R>> categoryTree(FlowCategoryBo categoryBo) { + return R.ok(flwCategoryService.selectCategoryTreeList(categoryBo)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java new file mode 100644 index 0000000..e21a1a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java @@ -0,0 +1,193 @@ +package org.dromara.workflow.controller; + +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.FlowDefinitionBo; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * 流程定义管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/definition") +public class FlwDefinitionController extends BaseController { + + private final DefService defService; + private final IFlwDefinitionService flwDefinitionService; + + /** + * 查询流程定义列表 + * + * @param flowDefinitionBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/list") + public TableDataInfo list(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) { + return flwDefinitionService.queryList(flowDefinitionBo, pageQuery); + } + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinitionBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/unPublishList") + public TableDataInfo unPublishList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) { + return flwDefinitionService.unPublishList(flowDefinitionBo, pageQuery); + } + + /** + * 获取流程定义详细信息 + * + * @param id 流程定义id + */ + @GetMapping(value = "/{id}") + public R getInfo(@PathVariable Long id) { + return R.ok(defService.getById(id)); + } + + /** + * 新增流程定义 + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PostMapping + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R add(@RequestBody FlowDefinition flowDefinition) { + return R.ok(defService.checkAndSave(flowDefinition)); + } + + /** + * 修改流程定义 + * + * @param flowDefinition 参数 + */ + @Log(title = "流程定义", businessType = BusinessType.UPDATE) + @PutMapping + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R edit(@RequestBody FlowDefinition flowDefinition) { + return R.ok(defService.updateById(flowDefinition)); + } + + /** + * 发布流程定义 + * + * @param id 流程定义id + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PutMapping("/publish/{id}") + @RepeatSubmit() + public R publish(@PathVariable Long id) { + return R.ok(flwDefinitionService.publish(id)); + } + + /** + * 取消发布流程定义 + * + * @param id 流程定义id + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PutMapping("/unPublish/{id}") + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R unPublish(@PathVariable Long id) { + return R.ok(defService.unPublish(id)); + } + + /** + * 删除流程定义 + */ + @Log(title = "流程定义", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@PathVariable List ids) { + return toAjax(flwDefinitionService.removeDef(ids)); + } + + /** + * 复制流程定义 + * + * @param id 流程定义id + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PostMapping("/copy/{id}") + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R copy(@PathVariable Long id) { + return R.ok(defService.copyDef(id)); + } + + /** + * 导入流程定义 + * + * @param file 文件 + * @param category 分类 + */ + @Log(title = "流程定义", businessType = BusinessType.IMPORT) + @PostMapping("/importDef") + public R importDef(MultipartFile file, String category) { + return R.ok(flwDefinitionService.importJson(file, category)); + } + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + @Log(title = "流程定义", businessType = BusinessType.EXPORT) + @PostMapping("/exportDef/{id}") + public void exportDef(@PathVariable Long id, HttpServletResponse response) throws IOException { + flwDefinitionService.exportDef(id, response); + } + + /** + * 获取流程定义JSON字符串 + * + * @param id 流程定义id + */ + @GetMapping("/xmlString/{id}") + public R xmlString(@PathVariable Long id) { + return R.ok("操作成功", defService.exportJson(id)); + } + + /** + * 激活/挂起流程定义 + * + * @param id 流程定义id + * @param active 激活/挂起 + */ + @RepeatSubmit() + @PutMapping("/active/{id}") + @Transactional(rollbackFor = Exception.class) + public R active(@PathVariable Long id, @RequestParam boolean active) { + return R.ok(active ? defService.active(id) : defService.unActive(id)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java new file mode 100644 index 0000000..e7ea5e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java @@ -0,0 +1,157 @@ +package org.dromara.workflow.controller; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; +import org.dromara.workflow.service.IFlwInstanceService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/instance") +public class FlwInstanceController extends BaseController { + + private final InsService insService; + private final IFlwInstanceService flwInstanceService; + + /** + * 查询正在运行的流程实例列表 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @GetMapping("/pageByRunning") + public TableDataInfo selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return flwInstanceService.selectRunningInstanceList(flowInstanceBo, pageQuery); + } + + /** + * 查询已结束的流程实例列表 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @GetMapping("/pageByFinish") + public TableDataInfo selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return flwInstanceService.selectFinishInstanceList(flowInstanceBo, pageQuery); + } + + /** + * 根据业务id查询流程实例详细信息 + * + * @param businessId 业务id + */ + @GetMapping("/getInfo/{businessId}") + public R getInfo(@PathVariable Long businessId) { + return R.ok(flwInstanceService.queryByBusinessId(businessId)); + } + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + */ + @DeleteMapping("/deleteByBusinessIds/{businessIds}") + public R deleteByBusinessIds(@PathVariable List businessIds) { + return toAjax(flwInstanceService.deleteByBusinessIds(businessIds)); + } + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + */ + @DeleteMapping("/deleteByInstanceIds/{instanceIds}") + public R deleteByInstanceIds(@PathVariable List instanceIds) { + return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds)); + } + + /** + * 撤销流程 + * + * @param bo 参数 + */ + @RepeatSubmit() + @PutMapping("/cancelProcessApply") + public R cancelProcessApply(@RequestBody FlowCancelBo bo) { + return toAjax(flwInstanceService.cancelProcessApply(bo)); + } + + /** + * 激活/挂起流程实例 + * + * @param id 流程实例id + * @param active 激活/挂起 + */ + @RepeatSubmit() + @PutMapping("/active/{id}") + public R active(@PathVariable Long id, @RequestParam boolean active) { + return R.ok(active ? insService.active(id) : insService.unActive(id)); + } + + /** + * 获取当前登陆人发起的流程实例 + * + * @param flowInstanceBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByCurrent") + public TableDataInfo selectCurrentInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return flwInstanceService.selectCurrentInstanceList(flowInstanceBo, pageQuery); + } + + /** + * 获取流程图,流程记录 + * + * @param businessId 业务id + */ + @GetMapping("/flowHisTaskList/{businessId}") + public R> flowHisTaskList(@PathVariable String businessId) { + return R.ok(flwInstanceService.flowHisTaskList(businessId)); + } + + /** + * 获取流程变量 + * + * @param instanceId 流程实例id + */ + @GetMapping("/instanceVariable/{instanceId}") + public R> instanceVariable(@PathVariable Long instanceId) { + return R.ok(flwInstanceService.instanceVariable(instanceId)); + } + + /** + * 作废流程 + * + * @param bo 参数 + */ + @Log(title = "流程实例管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/invalid") + public R invalid(@Validated @RequestBody FlowInvalidBo bo) { + return R.ok(flwInstanceService.processInvalid(bo)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java new file mode 100644 index 0000000..5534b67 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java @@ -0,0 +1,212 @@ +package org.dromara.workflow.controller; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 任务管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/task") +public class FlwTaskController extends BaseController { + + private final IFlwTaskService flwTaskService; + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/startWorkFlow") + public R startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) { + StartProcessReturnDTO startProcessReturn = flwTaskService.startWorkFlow(startProcessBo); + return R.ok("提交成功", startProcessReturn); + } + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/completeTask") + public R completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) { + return toAjax(flwTaskService.completeTask(completeTaskBo)); + } + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByTaskWait") + public TableDataInfo pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByTaskWait(flowTaskBo, pageQuery); + } + + /** + * 查询当前用户的已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + + @GetMapping("/pageByTaskFinish") + public TableDataInfo pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByTaskFinish(flowTaskBo, pageQuery); + } + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByAllTaskWait") + public TableDataInfo pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByAllTaskWait(flowTaskBo, pageQuery); + } + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByAllTaskFinish") + public TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByAllTaskFinish(flowTaskBo, pageQuery); + } + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByTaskCopy") + public TableDataInfo pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByTaskCopy(flowTaskBo, pageQuery); + } + + /** + * 根据taskId查询代表任务 + * + * @param taskId 任务id + */ + @GetMapping("/getTask/{taskId}") + public R getTask(@PathVariable Long taskId) { + return R.ok(flwTaskService.selectById(taskId)); + } + + /** + * 获取下一节点信息 + * + * @param bo 参数 + */ + @PostMapping("/getNextNodeList") + public R> getNextNodeList(@RequestBody FlowNextNodeBo bo) { + return R.ok(flwTaskService.getNextNodeList(bo)); + } + + /** + * 终止任务 + * + * @param bo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/terminationTask") + public R terminationTask(@RequestBody FlowTerminationBo bo) { + return R.ok(flwTaskService.terminationTask(bo)); + } + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + */ + @Log(title = "任务管理", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PostMapping("/taskOperation/{taskOperation}") + public R taskOperation(@Validated @RequestBody TaskOperationBo bo, @PathVariable String taskOperation) { + return toAjax(flwTaskService.taskOperation(bo, taskOperation)); + } + + /** + * 修改任务办理人 + * + * @param taskIdList 任务id + * @param userId 办理人id + */ + @Log(title = "任务管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/updateAssignee/{userId}") + public R updateAssignee(@RequestBody List taskIdList, @PathVariable String userId) { + return toAjax(flwTaskService.updateAssignee(taskIdList, userId)); + } + + /** + * 驳回审批 + * + * @param bo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/backProcess") + public R backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo bo) { + return toAjax(flwTaskService.backProcess(bo)); + } + + /** + * 获取可驳回的前置节点 + * + * @param definitionId 流程定义id + * @param nowNodeCode 当前节点 + */ + @GetMapping("/getBackTaskNode/{definitionId}/{nowNodeCode}") + public R> getBackTaskNode(@PathVariable Long definitionId, @PathVariable String nowNodeCode) { + return R.ok(flwTaskService.getBackTaskNode(definitionId, nowNodeCode)); + } + + /** + * 获取当前任务的所有办理人 + * + * @param taskId 任务id + */ + @GetMapping("/currentTaskAllUser/{taskId}") + public R> currentTaskAllUser(@PathVariable Long taskId) { + return R.ok(flwTaskService.currentTaskAllUser(taskId)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java new file mode 100644 index 0000000..98825d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java @@ -0,0 +1,108 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.service.ITestLeaveService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 请假 + * + * @author may + * @date 2023-07-21 + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/leave") +public class TestLeaveController extends BaseController { + + private final ITestLeaveService testLeaveService; + + /** + * 查询请假列表 + */ + @SaCheckPermission("workflow:leave:list") + @GetMapping("/list") + public TableDataInfo list(TestLeaveBo bo, PageQuery pageQuery) { + return testLeaveService.queryPageList(bo, pageQuery); + } + + /** + * 导出请假列表 + */ + @SaCheckPermission("workflow:leave:export") + @Log(title = "请假", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TestLeaveBo bo, HttpServletResponse response) { + List list = testLeaveService.queryList(bo); + ExcelUtil.exportExcel(list, "请假", TestLeaveVo.class, response); + } + + /** + * 获取请假详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("workflow:leave:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(testLeaveService.queryById(id)); + } + + /** + * 新增请假 + */ + @SaCheckPermission("workflow:leave:add") + @Log(title = "请假", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.insertByBo(bo)); + } + + /** + * 修改请假 + */ + @SaCheckPermission("workflow:leave:edit") + @Log(title = "请假", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.updateByBo(bo)); + } + + /** + * 删除请假 + * + * @param ids 主键串 + */ + @SaCheckPermission("workflow:leave:remove") + @Log(title = "请假", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java new file mode 100644 index 0000000..28918f1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java @@ -0,0 +1,67 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; +import java.util.ArrayList; +import java.util.List; + +/** + * 流程分类对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("flow_category") +public class FlowCategory extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程分类ID + */ + @TableId(value = "category_id") + private Long categoryId; + + /** + * 父流程分类id + */ + private Long parentId; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 流程分类名称 + */ + private String categoryName; + + /** + * 显示顺序 + */ + private Long orderNum; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 子菜单 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java new file mode 100644 index 0000000..7d42a9b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java @@ -0,0 +1,63 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 请假对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_leave") +public class TestLeave extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 请假类型 + */ + private String leaveType; + + /** + * 开始时间 + */ + private Date startDate; + + /** + * 结束时间 + */ + private Date endDate; + + /** + * 请假天数 + */ + private Integer leaveDays; + + /** + * 请假原因 + */ + private String remark; + + /** + * 状态 + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java new file mode 100644 index 0000000..a67a1f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java @@ -0,0 +1,69 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + + +/** + * 驳回参数请求 + * + * @author may + */ +@Data +public class BackProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotNull(message = "任务ID不能为空", groups = AddGroup.class) + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 驳回的节点id(目前未使用,直接驳回到申请人) + */ + private String nodeCode; + + /** + * 办理意见 + */ + private String message; + + /** + * 通知 + */ + private String notice; + + /** + * 流程变量 + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java new file mode 100644 index 0000000..360fc3b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java @@ -0,0 +1,80 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 办理任务请求对象 + * + * @author may + */ +@Data +public class CompleteTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotNull(message = "任务id不能为空", groups = {AddGroup.class}) + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 抄送人员 + */ + private List flowCopyList; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 办理意见 + */ + private String message; + + /** + * 消息通知 + */ + private String notice; + + /** + * 流程变量 + */ + private Map variables; + + /** + * 弹窗选择的办理人 + */ + private Map assigneeMap; + + /** + * 扩展变量(此处为逗号分隔的ossId) + */ + private String ext; + + public Map getVariables() { + if (variables == null) { + variables = new HashMap<>(16); + return variables; + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java new file mode 100644 index 0000000..31742ea --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 撤销任务请求对象 + * + * @author may + */ +@Data +public class FlowCancelBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotBlank(message = "业务ID不能为空", groups = AddGroup.class) + private String businessId; + + /** + * 办理意见 + */ + private String message; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java new file mode 100644 index 0000000..fd626eb --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java @@ -0,0 +1,47 @@ +package org.dromara.workflow.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.workflow.domain.FlowCategory; + +/** + * 流程分类业务对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = FlowCategory.class, reverseConvertGenerate = false) +public class FlowCategoryBo extends BaseEntity { + + /** + * 流程分类ID + */ + @NotNull(message = "流程分类ID不能为空", groups = { EditGroup.class }) + private Long categoryId; + + /** + * 父流程分类id + */ + @NotNull(message = "父流程分类id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long parentId; + + /** + * 流程分类名称 + */ + @NotBlank(message = "流程分类名称不能为空", groups = {AddGroup.class, EditGroup.class}) + private String categoryName; + + /** + * 显示顺序 + */ + private Long orderNum; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java new file mode 100644 index 0000000..a45e521 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java @@ -0,0 +1,30 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 抄送 + * + * @author may + */ +@Data +public class FlowCopyBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户名称 + */ + private String userName; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowDefinitionBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowDefinitionBo.java new file mode 100644 index 0000000..307f514 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowDefinitionBo.java @@ -0,0 +1,25 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.warm.flow.orm.entity.FlowDefinition; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author lilemy + * @date 2025/7/3 16:54 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class FlowDefinitionBo extends FlowDefinition implements Serializable { + + @Serial + private static final long serialVersionUID = 2120294203941407990L; + + /** + * 项目id + */ + private Long projectId; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java new file mode 100644 index 0000000..fb1fe61 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java @@ -0,0 +1,55 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 流程实例请求对象 + * + * @author may + */ +@Data +public class FlowInstanceBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 任务发起人 + */ + private String startUserId; + + /** + * 业务id + */ + private String businessId; + + /** + * 流程分类id + */ + private String category; + + /** + * 任务名称 + */ + private String nodeName; + + /** + * 申请人Ids + */ + private List createByIds; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java new file mode 100644 index 0000000..297bd00 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 作废请求对象 + * + * @author may + */ +@Data +public class FlowInvalidBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + @NotNull(message = "流程实例id为空", groups = AddGroup.class) + private Long id; + + /** + * 审批意见 + */ + private String comment; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java new file mode 100644 index 0000000..12f0653 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java @@ -0,0 +1,38 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 下一节点信息 + * + * @author may + */ +@Data +public class FlowNextNodeBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + /** + * 任务id + */ + private Long taskId; + + /** + * 流程变量 + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java new file mode 100644 index 0000000..64dd082 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java @@ -0,0 +1,55 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 任务请求对象 + * + * @author may + */ +@Data +public class FlowTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务名称 + */ + private String nodeName; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程实例id + */ + private Long instanceId; + + /** + * 权限列表 + */ + private List permissionList; + + /** + * 申请人Ids + */ + private List createByIds; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java new file mode 100644 index 0000000..897fc21 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 终止任务请求对象 + * + * @author may + */ +@Data +public class FlowTerminationBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotNull(message = "任务id为空", groups = AddGroup.class) + private Long taskId; + + /** + * 审批意见 + */ + private String comment; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java new file mode 100644 index 0000000..ea21a81 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.domain.bo; + + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 启动流程对象 + * + * @author may + */ +@Data +public class StartProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 业务唯一值id + */ + @NotBlank(message = "业务ID不能为空", groups = {AddGroup.class}) + private String businessId; + + /** + * 流程定义编码 + */ + @NotBlank(message = "流程定义编码不能为空", groups = {AddGroup.class}) + private String flowCode; + + /** + * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java new file mode 100644 index 0000000..4348e31 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java @@ -0,0 +1,48 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 任务操作业务对象,用于描述任务委派、转办、加签等操作的必要参数 + * 包含了用户ID、任务ID、任务相关的消息、以及加签/减签的用户ID + * + * @author AprilWind + */ +@Data +public class TaskOperationBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 委派/转办人的用户ID(必填,准对委派/转办人操作) + */ + @NotNull(message = "委派/转办人id不能为空", groups = {AddGroup.class}) + private String userId; + + /** + * 加签/减签人的用户ID列表(必填,针对加签/减签操作) + */ + @NotNull(message = "加签/减签id不能为空", groups = {EditGroup.class}) + private List userIds; + + /** + * 任务ID(必填) + */ + @NotNull(message = "任务id不能为空") + private Long taskId; + + /** + * 意见或备注信息(可选) + */ + private String message; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java new file mode 100644 index 0000000..395f71d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java @@ -0,0 +1,82 @@ +package org.dromara.workflow.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.workflow.domain.TestLeave; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 请假业务对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TestLeave.class, reverseConvertGenerate = false) +public class TestLeaveBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 请假类型 + */ + @NotBlank(message = "请假类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String leaveType; + + /** + * 开始时间 + */ + @NotNull(message = "开始时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date startDate; + + /** + * 结束时间 + */ + @NotNull(message = "结束时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date endDate; + + /** + * 请假天数 + */ + private Integer leaveDays; + + /** + * 开始时间 + */ + private Integer startLeaveDays; + + /** + * 结束时间 + */ + private Integer endLeaveDays; + + /** + * 请假原因 + */ + private String remark; + + /** + * 状态 + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ButtonPermissionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ButtonPermissionVo.java new file mode 100644 index 0000000..7175e5e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ButtonPermissionVo.java @@ -0,0 +1,43 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 按钮权限 + * + * @author may + * @date 2025-02-28 + */ +@Data +public class ButtonPermissionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 唯一编码 + */ + private String code; + + /** + * 选项值 + */ + private String value; + + /** + * 是否显示 + */ + private Boolean show; + + public ButtonPermissionVo() { + } + + public ButtonPermissionVo(String code, Boolean show) { + this.code = code; + this.show = show; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java new file mode 100644 index 0000000..37d1bc8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java @@ -0,0 +1,69 @@ +package org.dromara.workflow.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.FlowCategory; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 流程分类视图对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FlowCategory.class) +public class FlowCategoryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程分类ID + */ + @ExcelProperty(value = "流程分类ID") + private Long categoryId; + + /** + * 父级分类id + */ + private Long parentId; + + /** + * 父级分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "parentId") + private String parentName; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 流程分类名称 + */ + @ExcelProperty(value = "流程分类名称") + private String categoryName; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "显示顺序") + private Long orderNum; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java new file mode 100644 index 0000000..aef7573 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java @@ -0,0 +1,104 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 流程定义视图 + * + * @author may + */ +@Data +public class FlowDefinitionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 流程版本 + */ + private String version; + + /** + * 是否发布(0未发布 1已发布 9失效) + */ + private Integer isPublish; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 流程激活状态(0挂起 1激活) + */ + private Integer activityStatus; + + /** + * 监听器类型 + */ + private String listenerType; + + /** + * 监听器路径 + */ + private String listenerPath; + + /** + * 扩展字段,预留给业务系统使用 + */ + private String ext; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java new file mode 100644 index 0000000..8776a76 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java @@ -0,0 +1,244 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.warm.flow.core.enums.CooperateType; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 历史任务视图 + * + * @author may + */ +@Data +public class FlowHisTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程实例表id + */ + private Long instanceId; + + /** + * 任务表id + */ + private Long taskId; + + /** + * 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + */ + private Integer cooperateType; + + /** + * 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + */ + private String cooperateTypeName; + + /** + * 业务id + */ + private String businessId; + + /** + * 开始节点编码 + */ + private String nodeCode; + + /** + * 开始节点名称 + */ + private String nodeName; + + /** + * 开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 目标节点编码 + */ + private String targetNodeCode; + + /** + * 结束节点名称 + */ + private String targetNodeName; + + /** + * 审批者 + */ + private String approver; + + /** + * 审批者 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "approver") + private String approveName; + + /** + * 协作人(只有转办、会签、票签、委派) + */ + private String collaborator; + + /** + * 权限标识 permissionFlag的list形式 + */ + private List permissionList; + + /** + * 跳转类型(PASS通过 REJECT退回 NONE无动作) + */ + private String skipType; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 任务状态 + */ + private String flowTaskStatus; + + /** + * 流程状态 + */ + private String flowStatusName; + + /** + * 审批意见 + */ + private String message; + + /** + * 业务详情 存业务类的json + */ + private String ext; + + /** + * 创建者 + */ + private String createBy; + + /** + * 申请人 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程版本号 + */ + private String version; + + /** + * 运行时长 + */ + private String runDuration; + + /** + * 设置创建时间并计算任务运行时长 + * + * @param createTime 创建时间 + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + updateRunDuration(); + } + + /** + * 设置更新时间并计算任务运行时长 + * + * @param updateTime 更新时间 + */ + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + updateRunDuration(); + } + + /** + * 更新运行时长 + */ + private void updateRunDuration() { + // 如果创建时间和更新时间均不为空,计算它们之间的时长 + if (this.updateTime != null && this.createTime != null) { + this.runDuration = DateUtils.getTimeDifference(this.updateTime, this.createTime); + } + } + + /** + * 设置协作方式,并通过协作方式获取名称 + */ + public void setCooperateType(Integer cooperateType) { + this.cooperateType = cooperateType; + this.cooperateTypeName = CooperateType.getValueByKey(cooperateType); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java new file mode 100644 index 0000000..75543f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java @@ -0,0 +1,137 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.util.Date; + +/** + * 流程实例视图 + * + * @author may + */ +@Data +public class FlowInstanceVo { + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 业务id + */ + private String businessId; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 流程节点编码 每个流程的nodeCode是唯一的,即definitionId+nodeCode唯一,在数据库层面做了控制 + */ + private String nodeCode; + + /** + * 流程节点名称 + */ + private String nodeName; + + /** + * 流程变量 + */ + private String variable; + + /** + * 流程状态(0待提交 1审批中 2 审批通过 3自动通过 8已完成 9已退回 10失效) + */ + private String flowStatus; + + /** + * 流程状态 + */ + private String flowStatusName; + + /** + * 流程激活状态(0挂起 1激活) + */ + private Integer activityStatus; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 扩展字段,预留给业务系统使用 + */ + private String ext; + + /** + * 流程定义版本 + */ + private String version; + + /** + * 创建者 + */ + private String createBy; + + /** + * 申请人 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java new file mode 100644 index 0000000..07a22c4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java @@ -0,0 +1,187 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.warm.flow.core.entity.User; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 任务视图 + * + * @author may + */ +@Data +public class FlowTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程实例表id + */ + private Long instanceId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 业务id + */ + private String businessId; + + /** + * 节点编码 + */ + private String nodeCode; + + /** + * 节点名称 + */ + private String nodeName; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 权限标识 permissionFlag的list形式 + */ + private List permissionList; + + /** + * 流程用户列表 + */ + private List userList; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单 + */ + private String formPath; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程版本号 + */ + private String version; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 流程状态 + */ + @Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "flowStatus", other = "wf_business_status") + private String flowStatusName; + + /** + * 办理人类型 + */ + private String type; + + /** + * 办理人ids + */ + private String assigneeIds; + + /** + * 办理人名称 + */ + private String assigneeNames; + + /** + * 抄送人id + */ + private String processedBy; + + /** + * 抄送人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "processedBy") + private String processedByName; + + /** + * 流程签署比例值 大于0为票签,会签 + */ + private BigDecimal nodeRatio; + + /** + * 申请人id + */ + private String createBy; + + /** + * 申请人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 是否为申请人节点 + */ + private Boolean applyNode; + + /** + * 按钮权限 + */ + private List buttonList; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java new file mode 100644 index 0000000..b4de76e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java @@ -0,0 +1,28 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程变量 + * + * @author may + */ +@Data +public class FlowVariableVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 变量key + */ + private String key; + + /** + * 变量值 + */ + private String value; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java new file mode 100644 index 0000000..47886d7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.workflow.domain.TestLeave; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 请假视图对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TestLeave.class) +public class TestLeaveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 请假类型 + */ + @ExcelProperty(value = "请假类型") + private String leaveType; + + /** + * 开始时间 + */ + @ExcelProperty(value = "开始时间") + private Date startDate; + + /** + * 结束时间 + */ + @ExcelProperty(value = "结束时间") + private Date endDate; + + /** + * 请假天数 + */ + @ExcelProperty(value = "请假天数") + private Integer leaveDays; + + /** + * 备注 + */ + @ExcelProperty(value = "请假原因") + private String remark; + + /** + * 状态 + */ + @ExcelProperty(value = "状态") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java new file mode 100644 index 0000000..c465271 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java @@ -0,0 +1,91 @@ +package org.dromara.workflow.handler; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 流程监听服务 + * + * @author may + * @date 2024-06-02 + */ +@ConditionalOnEnable +@Slf4j +@Component +public class FlowProcessEventHandler { + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * + * @param flowCode 流程定义编码 + * @param instance 实例数据 + * @param status 流程状态 + * @param params 办理参数 + * @param submit 当为true时为申请人节点办理 + */ + public void processHandler(String flowCode, Instance instance, String status, Map params, boolean submit) { + String tenantId = TenantHelper.getTenantId(); + log.info("【流程事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 流程状态: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 是否申请人节点: {}, 参数: {}", + tenantId, flowCode, instance.getBusinessId(), status, instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), submit, params); + ProcessEvent processEvent = new ProcessEvent(); + processEvent.setTenantId(tenantId); + processEvent.setFlowCode(flowCode); + processEvent.setBusinessId(instance.getBusinessId()); + processEvent.setNodeType(instance.getNodeType()); + processEvent.setNodeCode(instance.getNodeCode()); + processEvent.setNodeName(instance.getNodeName()); + processEvent.setStatus(status); + processEvent.setParams(params); + processEvent.setSubmit(submit); + SpringUtils.context().publishEvent(processEvent); + } + + /** + * 执行创建任务监听 + * + * @param flowCode 流程定义编码 + * @param instance 实例数据 + * @param taskId 任务id + */ + public void processTaskHandler(String flowCode, Instance instance, Long taskId) { + String tenantId = TenantHelper.getTenantId(); + log.info("【流程任务事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 任务ID: {}", + tenantId, flowCode, instance.getBusinessId(), instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), taskId); + ProcessTaskEvent processTaskEvent = new ProcessTaskEvent(); + processTaskEvent.setTenantId(tenantId); + processTaskEvent.setFlowCode(flowCode); + processTaskEvent.setBusinessId(instance.getBusinessId()); + processTaskEvent.setNodeType(instance.getNodeType()); + processTaskEvent.setNodeCode(instance.getNodeCode()); + processTaskEvent.setNodeName(instance.getNodeName()); + processTaskEvent.setTaskId(taskId); + processTaskEvent.setStatus(instance.getFlowStatus()); + SpringUtils.context().publishEvent(processTaskEvent); + } + + /** + * 删除流程监听 + * + * @param flowCode 流程定义编码 + * @param businessId 业务ID + */ + public void processDeleteHandler(String flowCode, String businessId) { + String tenantId = TenantHelper.getTenantId(); + log.info("【流程删除事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}", tenantId, flowCode, businessId); + ProcessDeleteEvent processDeleteEvent = new ProcessDeleteEvent(); + processDeleteEvent.setTenantId(tenantId); + processDeleteEvent.setFlowCode(flowCode); + processDeleteEvent.setBusinessId(businessId); + SpringUtils.context().publishEvent(processDeleteEvent); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java new file mode 100644 index 0000000..f9ede15 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java @@ -0,0 +1,59 @@ +package org.dromara.workflow.handler; + +import cn.hutool.core.collection.CollUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.handler.PermissionHandler; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.service.IFlwCommonService; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +/** + * 办理人权限处理器 + * + * @author AprilWind + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Component +@Slf4j +public class WorkflowPermissionHandler implements PermissionHandler { + + private final IFlwCommonService flwCommonService; + + /** + * 办理人权限标识,比如用户,角色,部门等,用于校验是否有权限办理任务 + * 后续在{@link FlowParams#getPermissionFlag} 中获取 + * 返回当前用户权限集合 + */ + @Override + public List permissions() { + return Collections.singletonList(LoginHelper.getUserIdStr()); + } + + /** + * 获取当前办理人 + * + * @return 当前办理人 + */ + @Override + public String getHandler() { + return LoginHelper.getUserIdStr(); + } + + /** + * 转换办理人,比如设计器中预设了能办理的人,如果其中包含角色或者部门id等,可以通过此接口进行转换成用户id + */ + @Override + public List convertPermissions(List permissions) { + if (CollUtil.isNotEmpty(permissions)) { + permissions = flwCommonService.buildUser(permissions); + } + return permissions; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java new file mode 100644 index 0000000..c1ef262 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java @@ -0,0 +1,193 @@ +package org.dromara.workflow.listener; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.listener.GlobalListener; +import org.dromara.warm.flow.core.listener.ListenerVariable; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.FlowCopyBo; +import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 全局任务办理监听 + * + * @author may + */ +@ConditionalOnEnable +@Component +@Slf4j +@RequiredArgsConstructor +public class WorkflowGlobalListener implements GlobalListener { + + private final IFlwTaskService flwTaskService; + private final IFlwInstanceService instanceService; + private final FlowProcessEventHandler flowProcessEventHandler; + private final IFlwCommonService flwCommonService; + private final InsService insService; + + /** + * 创建监听器,任务创建时执行 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void create(ListenerVariable listenerVariable) { + + } + + /** + * 开始监听器,任务开始办理时执行 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void start(ListenerVariable listenerVariable) { + } + + /** + * 分派监听器,动态修改代办任务信息 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void assignment(ListenerVariable listenerVariable) { + Map variable = listenerVariable.getVariable(); + List nextTasks = listenerVariable.getNextTasks(); + FlowParams flowParams = listenerVariable.getFlowParams(); + Definition definition = listenerVariable.getDefinition(); + Instance instance = listenerVariable.getInstance(); + String applyNodeCode = flwCommonService.applyNodeCode(definition.getId()); + for (Task flowTask : nextTasks) { + // 如果办理或者退回并行存在需要指定办理人,则直接覆盖办理人 + if (variable.containsKey(flowTask.getNodeCode()) && (TaskStatusEnum.PASS.getStatus().equals(flowParams.getHisStatus()) + || TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus()))) { + String userIds = variable.get(flowTask.getNodeCode()).toString(); + flowTask.setPermissionList(List.of(userIds.split(StringUtils.SEPARATOR))); + variable.remove(flowTask.getNodeCode()); + } + // 如果是申请节点,则把启动人添加到办理人 + if (flowTask.getNodeCode().equals(applyNodeCode)) { + flowTask.setPermissionList(List.of(instance.getCreateBy())); + } + } + } + + /** + * 完成监听器,当前任务完成后执行 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void finish(ListenerVariable listenerVariable) { + Instance instance = listenerVariable.getInstance(); + Definition definition = listenerVariable.getDefinition(); + Task task = listenerVariable.getTask(); + Map params = new HashMap<>(); + FlowParams flowParams = listenerVariable.getFlowParams(); + Map variable = new HashMap<>(); + if (ObjectUtil.isNotNull(flowParams)) { + // 历史任务扩展(通常为附件) + params.put("hisTaskExt", flowParams.getHisTaskExt()); + // 办理人 + params.put("handler", flowParams.getHandler()); + // 办理意见 + params.put("message", flowParams.getMessage()); + variable = flowParams.getVariable(); + } + //申请人提交事件 + Boolean submit = MapUtil.getBool(variable, FlowConstant.SUBMIT); + if (submit != null && submit) { + flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, instance.getFlowStatus(), variable, true); + } else { + // 判断流程状态(发布:撤销,退回,作废,终止,已完成事件) + String status = determineFlowStatus(instance); + if (StringUtils.isNotBlank(status)) { + flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, params, false); + } + } + //发布任务事件 + if (task != null) { + flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, task.getId()); + } + if (ObjectUtil.isNull(flowParams)) { + return; + } + // 只有办理或者退回的时候才执行消息通知和抄送 + if (TaskStatusEnum.PASS.getStatus().equals(flowParams.getHisStatus()) + || TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus())) { + if (variable != null) { + if (variable.containsKey(FlowConstant.FLOW_COPY_LIST)) { + List flowCopyList = (List) variable.get(FlowConstant.FLOW_COPY_LIST); + // 添加抄送人 + flwTaskService.setCopy(task, flowCopyList); + } + if (variable.containsKey(FlowConstant.MESSAGE_TYPE)) { + List messageType = (List) variable.get(FlowConstant.MESSAGE_TYPE); + String notice = (String) variable.get(FlowConstant.MESSAGE_NOTICE); + // 消息通知 + if (CollUtil.isNotEmpty(messageType)) { + flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice); + } + } + FlowInstance ins = new FlowInstance(); + Map variableMap = instance.getVariableMap(); + variableMap.remove(FlowConstant.FLOW_COPY_LIST); + variableMap.remove(FlowConstant.MESSAGE_TYPE); + variableMap.remove(FlowConstant.MESSAGE_NOTICE); + variableMap.remove(FlowConstant.SUBMIT); + ins.setId(instance.getId()); + ins.setVariable(FlowEngine.jsonConvert.objToStr(variableMap)); + insService.updateById(ins); + } + } + } + + /** + * 根据流程实例确定最终状态 + * + * @param instance 流程实例 + * @return 流程最终状态 + */ + private String determineFlowStatus(Instance instance) { + String flowStatus = instance.getFlowStatus(); + if (StringUtils.isNotBlank(flowStatus) && BusinessStatusEnum.initialState(flowStatus)) { + log.info("流程实例当前状态: {}", flowStatus); + return flowStatus; + } else { + Long instanceId = instance.getId(); + List flowTasks = flwTaskService.selectByInstId(instanceId); + if (CollUtil.isEmpty(flowTasks)) { + String status = BusinessStatusEnum.FINISH.getStatus(); + // 更新流程状态为已完成 + instanceService.updateStatus(instanceId, status); + log.info("流程已结束,状态更新为: {}", status); + return status; + } + return null; + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java new file mode 100644 index 0000000..4a59f25 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java @@ -0,0 +1,62 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.vo.FlowCategoryVo; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 流程分类Mapper接口 + * + * @author may + * @date 2023-06-27 + */ +public interface FlwCategoryMapper extends BaseMapperPlus { + + /** + * 统计指定流程分类ID的分类数量 + * + * @param categoryId 流程分类ID + * @return 该流程分类ID的分类数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "createDept") + }) + default long countCategoryById(Long categoryId) { + return this.selectCount(new LambdaQueryWrapper().eq(FlowCategory::getCategoryId, categoryId)); + } + + /** + * 根据父流程分类ID查询其所有子流程分类的列表 + * + * @param parentId 父流程分类ID + * @return 包含子流程分类的列表 + */ + default List selectListByParentId(Long parentId) { + return this.selectList(new LambdaQueryWrapper() + .select(FlowCategory::getCategoryId) + .apply(DataBaseHelper.findInSet(parentId, "ancestors"))); + } + + /** + * 根据父流程分类ID查询包括父ID及其所有子流程分类ID的列表 + * + * @param parentId 父流程分类ID + * @return 包含父ID和子流程分类ID的列表 + */ + default List selectCategoryIdsByParentId(Long parentId) { + return Stream.concat( + this.selectListByParentId(parentId).stream() + .map(FlowCategory::getCategoryId), + Stream.of(parentId) + ).collect(Collectors.toList()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java new file mode 100644 index 0000000..92809c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java @@ -0,0 +1,27 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; + +/** + * 实例信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwInstanceMapper { + + /** + * 流程实例信息 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page selectInstanceList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java new file mode 100644 index 0000000..fd86c82 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java @@ -0,0 +1,57 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.workflow.domain.bo.FlowTaskBo; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; + +import java.util.List; + + +/** + * 任务信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwTaskMapper { + + /** + * 获取待办信息 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getListRunTask(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 获取待办信息 + * + * @param queryWrapper 条件 + * @return 结果 + */ + List getListRunTask(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 获取已办 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getListFinishTask(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 查询当前用户的抄送 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getTaskCopyByPage(@Param("page") Page page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java new file mode 100644 index 0000000..cd1edba --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +/** + * 请假Mapper接口 + * + * @author may + * @date 2023-07-21 + */ +public interface TestLeaveMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java new file mode 100644 index 0000000..91f173d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java @@ -0,0 +1,102 @@ +package org.dromara.workflow.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; + +import java.util.List; + +/** + * 流程分类Service接口 + * + * @author may + */ +public interface IFlwCategoryService { + + /** + * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 + */ + FlowCategoryVo queryById(Long categoryId); + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryId 流程分类ID + * @return 流程分类名称 + */ + String selectCategoryNameById(Long categoryId); + + /** + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 + */ + List queryList(FlowCategoryBo bo); + + /** + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 + */ + List> selectCategoryTreeList(FlowCategoryBo category); + + /** + * 校验流程分类是否有数据权限 + * + * @param categoryId 流程分类ID + */ + void checkCategoryDataScope(Long categoryId); + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + boolean checkCategoryNameUnique(FlowCategoryBo category); + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkCategoryExistDefinition(Long categoryId); + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + boolean hasChildByCategoryId(Long categoryId); + + /** + * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 + */ + int insertByBo(FlowCategoryBo bo); + + /** + * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 + */ + int updateByBo(FlowCategoryBo bo); + + /** + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 + */ + int deleteWithValidById(Long categoryId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java new file mode 100644 index 0000000..662d599 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java @@ -0,0 +1,37 @@ +package org.dromara.workflow.service; + +import java.util.List; + +/** + * 通用 工作流服务 + * + * @author LionLi + */ +public interface IFlwCommonService { + + /** + * 构建工作流用户 + * + * @param permissionList 办理用户 + * @return 用户 + */ + List buildUser(List permissionList); + + /** + * 发送消息 + * + * @param flowName 流程定义名称 + * @param instId 实例id + * @param messageType 消息类型 + * @param message 消息内容,为空则发送默认配置的消息内容 + */ + void sendMessage(String flowName, Long instId, List messageType, String message); + + /** + * 申请人节点编码 + * + * @param definitionId 流程定义id + * @return 申请人节点编码 + */ + String applyNodeCode(Long definitionId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java new file mode 100644 index 0000000..6076260 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java @@ -0,0 +1,85 @@ +package org.dromara.workflow.service; + +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.bo.FlowDefinitionBo; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * 流程定义 服务层 + * + * @author may + */ +public interface IFlwDefinitionService { + + /** + * 查询流程定义列表 + * + * @param flowDefinitionBo 参数 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + TableDataInfo queryList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery); + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinitionBo 参数 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + TableDataInfo unPublishList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery); + + /** + * 发布流程定义 + * + * @param id 流程定义id + * @return 结果 + */ + boolean publish(Long id); + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + void exportDef(Long id, HttpServletResponse response) throws IOException; + + /** + * 导入流程定义 + * + * @param file 文件 + * @param category 分类 + * @return 结果 + */ + boolean importJson(MultipartFile file, String category); + + /** + * 删除流程定义 + * + * @param ids 流程定义id + * @return 结果 + */ + boolean removeDef(List ids); + + /** + * 新增流程定义 + * + * @param projectId 项目id + */ + void insertDefByProjectId(Long projectId); + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + void syncDef(String tenantId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java new file mode 100644 index 0000000..01e5124 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java @@ -0,0 +1,159 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例 服务层 + * + * @author may + */ +public interface IFlwInstanceService { + + /** + * 分页查询正在运行的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery); + + /** + * 分页查询已结束的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery); + + /** + * 根据业务id查询流程实例详细信息 + * + * @param businessId 业务id + * @return 结果 + */ + FlowInstanceVo queryByBusinessId(Long businessId); + + /** + * 按照业务id查询流程实例 + * + * @param businessId 业务id + * @return 结果 + */ + FlowInstance selectInstByBusinessId(String businessId); + + /** + * 按照实例id查询流程实例 + * + * @param instanceId 实例id + * @return 结果 + */ + FlowInstance selectInstById(Long instanceId); + + /** + * 按照实例id查询流程实例 + * + * @param instanceIds 实例id + * @return 结果 + */ + List selectInstListByIdList(List instanceIds); + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + * @return 结果 + */ + boolean deleteByBusinessIds(List businessIds); + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + * @return 结果 + */ + boolean deleteByInstanceIds(List instanceIds); + + /** + * 撤销流程 + * + * @param bo 参数 + * @return 结果 + */ + boolean cancelProcessApply(FlowCancelBo bo); + + /** + * 获取当前登陆人发起的流程实例 + * + * @param instanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery); + + /** + * 获取流程图,流程记录 + * + * @param businessId 业务id + * @return 结果 + */ + Map flowHisTaskList(String businessId); + + /** + * 按照实例id更新状态 + * + * @param instanceId 实例id + * @param status 状态 + */ + void updateStatus(Long instanceId, String status); + + /** + * 获取流程变量 + * + * @param instanceId 实例id + * @return 结果 + */ + Map instanceVariable(Long instanceId); + + /** + * 设置流程变量 + * + * @param instanceId 实例id + * @param variable 流程变量 + */ + void setVariable(Long instanceId, Map variable); + + /** + * 按任务id查询实例 + * + * @param taskId 任务id + * @return 结果 + */ + FlowInstance selectByTaskId(Long taskId); + + /** + * 按任务id查询实例 + * + * @param taskIdList 任务id + * @return 结果 + */ + List selectByTaskIdList(List taskIdList); + + /** + * 作废流程 + * + * @param bo 流程实例 + * @return 结果 + */ + boolean processInvalid(FlowInvalidBo bo); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java new file mode 100644 index 0000000..9595165 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java @@ -0,0 +1,22 @@ +package org.dromara.workflow.service; + +import org.dromara.workflow.domain.vo.ButtonPermissionVo; + +import java.util.List; + +/** + * 流程节点扩展属性 服务层 + * + * @author AprilWind + */ +public interface IFlwNodeExtService { + + /** + * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选 + * + * @param ext 扩展属性 JSON 字符串 + * @return 按钮权限 VO 列表 + */ + List buildButtonPermissionsFromExt(String ext); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java new file mode 100644 index 0000000..830abaf --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.dto.UserDTO; + +import java.util.List; + +/** + * 流程设计器-获取办理人 + * + * @author AprilWind + */ +public interface IFlwTaskAssigneeService { + + /** + * 批量解析多个存储标识符(storageIds),按类型分类并合并查询用户列表 + * 输入格式支持多个以逗号分隔的标识(如 "user:123,role:456,789") + * 会自动去重返回结果,非法格式的标识将被忽略 + * + * @param storageIds 多个存储标识符字符串(逗号分隔) + * @return 合并后的用户列表,去重后返回,非法格式的标识将被跳过 + */ + List fetchUsersByStorageIds(String storageIds); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java new file mode 100644 index 0000000..e172c00 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java @@ -0,0 +1,218 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; + +import java.util.List; +import java.util.Map; + +/** + * 任务 服务层 + * + * @author may + */ +public interface IFlwTaskService { + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + * @return 结果 + */ + StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo); + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + * @return 结果 + */ + boolean completeTask(CompleteTaskBo completeTaskBo); + + /** + * 添加抄送人 + * + * @param task 任务信息 + * @param flowCopyList 抄送人 + */ + void setCopy(Task task, List flowCopyList); + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询当前租户所有待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 修改任务办理人 + * + * @param taskIdList 任务id + * @param userId 用户id + * @return 结果 + */ + boolean updateAssignee(List taskIdList, String userId); + + /** + * 驳回审批 + * + * @param bo 参数 + * @return 结果 + */ + boolean backProcess(BackProcessBo bo); + + /** + * 获取可驳回的前置节点 + * + * @param definitionId 流程定义id + * @param nowNodeCode 当前节点 + * @return 结果 + */ + List getBackTaskNode(Long definitionId, String nowNodeCode); + + /** + * 终止任务 + * + * @param bo 参数 + * @return 结果 + */ + boolean terminationTask(FlowTerminationBo bo); + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 结果 + */ + List selectByIdList(List taskIdList); + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 结果 + */ + FlowTaskVo selectById(Long taskId); + + /** + * 获取下一节点信息 + * + * @param bo 参数 + * @return 结果 + */ + List getNextNodeList(FlowNextNodeBo bo); + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 结果 + */ + List selectHisTaskByIdList(List taskIdList); + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 结果 + */ + FlowHisTask selectHisTaskById(Long taskId); + + /** + * 按照实例id查询任务 + * + * @param instanceIdList 流程实例id + * @return 结果 + */ + List selectByInstIdList(List instanceIdList); + + /** + * 按照实例id查询任务 + * + * @param instanceId 流程实例id + * @return 结果 + */ + List selectByInstId(Long instanceId); + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + * @return 结果 + */ + boolean taskOperation(TaskOperationBo bo, String taskOperation); + + /** + * 获取任务所有办理人 + * + * @param taskIdList 任务id + * @return 结果 + */ + Map> currentTaskAllUser(List taskIdList); + + /** + * 获取当前任务的所有办理人 + * + * @param taskId 任务id + * @return 结果 + */ + List currentTaskAllUser(Long taskId); + + /** + * 按照节点编码查询节点 + * + * @param nodeCode 节点编码 + * @param definitionId 流程定义id + * @return 节点 + */ + FlowNode getByNodeCode(String nodeCode, Long definitionId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java new file mode 100644 index 0000000..67b50ba --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java @@ -0,0 +1,47 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +import java.util.List; + +/** + * 请假Service接口 + * + * @author may + * @date 2023-07-21 + */ +public interface ITestLeaveService { + + /** + * 查询请假 + */ + TestLeaveVo queryById(Long id); + + /** + * 查询请假列表 + */ + TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery); + + /** + * 查询请假列表 + */ + List queryList(TestLeaveBo bo); + + /** + * 新增请假 + */ + TestLeaveVo insertByBo(TestLeaveBo bo); + + /** + * 修改请假 + */ + TestLeaveVo updateByBo(TestLeaveBo bo); + + /** + * 校验并批量删除请假信息 + */ + Boolean deleteWithValidByIds(List ids); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java new file mode 100644 index 0000000..883a967 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.translation.annotation.TranslationType; +import org.dromara.common.translation.core.TranslationInterface; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.stereotype.Service; + +/** + * 流程分类名称翻译实现 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +@TranslationType(type = FlowConstant.CATEGORY_ID_TO_NAME) +public class CategoryNameTranslationImpl implements TranslationInterface { + + private final IFlwCategoryService flwCategoryService; + + @Override + public String translation(Object key, String other) { + return flwCategoryService.selectCategoryNameById(Convert.toLong(key)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java new file mode 100644 index 0000000..d42a48a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java @@ -0,0 +1,258 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.TreeBuildUtils; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * 流程分类Service业务层处理 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +public class FlwCategoryServiceImpl implements IFlwCategoryService { + + private final DefService defService; + private final FlwCategoryMapper baseMapper; + + /** + * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 + */ + @Override + public FlowCategoryVo queryById(Long categoryId) { + return baseMapper.selectVoById(categoryId); + } + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryId 流程分类ID + * @return 流程分类名称 + */ + @Cacheable(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId") + @Override + public String selectCategoryNameById(Long categoryId) { + if (ObjectUtil.isNull(categoryId)) { + return null; + } + FlowCategory category = baseMapper.selectOne(new LambdaQueryWrapper() + .select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, categoryId)); + return ObjectUtils.notNullGetter(category, FlowCategory::getCategoryName); + } + + /** + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 + */ + @Override + public List queryList(FlowCategoryBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + /** + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 + */ + @Override + public List> selectCategoryTreeList(FlowCategoryBo category) { + List categoryList = this.queryList(category); + if (CollUtil.isEmpty(categoryList)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.buildMultiRoot( + categoryList, + node -> String.valueOf(node.getCategoryId()), + node -> String.valueOf(node.getParentId()), + (node, treeNode) -> treeNode + .setId(String.valueOf(node.getCategoryId())) + .setParentId(String.valueOf(node.getParentId())) + .setName(node.getCategoryName()) + .setWeight(node.getOrderNum()) + ); + } + + /** + * 校验流程分类是否有数据权限 + * + * @param categoryId 流程分类ID + */ + @Override + public void checkCategoryDataScope(Long categoryId) { + if (ObjectUtil.isNull(categoryId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (baseMapper.countCategoryById(categoryId) == 0) { + throw new ServiceException("没有权限访问流程分类数据!"); + } + } + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + @Override + public boolean checkCategoryNameUnique(FlowCategoryBo category) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowCategory::getCategoryName, category.getCategoryName()) + .eq(FlowCategory::getParentId, category.getParentId()) + .ne(ObjectUtil.isNotNull(category.getCategoryId()), FlowCategory::getCategoryId, category.getCategoryId())); + return !exist; + } + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkCategoryExistDefinition(Long categoryId) { + FlowDefinition definition = new FlowDefinition(); + definition.setCategory(categoryId.toString()); + return defService.exists(definition); + } + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + @Override + public boolean hasChildByCategoryId(Long categoryId) { + return baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowCategory::getParentId, categoryId)); + } + + private LambdaQueryWrapper buildQueryWrapper(FlowCategoryBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(FlowCategory::getDelFlag, SystemConstants.NORMAL); + lqw.eq(ObjectUtil.isNotNull(bo.getCategoryId()), FlowCategory::getCategoryId, bo.getCategoryId()); + lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), FlowCategory::getParentId, bo.getParentId()); + lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), FlowCategory::getCategoryName, bo.getCategoryName()); + lqw.orderByAsc(FlowCategory::getAncestors); + lqw.orderByAsc(FlowCategory::getParentId); + lqw.orderByAsc(FlowCategory::getOrderNum); + lqw.orderByAsc(FlowCategory::getCategoryId); + return lqw; + } + + /** + * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 + */ + @Override + public int insertByBo(FlowCategoryBo bo) { + FlowCategory info = baseMapper.selectById(bo.getParentId()); + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId()); + return baseMapper.insert(category); + } + + /** + * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 + */ + @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId") + @Override + public int updateByBo(FlowCategoryBo bo) { + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId()); + if (ObjectUtil.isNull(oldCategory)) { + throw new ServiceException("流程分类不存在,无法修改"); + } + if (!oldCategory.getParentId().equals(category.getParentId())) { + // 如果是新父流程分类 则校验是否具有新父流程分类权限 避免越权 + this.checkCategoryDataScope(category.getParentId()); + FlowCategory newParentCategory = baseMapper.selectById(category.getParentId()); + if (ObjectUtil.isNotNull(newParentCategory)) { + String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId(); + String oldAncestors = oldCategory.getAncestors(); + category.setAncestors(newAncestors); + updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors); + } + } else { + category.setAncestors(oldCategory.getAncestors()); + } + return baseMapper.updateById(category); + } + + /** + * 修改子元素关系 + * + * @param categoryId 被修改的流程分类ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + private void updateCategoryChildren(Long categoryId, String newAncestors, String oldAncestors) { + List children = baseMapper.selectList(new LambdaQueryWrapper() + .apply(DataBaseHelper.findInSet(categoryId, "ancestors"))); + List list = new ArrayList<>(); + for (FlowCategory child : children) { + FlowCategory category = new FlowCategory(); + category.setCategoryId(child.getCategoryId()); + category.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + list.add(category); + } + if (CollUtil.isNotEmpty(list)) { + baseMapper.updateBatchById(list); + } + } + + /** + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 + */ + @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId") + @Override + public int deleteWithValidById(Long categoryId) { + return baseMapper.deleteById(categoryId); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwChartExtServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwChartExtServiceImpl.java new file mode 100644 index 0000000..d7c6f77 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwChartExtServiceImpl.java @@ -0,0 +1,247 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.service.DeptService; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.core.dto.DefJson; +import org.dromara.warm.flow.core.dto.NodeJson; +import org.dromara.warm.flow.core.dto.PromptContent; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.utils.MapUtil; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.ui.service.ChartExtService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * 流程图提示信息 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwChartExtServiceImpl implements ChartExtService { + + private final UserService userService; + private final DeptService deptService; + private final FlowHisTaskMapper flowHisTaskMapper; + private final DictService dictService; + + /** + * 设置流程图提示信息 + * + * @param defJson 流程定义json对象 + */ + @Override + public void execute(DefJson defJson) { + // 临时修复 后续版本将通过defjson获取流程实例ID + String[] parts = ServletUtils.getRequest().getRequestURI().split("/"); + Long instanceId = Convert.toLong(parts[parts.length - 1]); + + // 根据流程实例ID查询所有相关的历史任务列表 + List flowHisTasks = this.getHisTaskGroupedByNode(instanceId); + if (CollUtil.isEmpty(flowHisTasks)) { + return; + } + + // 按节点编号(nodeCode)对历史任务进行分组 + Map> groupedByNode = StreamUtils.groupByKey(flowHisTasks, FlowHisTask::getNodeCode); + + // 批量查询所有审批人的用户信息 + List userDTOList = userService.selectListByIds(StreamUtils.toList(flowHisTasks, e -> Convert.toLong(e.getApprover()))); + + // 将查询到的用户列表转换为以用户ID为key的映射 + Map userMap = StreamUtils.toIdentityMap(userDTOList, UserDTO::getUserId); + + Map dictType = dictService.getAllDictByDictType(FlowConstant.WF_TASK_STATUS); + + // 遍历流程定义中的每个节点,调用处理方法,将对应节点的任务列表及用户信息传入,生成扩展提示内容 + for (NodeJson nodeJson : defJson.getNodeList()) { + // 获取当前节点对应的历史任务列表,如果没有则返回空列表避免空指针 + List taskList = groupedByNode.get(nodeJson.getNodeCode()); + if (CollUtil.isEmpty(taskList)) { + continue; + } + // 处理当前节点的扩展信息,包括构建审批人提示内容等 + this.processNodeExtInfo(nodeJson, taskList, userMap, dictType); + } + } + + /** + * 初始化流程图提示信息 + * + * @param defJson 流程定义json对象 + */ + @Override + public void initPromptContent(DefJson defJson) { + defJson.setTopText("流程名称: " + defJson.getFlowName()); + defJson.getNodeList().forEach(nodeJson -> { + nodeJson.setPromptContent( + new PromptContent() + // 提示信息 + .setInfo( + CollUtil.newArrayList( + new PromptContent.InfoItem() + .setPrefix("任务名称: ") + .setContent(nodeJson.getNodeName()) + .setContentStyle(Map.of( + "border", "1px solid #d1e9ff", + "backgroundColor", "#e8f4ff", + "padding", "4px 8px", + "borderRadius", "4px" + )) + .setRowStyle(Map.of( + "fontWeight", "bold", + "margin", "0 0 6px 0", + "padding", "0 0 8px 0", + "borderBottom", "1px solid #ccc" + )) + ) + ) + // 弹窗样式 + .setDialogStyle(MapUtil.mergeAll( + "position", "absolute", + "backgroundColor", "#fff", + "border", "1px solid #ccc", + "borderRadius", "4px", + "boxShadow", "0 2px 8px rgba(0, 0, 0, 0.15)", + "padding", "8px 12px", + "fontSize", "14px", + "zIndex", "1000", + "maxWidth", "500px", + "overflowY", "visible", + "overflowX", "hidden", + "color", "#333", + "pointerEvents", "auto", + "scrollbarWidth", "thin" + )) + ); + }); + } + + /** + * 处理节点的扩展信息,构建用于流程图悬浮提示的内容 + * + * @param nodeJson 当前节点对象 + * @param taskList 当前节点对应的历史审批任务列表 + */ + private void processNodeExtInfo(NodeJson nodeJson, List taskList, Map userMap, Map dictType) { + + // 获取节点提示内容对象中的 info 列表,用于追加提示项 + List info = nodeJson.getPromptContent().getInfo(); + + // 遍历所有任务记录,构建提示内容 + for (FlowHisTask task : taskList) { + UserDTO userDTO = userMap.get(Convert.toLong(task.getApprover())); + if (ObjectUtil.isEmpty(userDTO)) { + continue; + } + + // 查询用户所属部门名称 + String deptName = deptService.selectDeptNameByIds(Convert.toStr(userDTO.getDeptId())); + + // 添加标题项,如:👤 张三(市场部) + info.add(new PromptContent.InfoItem() + .setPrefix(StringUtils.format("👥 {}({})", userDTO.getNickName(), deptName)) + .setPrefixStyle(Map.of( + "fontWeight", "bold", + "fontSize", "15px", + "color", "#333" + )) + .setRowStyle(Map.of( + "margin", "8px 0", + "borderBottom", "1px dashed #ccc" + )) + ); + + // 添加具体信息项:账号、耗时、时间 + info.add(buildInfoItem("用户账号", userDTO.getUserName())); + info.add(buildInfoItem("审批状态", dictType.get(task.getFlowStatus()))); + info.add(buildInfoItem("审批耗时", DateUtils.getTimeDifference(task.getUpdateTime(), task.getCreateTime()))); + info.add(buildInfoItem("办理时间", DateUtils.formatDateTime(task.getUpdateTime()))); + } + } + + /** + * 构建单条提示内容对象 InfoItem,用于悬浮窗显示(key: value) + * + * @param key 字段名(作为前缀) + * @param value 字段值 + * @return 提示项对象 + */ + private PromptContent.InfoItem buildInfoItem(String key, String value) { + return new PromptContent.InfoItem() + // 前缀 + .setPrefix(key + ": ") + // 前缀样式 + .setPrefixStyle(Map.of( + "textAlign", "right", + "color", "#444", + "userSelect", "none", + "display", "inline-block", + "width", "100px", + "paddingRight", "8px", + "fontWeight", "500", + "fontSize", "14px", + "lineHeight", "24px", + "verticalAlign", "middle" + )) + // 内容 + .setContent(value) + // 内容样式 + .setContentStyle(Map.of( + "backgroundColor", "#f7faff", + "color", "#005cbf", + "padding", "4px 8px", + "fontSize", "14px", + "borderRadius", "4px", + "whiteSpace", "normal", + "border", "1px solid #d0e5ff", + "userSelect", "text", + "lineHeight", "20px" + )) + // 行样式 + .setRowStyle(Map.of( + "color", "#222", + "alignItems", "center", + "display", "flex", + "marginBottom", "6px", + "fontWeight", "400", + "fontSize", "14px" + )); + } + + /** + * 根据流程实例ID获取历史任务列表 + * + * @param instanceId 流程实例ID + * @return 历史任务列表 + */ + public List getHisTaskGroupedByNode(Long instanceId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(FlowHisTask::getInstanceId, instanceId) + .eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey()) + .orderByDesc(FlowHisTask::getCreateTime, FlowHisTask::getUpdateTime); + return flowHisTaskMapper.selectList(wrapper); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java new file mode 100644 index 0000000..e6dc815 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java @@ -0,0 +1,122 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mail.utils.MailUtils; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.service.NodeService; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.MessageTypeEnum; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + + +/** + * 工作流工具 + * + * @author LionLi + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwCommonServiceImpl implements IFlwCommonService { + private final NodeService nodeService; + + /** + * 构建工作流用户 + * + * @param permissionList 办理用户 + * @return 用户 + */ + @Override + public List buildUser(List permissionList) { + if (CollUtil.isEmpty(permissionList)) { + return List.of(); + } + IFlwTaskAssigneeService taskAssigneeService = SpringUtils.getBean(IFlwTaskAssigneeService.class); + String processedBys = CollUtil.join(permissionList, StringUtils.SEPARATOR); + // 根据 processedBy 前缀判断处理人类型,分别获取用户列表 + List users = taskAssigneeService.fetchUsersByStorageIds(processedBys); + + return StreamUtils.toList(users, userDTO -> String.valueOf(userDTO.getUserId())); + } + + + /** + * 发送消息 + * + * @param flowName 流程定义名称 + * @param messageType 消息类型 + * @param message 消息内容,为空则发送默认配置的消息内容 + */ + @Override + public void sendMessage(String flowName, Long instId, List messageType, String message) { + IFlwTaskService flwTaskService = SpringUtils.getBean(IFlwTaskService.class); + List userList = new ArrayList<>(); + List list = flwTaskService.selectByInstId(instId); + if (StringUtils.isBlank(message)) { + message = "有新的【" + flowName + "】单据已经提交至您,请您及时处理。"; + } + for (Task task : list) { + List users = flwTaskService.currentTaskAllUser(task.getId()); + if (CollUtil.isNotEmpty(users)) { + userList.addAll(users); + } + } + if (CollUtil.isNotEmpty(userList)) { + for (String code : messageType) { + MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code); + if (ObjectUtil.isNotEmpty(messageTypeEnum)) { + switch (messageTypeEnum) { + case SYSTEM_MESSAGE: + SseMessageDto dto = new SseMessageDto(); + dto.setUserIds(StreamUtils.toList(userList, UserDTO::getUserId).stream().distinct().collect(Collectors.toList())); + dto.setMessage(message); + SseMessageUtils.publishMessage(dto); + break; + case EMAIL_MESSAGE: + MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), "单据审批提醒", message); + break; + case SMS_MESSAGE: + //todo 短信发送 + break; + default: + throw new IllegalStateException("Unexpected value: " + messageTypeEnum); + } + } + } + } + } + + + /** + * 申请人节点编码 + * + * @param definitionId 流程定义id + * @return 申请人节点编码 + */ + @Override + public String applyNodeCode(Long definitionId) { + Node startNode = nodeService.getStartNode(definitionId); + Node nextNode = nodeService.getNextNode(definitionId, startNode.getNodeCode(), null, SkipType.PASS.getKey()); + return nextNode.getNodeCode(); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java new file mode 100644 index 0000000..10e753e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java @@ -0,0 +1,291 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.core.dto.DefJson; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.PublishStatus; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowSkip; +import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.warm.flow.orm.mapper.FlowSkipMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.FlwDefinitionSuffixTemplateEnum; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.bo.FlowDefinitionBo; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.dromara.common.core.constant.TenantConstants.DEFAULT_TENANT_ID; + +/** + * 流程定义 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwDefinitionServiceImpl implements IFlwDefinitionService { + + private final DefService defService; + private final FlowDefinitionMapper flowDefinitionMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowNodeMapper flowNodeMapper; + private final FlowSkipMapper flowSkipMapper; + private final FlwCategoryMapper flwCategoryMapper; + private final IFlwCommonService flwCommonService; + + /** + * 查询流程定义列表 + * + * @param flowDefinitionBo 流程定义信息 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + @Override + public TableDataInfo queryList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) { + LambdaQueryWrapper wrapper = buildQueryWrapper(flowDefinitionBo); + wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey()); + Page page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + List list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class); + return new TableDataInfo<>(list, page.getTotal()); + } + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinitionBo 流程定义信息 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + @Override + public TableDataInfo unPublishList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) { + LambdaQueryWrapper wrapper = buildQueryWrapper(flowDefinitionBo); + wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey())); + Page page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + List list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class); + return new TableDataInfo<>(list, page.getTotal()); + } + + private LambdaQueryWrapper buildQueryWrapper(FlowDefinitionBo flowDefinitionBo) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.like(StringUtils.isNotBlank(flowDefinitionBo.getFlowCode()), FlowDefinition::getFlowCode, flowDefinitionBo.getFlowCode()); + wrapper.like(StringUtils.isNotBlank(flowDefinitionBo.getFlowName()), FlowDefinition::getFlowName, flowDefinitionBo.getFlowName()); + if (StringUtils.isNotBlank(flowDefinitionBo.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinitionBo.getCategory())); + wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr)); + } + wrapper.likeRight(FlowDefinition::getFlowCode, flowDefinitionBo.getProjectId() + "_"); + wrapper.orderByDesc(FlowDefinition::getCreateTime); + return wrapper; + } + + /** + * 发布流程定义 + * + * @param id 流程定义id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean publish(Long id) { + List flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper().eq(FlowNode::getDefinitionId, id)); + List errorMsg = new ArrayList<>(); + if (CollUtil.isNotEmpty(flowNodes)) { + for (FlowNode flowNode : flowNodes) { + String applyNodeCode = flwCommonService.applyNodeCode(id); + if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) { + errorMsg.add(flowNode.getNodeName()); + } + } + if (CollUtil.isNotEmpty(errorMsg)) { + throw new ServiceException("节点【" + StringUtils.join(errorMsg, ",") + "】未配置办理人!"); + } + } + return defService.publish(id); + } + + /** + * 导入流程定义 + * + * @param file 文件 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean importJson(MultipartFile file, String category) { + try { + DefJson defJson = JsonUtils.parseObject(file.getBytes(), DefJson.class); + defJson.setCategory(category); + defService.importDef(defJson); + } catch (IOException e) { + log.error("读取文件流错误: {}", e.getMessage(), e); + throw new IllegalStateException("文件读取失败,请检查文件内容", e); + } + return true; + } + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + @Override + public void exportDef(Long id, HttpServletResponse response) throws IOException { + byte[] data = defService.exportJson(id).getBytes(StandardCharsets.UTF_8); + // 设置响应头和内容类型 + response.reset(); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setContentType("application/text"); + response.setHeader("Content-Disposition", "attachment;"); + response.addHeader("Content-Length", "" + data.length); + IoUtil.write(response.getOutputStream(), false, data); + } + + /** + * 删除流程定义 + * + * @param ids 流程定义id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeDef(List ids) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.in(FlowHisTask::getDefinitionId, ids); + List flowHisTasks = flowHisTaskMapper.selectList(wrapper); + if (CollUtil.isNotEmpty(flowHisTasks)) { + List flowDefinitions = flowDefinitionMapper.selectByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId)); + if (CollUtil.isNotEmpty(flowDefinitions)) { + String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode); + log.info("流程定义【{}】已被使用不可被删除!", join); + throw new ServiceException("流程定义【" + join + "】已被使用不可被删除!"); + } + } + try { + defService.removeDef(ids); + } catch (Exception e) { + log.error("Error removing flow definitions: {}", e.getMessage(), e); + throw new RuntimeException("Failed to remove flow definitions", e); + } + return true; + } + + /** + * 新增流程定义 + * + * @param projectId 项目id + */ + @Override + public void insertDefByProjectId(Long projectId) { + FlwDefinitionSuffixTemplateEnum[] suffixList = FlwDefinitionSuffixTemplateEnum.values(); + for (FlwDefinitionSuffixTemplateEnum suffix : suffixList) { + FlowDefinition definition = new FlowDefinition(); + definition.setCategory("100"); + definition.setFlowCode(projectId + suffix.getCode()); + definition.setFlowName(suffix.getName()); + definition.setFormPath(suffix.getPath()); + boolean result = defService.checkAndSave(definition); + if (!result) { + log.info("流程定义[{}-{}]失败!", suffix.getName(), projectId + suffix.getCode()); + } + } + } + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void syncDef(String tenantId) { + List flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID)); + if (CollUtil.isEmpty(flowDefinitions)) { + return; + } + FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper() + .eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID)); + flowCategory.setCategoryId(null); + flowCategory.setTenantId(tenantId); + flowCategory.setCreateBy(null); + flowCategory.setCreateTime(null); + flowCategory.setUpdateBy(null); + flowCategory.setUpdateTime(null); + flwCategoryMapper.insert(flowCategory); + List defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId); + List flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper().in(FlowNode::getDefinitionId, defIds)); + List flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper().in(FlowSkip::getDefinitionId, defIds)); + for (FlowDefinition definition : flowDefinitions) { + FlowDefinition flowDefinition = BeanUtil.toBean(definition, FlowDefinition.class); + flowDefinition.setId(null); + flowDefinition.setTenantId(tenantId); + flowDefinition.setIsPublish(0); + flowDefinition.setCategory(String.valueOf(flowCategory.getCategoryId())); + int insert = flowDefinitionMapper.insert(flowDefinition); + if (insert <= 0) { + log.info("同步流程定义【{}】失败!", definition.getFlowCode()); + continue; + } + log.info("同步流程定义【{}】成功!", definition.getFlowCode()); + Long definitionId = flowDefinition.getId(); + if (CollUtil.isNotEmpty(flowNodes)) { + List nodes = StreamUtils.filter(flowNodes, node -> node.getDefinitionId().equals(definition.getId())); + if (CollUtil.isNotEmpty(nodes)) { + List flowNodeList = BeanUtil.copyToList(nodes, FlowNode.class); + flowNodeList.forEach(e -> { + e.setId(null); + e.setDefinitionId(definitionId); + e.setTenantId(tenantId); + e.setPermissionFlag(null); + }); + flowNodeMapper.insertOrUpdate(flowNodeList); + } + } + if (CollUtil.isNotEmpty(flowSkips)) { + List skips = StreamUtils.filter(flowSkips, skip -> skip.getDefinitionId().equals(definition.getId())); + if (CollUtil.isNotEmpty(skips)) { + List flowSkipList = BeanUtil.copyToList(skips, FlowSkip.class); + flowSkipList.forEach(e -> { + e.setId(null); + e.setDefinitionId(definitionId); + e.setTenantId(tenantId); + }); + flowSkipMapper.insertOrUpdate(flowSkipList); + } + } + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java new file mode 100644 index 0000000..a3e272f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java @@ -0,0 +1,430 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.constant.ExceptionCons; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; +import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.mapper.FlwInstanceMapper; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程实例 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwInstanceServiceImpl implements IFlwInstanceService { + + private final InsService insService; + private final DefService defService; + private final TaskService taskService; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowInstanceMapper flowInstanceMapper; + private final FlowProcessEventHandler flowProcessEventHandler; + private final IFlwTaskService flwTaskService; + private final FlwInstanceMapper flwInstanceMapper; + private final FlwCategoryMapper flwCategoryMapper; + + /** + * 分页查询正在运行的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowInstanceBo); + queryWrapper.in("fi.flow_status", BusinessStatusEnum.runningStatus()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 分页查询已结束的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowInstanceBo); + queryWrapper.in("fi.flow_status", BusinessStatusEnum.finishStatus()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 根据业务id查询流程实例详细信息 + * + * @param businessId 业务id + * @return 结果 + */ + @Override + public FlowInstanceVo queryByBusinessId(Long businessId) { + FlowInstance instance = this.selectInstByBusinessId(String.valueOf(businessId)); + FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class); + Definition definition = defService.getById(instanceVo.getDefinitionId()); + instanceVo.setFlowName(definition.getFlowName()); + instanceVo.setFlowCode(definition.getFlowCode()); + instanceVo.setVersion(definition.getVersion()); + instanceVo.setFormCustom(definition.getFormCustom()); + instanceVo.setFormPath(definition.getFormPath()); + instanceVo.setCategory(definition.getCategory()); + return instanceVo; + } + + /** + * 通用查询条件 + * + * @param flowInstanceBo 查询条件 + * @return 查询条件构造方法 + */ + private QueryWrapper buildQueryWrapper(FlowInstanceBo flowInstanceBo) { + QueryWrapper queryWrapper = Wrappers.query(); + queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getNodeName()), "fi.node_name", flowInstanceBo.getNodeName()); + queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowName()), "fd.flow_name", flowInstanceBo.getFlowName()); + queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowCode()), "fd.flow_code", flowInstanceBo.getFlowCode()); + if (StringUtils.isNotBlank(flowInstanceBo.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowInstanceBo.getCategory())); + queryWrapper.in("fd.category", StreamUtils.toList(categoryIds, Convert::toStr)); + } + queryWrapper.eq(StringUtils.isNotBlank(flowInstanceBo.getBusinessId()), "fi.business_id", flowInstanceBo.getBusinessId()); + queryWrapper.in(CollUtil.isNotEmpty(flowInstanceBo.getCreateByIds()), "fi.create_by", flowInstanceBo.getCreateByIds()); + queryWrapper.eq("fi.del_flag", "0"); + queryWrapper.orderByDesc("fi.create_time"); + return queryWrapper; + } + + /** + * 根据业务id查询流程实例 + * + * @param businessId 业务id + */ + @Override + public FlowInstance selectInstByBusinessId(String businessId) { + return flowInstanceMapper.selectOne(new LambdaQueryWrapper().eq(FlowInstance::getBusinessId, businessId)); + } + + /** + * 按照实例id查询流程实例 + * + * @param instanceId 实例id + */ + @Override + public FlowInstance selectInstById(Long instanceId) { + return flowInstanceMapper.selectById(instanceId); + } + + /** + * 按照实例id查询流程实例 + * + * @param instanceIds 实例id + */ + @Override + public List selectInstListByIdList(List instanceIds) { + return flowInstanceMapper.selectByIds(instanceIds); + } + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByBusinessIds(List businessIds) { + List flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper().in(FlowInstance::getBusinessId, StreamUtils.toList(businessIds, Convert::toStr))); + if (CollUtil.isEmpty(flowInstances)) { + log.warn("未找到对应的流程实例信息,无法执行删除操作。"); + return false; + } + return insService.remove(StreamUtils.toList(flowInstances, FlowInstance::getId)); + } + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByInstanceIds(List instanceIds) { + // 获取实例信息 + List instances = insService.getByIds(instanceIds); + if (CollUtil.isEmpty(instances)) { + log.warn("未找到对应的流程实例信息,无法执行删除操作。"); + return false; + } + // 获取定义信息 + Map definitionMap = defService.getByIds( + StreamUtils.toList(instances, Instance::getDefinitionId) + ).stream().collect(Collectors.toMap(Definition::getId, definition -> definition)); + + // 逐一触发删除事件 + instances.forEach(instance -> { + Definition definition = definitionMap.get(instance.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); + return; + } + flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); + }); + + // 删除实例 + return insService.remove(instanceIds); + } + + /** + * 撤销流程 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelProcessApply(FlowCancelBo bo) { + try { + Instance instance = selectInstByBusinessId(bo.getBusinessId()); + if (instance == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Definition definition = defService.getById(instance.getDefinitionId()); + if (definition == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); + } + String message = bo.getMessage(); + String userIdStr = LoginHelper.getUserIdStr(); + BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus()); + FlowParams flowParams = FlowParams.build() + .message(message) + .flowStatus(BusinessStatusEnum.CANCEL.getStatus()) + .hisStatus(BusinessStatusEnum.CANCEL.getStatus()) + .handler(userIdStr) + .ignore(true); + taskService.revoke(instance.getId(), flowParams); + } catch (Exception e) { + log.error("撤销失败: {}", e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + return true; + } + + /** + * 获取当前登陆人发起的流程实例 + * + * @param instanceBo 流程实例 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(instanceBo); + queryWrapper.eq("fi.create_by", LoginHelper.getUserIdStr()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 获取流程图,流程记录 + * + * @param businessId 业务id + */ + @Override + public Map flowHisTaskList(String businessId) { + FlowInstance flowInstance = this.selectInstByBusinessId(businessId); + if (ObjectUtil.isNull(flowInstance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Long instanceId = flowInstance.getId(); + //运行中的任务 + List list = new ArrayList<>(); + List flowTaskList = flwTaskService.selectByInstId(instanceId); + if (CollUtil.isNotEmpty(flowTaskList)) { + List flowHisTaskVos = BeanUtil.copyToList(flowTaskList, FlowHisTaskVo.class); + for (FlowHisTaskVo flowHisTaskVo : flowHisTaskVos) { + flowHisTaskVo.setFlowStatus(TaskStatusEnum.WAITING.getStatus()); + flowHisTaskVo.setUpdateTime(null); + flowHisTaskVo.setRunDuration(null); + List allUser = flwTaskService.currentTaskAllUser(flowHisTaskVo.getId()); + if (CollUtil.isNotEmpty(allUser)) { + String join = StreamUtils.join(allUser, e -> String.valueOf(e.getUserId())); + flowHisTaskVo.setApprover(join); + } + if (BusinessStatusEnum.isDraftOrCancelOrBack(flowInstance.getFlowStatus())) { + flowHisTaskVo.setApprover(LoginHelper.getUserIdStr()); + flowHisTaskVo.setApproveName(LoginHelper.getLoginUser().getNickname()); + } + } + list.addAll(flowHisTaskVos); + } + //历史任务 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(FlowHisTask::getInstanceId, instanceId) + .eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey()) + .orderByDesc(FlowHisTask::getCreateTime, FlowHisTask::getUpdateTime); + List flowHisTasks = flowHisTaskMapper.selectList(wrapper); + if (CollUtil.isNotEmpty(flowHisTasks)) { + list.addAll(BeanUtil.copyToList(flowHisTasks, FlowHisTaskVo.class)); + } + return Map.of("list", list, "instanceId", instanceId); + } + + /** + * 按照实例id更新状态 + * + * @param instanceId 实例id + * @param status 状态 + */ + @Override + public void updateStatus(Long instanceId, String status) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.set(FlowInstance::getFlowStatus, status); + wrapper.eq(FlowInstance::getId, instanceId); + flowInstanceMapper.update(wrapper); + } + + /** + * 获取流程变量 + * + * @param instanceId 实例id + */ + @Override + public Map instanceVariable(Long instanceId) { + FlowInstance flowInstance = flowInstanceMapper.selectById(instanceId); + Map variableMap = Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap()); + List> variableList = variableMap.entrySet().stream() + .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) + .toList(); + return Map.of("variableList", variableList, "variable", flowInstance.getVariable()); + } + + /** + * 设置流程变量 + * + * @param instanceId 实例id + * @param variable 流程变量 + */ + @Override + public void setVariable(Long instanceId, Map variable) { + Instance instance = insService.getById(instanceId); + if (instance != null) { + taskService.mergeVariable(instance, variable); + insService.updateById(instance); + } + } + + /** + * 按任务id查询实例 + * + * @param taskId 任务id + */ + @Override + public FlowInstance selectByTaskId(Long taskId) { + Task task = taskService.getById(taskId); + if (task == null) { + FlowHisTask flowHisTask = flwTaskService.selectHisTaskById(taskId); + if (flowHisTask != null) { + return this.selectInstById(flowHisTask.getInstanceId()); + } + } else { + return this.selectInstById(task.getInstanceId()); + } + return null; + } + + /** + * 按任务id查询实例 + * + * @param taskIdList 任务id + */ + @Override + public List selectByTaskIdList(List taskIdList) { + if (CollUtil.isEmpty(taskIdList)) { + return Collections.emptyList(); + } + Set instanceIds = new HashSet<>(); + List flowTaskList = flwTaskService.selectByIdList(taskIdList); + for (FlowTask flowTask : flowTaskList) { + instanceIds.add(flowTask.getInstanceId()); + } + List flowHisTaskList = flwTaskService.selectHisTaskByIdList(taskIdList); + for (FlowHisTask flowHisTask : flowHisTaskList) { + instanceIds.add(flowHisTask.getInstanceId()); + } + if (!instanceIds.isEmpty()) { + return this.selectInstListByIdList(new ArrayList<>(instanceIds)); + } + return Collections.emptyList(); + } + + /** + * 作废流程 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean processInvalid(FlowInvalidBo bo) { + try { + Instance instance = insService.getById(bo.getId()); + if (instance != null) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + FlowParams flowParams = FlowParams.build() + .message(bo.getComment()) + .flowStatus(BusinessStatusEnum.INVALID.getStatus()) + .hisStatus(TaskStatusEnum.INVALID.getStatus()) + .ignore(true); + taskService.terminationByInsId(bo.getId(), flowParams); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java new file mode 100644 index 0000000..fca21a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java @@ -0,0 +1,243 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.DictTypeDTO; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.warm.flow.ui.service.NodeExtService; +import org.dromara.warm.flow.ui.vo.NodeExt; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.ButtonPermissionEnum; +import org.dromara.workflow.common.enums.NodeExtEnum; +import org.dromara.workflow.domain.vo.ButtonPermissionVo; +import org.dromara.workflow.service.IFlwNodeExtService; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 流程设计器-节点扩展属性 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService { + + /** + * 存储不同 dictType 对应的配置信息 + */ + private static final Map CHILD_NODE_MAP = new HashMap<>(); + + record ButtonPermission(String label, Integer type, Boolean must, Boolean multiple) { + } + + static { + CHILD_NODE_MAP.put(ButtonPermissionEnum.class.getSimpleName(), + new ButtonPermission("权限按钮", 4, false, true)); + } + + private final DictService dictService; + + /** + * 获取节点扩展属性 + * + * @return 节点扩展属性列表 + */ + @Override + public List getNodeExt() { + List nodeExtList = new ArrayList<>(); + // 构建按钮权限页面 + nodeExtList.add(buildNodeExt("wf_button_tab", "权限", 2, + List.of(ButtonPermissionEnum.class))); + // 自定义构建 规则参考 NodeExt 与 warm-flow文档说明 + // nodeExtList.add(buildNodeExt("xxx_xxx", "xxx", 1, List); + return nodeExtList; + } + + /** + * 构建一个 `NodeExt` 对象 + * + * @param code 唯一编码 + * @param name 名称(新页签时,作为页签名称) + * @param type 节点类型(1: 基础设置,2: 新页签) + * @param sources 数据来源(枚举类或字典类型) + * @return 构建的 `NodeExt` 对象 + */ + @SuppressWarnings("unchecked cast") + private NodeExt buildNodeExt(String code, String name, int type, List sources) { + NodeExt nodeExt = new NodeExt(); + nodeExt.setCode(code); + nodeExt.setType(type); + nodeExt.setName(name); + nodeExt.setChilds(sources.stream() + .map(source -> { + if (source instanceof Class clazz && NodeExtEnum.class.isAssignableFrom(clazz)) { + return buildChildNode((Class) clazz); + } else if (source instanceof String dictType) { + return buildChildNode(dictType); + } + return null; + }) + .filter(ObjectUtil::isNotNull) + .toList() + ); + return nodeExt; + } + + /** + * 根据枚举类型构建一个 `ChildNode` 对象 + * + * @param enumClass 枚举类,必须实现 `NodeExtEnum` 接口 + * @return 构建的 `ChildNode` 对象 + */ + private NodeExt.ChildNode buildChildNode(Class enumClass) { + if (!enumClass.isEnum()) { + return null; + } + String simpleName = enumClass.getSimpleName(); + NodeExt.ChildNode childNode = buildChildNodeMap(simpleName); + // 编码,此json中唯 + childNode.setCode(simpleName); + // 字典,下拉框和复选框时用到 + childNode.setDict(Arrays.stream(enumClass.getEnumConstants()) + .map(NodeExtEnum.class::cast) + .map(x -> + new NodeExt.DictItem(x.getLabel(), x.getValue(), x.isSelected()) + ).toList()); + return childNode; + } + + /** + * 根据字典类型构建 `ChildNode` 对象 + * + * @param dictType 字典类型 + * @return 构建的 `ChildNode` 对象 + */ + private NodeExt.ChildNode buildChildNode(String dictType) { + DictTypeDTO dictTypeDTO = dictService.getDictType(dictType); + if (ObjectUtil.isNull(dictTypeDTO)) { + return null; + } + NodeExt.ChildNode childNode = buildChildNodeMap(dictType); + // 编码,此json中唯一 + childNode.setCode(dictType); + // label名称 + childNode.setLabel(dictTypeDTO.getDictName()); + // 描述 + childNode.setDesc(dictTypeDTO.getRemark()); + // 字典,下拉框和复选框时用到 + childNode.setDict(dictService.getDictData(dictType) + .stream().map(x -> + new NodeExt.DictItem(x.getDictLabel(), x.getDictValue(), Convert.toBool(x.getIsDefault(), false)) + ).toList()); + return childNode; + } + + /** + * 根据 CHILD_NODE_MAP 中的配置信息,构建一个基本的 ChildNode 对象 + * 该方法用于设置 ChildNode 的常规属性,例如 label、type、是否必填、是否多选等 + * + * @param key CHILD_NODE_MAP 的 key + * @return 返回构建好的 ChildNode 对象 + */ + private NodeExt.ChildNode buildChildNodeMap(String key) { + NodeExt.ChildNode childNode = new NodeExt.ChildNode(); + ButtonPermission bp = CHILD_NODE_MAP.get(key); + if (bp == null) { + childNode.setType(1); + childNode.setMust(false); + childNode.setMultiple(true); + return childNode; + } + // label名称 + childNode.setLabel(bp.label()); + // 1:输入框 2:输入框 3:下拉框 4:选择框 + childNode.setType(bp.type()); + // 是否必填 + childNode.setMust(bp.must()); + // 是否多选 + childNode.setMultiple(bp.multiple()); + return childNode; + } + + /** + * 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选 + * + * @param ext 扩展属性 JSON 字符串 + * @return 按钮权限 VO 列表 + */ + @Override + public List buildButtonPermissionsFromExt(String ext) { + // 解析 ext 为 Map>,用于标记权限 + Map> permissionMap = JsonUtils.parseArray(ext, ButtonPermissionVo.class) + .stream() + .collect(Collectors.toMap( + ButtonPermissionVo::getCode, + item -> StringUtils.splitList(item.getValue()).stream() + .map(String::trim) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toSet()), + (a, b) -> b, + HashMap::new + )); + + // 构建按钮权限列表,标记哪些按钮在 permissionMap 中出现(表示已勾选) + return buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class)); + } + + /** + * 将权限映射与按钮权限来源(枚举类或字典类型)进行匹配,生成权限视图列表 + *

+ * 使用说明: + * - sources 支持传入多个来源类型,支持 NodeExtEnum 枚举类 或 字典类型字符串(dictType) + * - 若需要扩展更多按钮权限,只需在 sources 中新增对应的枚举类或字典类型 + *

+ * 示例: + * buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class, "custom_button_dict")); + * + * @param permissionMap 权限映射 + * @param sources 枚举类或字典类型列表 + * @return 按钮权限视图对象列表 + */ + @SuppressWarnings("unchecked cast") + private List buildPermissionsFromSources(Map> permissionMap, List sources) { + return sources.stream() + .flatMap(source -> { + if (source instanceof Class clazz && NodeExtEnum.class.isAssignableFrom(clazz)) { + Set selectedSet = permissionMap.getOrDefault(clazz.getSimpleName(), Collections.emptySet()); + return extractDictItems(this.buildChildNode((Class) clazz), selectedSet).stream(); + } else if (source instanceof String dictType) { + Set selectedSet = permissionMap.getOrDefault(dictType, Collections.emptySet()); + return extractDictItems(this.buildChildNode(dictType), selectedSet).stream(); + } + return Stream.empty(); + }).toList(); + } + + /** + * 从节点子项中提取字典项,并构建按钮权限视图对象列表 + * + * @param childNode 子节点 + * @param selectedSet 已选中的值集 + * @return 按钮权限视图对象列表 + */ + private List extractDictItems(NodeExt.ChildNode childNode, Set selectedSet) { + return Optional.ofNullable(childNode) + .map(NodeExt.ChildNode::getDict) + .orElse(List.of()) + .stream() + .map(dict -> new ButtonPermissionVo(dict.getValue(), selectedSet.contains(dict.getValue()))) + .toList(); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java new file mode 100644 index 0000000..ceefa80 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java @@ -0,0 +1,254 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Pair; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.DeptDTO; +import org.dromara.common.core.domain.dto.TaskAssigneeDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.domain.model.TaskAssigneeBody; +import org.dromara.common.core.enums.FormatsType; +import org.dromara.common.core.service.DeptService; +import org.dromara.common.core.service.TaskAssigneeService; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.ui.dto.HandlerFunDto; +import org.dromara.warm.flow.ui.dto.HandlerQuery; +import org.dromara.warm.flow.ui.dto.TreeFunDto; +import org.dromara.warm.flow.ui.service.HandlerSelectService; +import org.dromara.warm.flow.ui.vo.HandlerFeedBackVo; +import org.dromara.warm.flow.ui.vo.HandlerSelectVo; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskAssigneeEnum; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 流程设计器-获取办理人权限设置列表 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, HandlerSelectService { + + private static final String DEFAULT_GROUP_NAME = "默认分组"; + private final TaskAssigneeService taskAssigneeService; + private final UserService userService; + private final DeptService deptService; + + /** + * 获取办理人权限设置列表tabs页签 + * + * @return tabs页签 + */ + @Override + public List getHandlerType() { + return TaskAssigneeEnum.getAssigneeTypeList(); + } + + /** + * 获取办理列表, 同时构建左侧部门树状结构 + * + * @param query 查询条件 + * @return HandlerSelectVo + */ + @Override + public HandlerSelectVo getHandlerSelect(HandlerQuery query) { + // 获取任务办理类型 + TaskAssigneeEnum type = TaskAssigneeEnum.fromDesc(query.getHandlerType()); + // 转换查询条件为 TaskAssigneeBody + TaskAssigneeBody taskQuery = BeanUtil.toBean(query, TaskAssigneeBody.class); + + // 统一查询并构建业务数据 + TaskAssigneeDTO dto = fetchTaskAssigneeData(type, taskQuery); + List depts = fetchDeptData(type); + + return getHandlerSelectVo(buildHandlerData(dto, type), buildDeptTree(depts)); + } + + /** + * 办理人权限名称回显 + * + * @param storageIds 入库主键集合 + * @return 结果 + */ + @Override + public List handlerFeedback(List storageIds) { + if (CollUtil.isEmpty(storageIds)) { + return Collections.emptyList(); + } + // 解析并归类 ID,同时记录原始顺序和对应解析结果 + Map> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class); + Map> parsedMap = new LinkedHashMap<>(); + for (String storageId : storageIds) { + Pair parsed = this.parseStorageId(storageId); + parsedMap.put(storageId, parsed); + if (parsed != null) { + typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue()); + } + } + + // 查询所有类型对应的 ID 名称映射 + Map> nameMap = new EnumMap<>(TaskAssigneeEnum.class); + typeIdMap.forEach((type, ids) -> nameMap.put(type, this.getNamesByType(type, ids))); + + // 组装返回结果,保持原始顺序 + return parsedMap.entrySet().stream() + .map(entry -> { + String storageId = entry.getKey(); + Pair parsed = entry.getValue(); + String handlerName = (parsed == null) ? null + : nameMap.getOrDefault(parsed.getKey(), Collections.emptyMap()) + .get(parsed.getValue()); + return new HandlerFeedBackVo(storageId, handlerName); + }).toList(); + } + + /** + * 根据任务办理类型查询对应的数据 + */ + private TaskAssigneeDTO fetchTaskAssigneeData(TaskAssigneeEnum type, TaskAssigneeBody taskQuery) { + return switch (type) { + case USER -> taskAssigneeService.selectUsersByTaskAssigneeList(taskQuery); + case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery); + case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery); + case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery); + }; + } + + /** + * 根据任务办理类型获取部门数据 + */ + private List fetchDeptData(TaskAssigneeEnum type) { + if (type == TaskAssigneeEnum.USER || type == TaskAssigneeEnum.DEPT || type == TaskAssigneeEnum.POST) { + return deptService.selectDeptsByList(); + } + return new ArrayList<>(); + } + + /** + * 构建部门树状结构 + */ + private TreeFunDto buildDeptTree(List depts) { + return new TreeFunDto<>(depts) + .setId(dept -> String.valueOf(dept.getDeptId())) + .setName(DeptDTO::getDeptName) + .setParentId(dept -> String.valueOf(dept.getParentId())); + } + + /** + * 构建任务办理人数据 + */ + private HandlerFunDto buildHandlerData(TaskAssigneeDTO dto, TaskAssigneeEnum type) { + return new HandlerFunDto<>(dto.getList(), dto.getTotal()) + .setStorageId(assignee -> type.getCode() + assignee.getStorageId()) + .setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "无")) + .setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "无")) + .setGroupName(assignee -> StringUtils.defaultIfBlank( + Optional.ofNullable(assignee.getGroupName()) + .map(deptService::selectDeptNameByIds) + .orElse(DEFAULT_GROUP_NAME), DEFAULT_GROUP_NAME)) + .setCreateTime(assignee -> DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, assignee.getCreateTime())); + } + + /** + * 批量解析多个存储标识符(storageIds),按类型分类并合并查询用户列表 + * 输入格式支持多个以逗号分隔的标识(如 "user:123,role:456,789") + * 会自动去重返回结果,非法格式的标识将被忽略 + * + * @param storageIds 多个存储标识符字符串(逗号分隔) + * @return 合并后的用户列表,去重后返回,非法格式的标识将被跳过 + */ + @Override + public List fetchUsersByStorageIds(String storageIds) { + if (StringUtils.isEmpty(storageIds)) { + return List.of(); + } + Map> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class); + for (String storageId : storageIds.split(StringUtils.SEPARATOR)) { + Pair parsed = this.parseStorageId(storageId); + if (parsed != null) { + typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue()); + } + } + return typeIdMap.entrySet().stream() + .flatMap(entry -> this.getUsersByType(entry.getKey(), entry.getValue()).stream()) + .distinct() + .toList(); + } + + /** + * 根据指定的任务分配类型(TaskAssigneeEnum)和 ID 列表,获取对应的用户信息列表 + * + * @param type 任务分配类型,表示用户、角色、部门或其他(TaskAssigneeEnum 枚举值) + * @param ids 与指定分配类型关联的 ID 列表(例如用户ID、角色ID、部门ID等) + * @return 返回包含用户信息的列表。如果类型为用户(USER),则通过用户ID列表查询; + * 如果类型为角色(ROLE),则通过角色ID列表查询; + * 如果类型为部门(DEPT),则通过部门ID列表查询; + * 如果类型为岗位(POST)或无法识别的类型,则返回空列表 + */ + private List getUsersByType(TaskAssigneeEnum type, List ids) { + return switch (type) { + case USER -> userService.selectListByIds(ids); + case ROLE -> userService.selectUsersByRoleIds(ids); + case DEPT -> userService.selectUsersByDeptIds(ids); + case POST -> userService.selectUsersByPostIds(ids); + }; + } + + /** + * 根据任务分配类型和对应 ID 列表,批量查询名称映射关系 + * + * @param type 分配类型(用户、角色、部门、岗位) + * @param ids ID 列表(如用户ID、角色ID等) + * @return 返回 Map,其中 key 为 ID,value 为对应的名称 + */ + private Map getNamesByType(TaskAssigneeEnum type, List ids) { + return switch (type) { + case USER -> userService.selectUserNamesByIds(ids); + case ROLE -> userService.selectRoleNamesByIds(ids); + case DEPT -> userService.selectDeptNamesByIds(ids); + case POST -> userService.selectPostNamesByIds(ids); + }; + } + + /** + * 解析 storageId 字符串,返回类型和ID的组合 + * + * @param storageId 例如 "user:123" 或 "456" + * @return Pair(TaskAssigneeEnum, Long),如果格式非法返回 null + */ + private Pair parseStorageId(String storageId) { + if (StringUtils.isBlank(storageId)) { + return null; + } + // 跳过以 $ 或 # 开头的字符串 + if (StringUtils.startsWith(storageId, "$") || StringUtils.startsWith(storageId, "#")) { + log.debug("跳过 storageId 解析,检测到内置变量表达式:{}", storageId); + return null; + } + try { + String[] parts = storageId.split(StrUtil.COLON, 2); + if (parts.length < 2) { + return Pair.of(TaskAssigneeEnum.USER, Convert.toLong(parts[0])); + } else { + TaskAssigneeEnum type = TaskAssigneeEnum.fromCode(parts[0] + StrUtil.COLON); + return Pair.of(type, Convert.toLong(parts[1])); + } + } catch (Exception e) { + log.warn("解析 storageId 失败,格式非法:{},错误信息:{}", storageId, e.getMessage()); + return null; + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java new file mode 100644 index 0000000..f96a757 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -0,0 +1,755 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.*; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.service.*; +import org.dromara.warm.flow.core.utils.ExpressionUtil; +import org.dromara.warm.flow.core.utils.MapUtil; +import org.dromara.warm.flow.orm.entity.*; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.TaskAssigneeType; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.mapper.FlwTaskMapper; +import org.dromara.workflow.service.IFlwCommonService; +import org.dromara.workflow.service.IFlwNodeExtService; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 任务 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwTaskServiceImpl implements IFlwTaskService { + + private final TaskService taskService; + private final InsService insService; + private final DefService defService; + private final HisTaskService hisTaskService; + private final NodeService nodeService; + private final FlowInstanceMapper flowInstanceMapper; + private final FlowTaskMapper flowTaskMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final IdentifierGenerator identifierGenerator; + private final UserService userService; + private final FlwTaskMapper flwTaskMapper; + private final FlwCategoryMapper flwCategoryMapper; + private final FlowNodeMapper flowNodeMapper; + private final IFlwTaskAssigneeService flwTaskAssigneeService; + private final IFlwCommonService flwCommonService; + private final IFlwNodeExtService flwNodeExtService; + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) { + String businessId = startProcessBo.getBusinessId(); + if (StringUtils.isBlank(businessId)) { + throw new ServiceException("启动工作流时必须包含业务ID"); + } + // 启动流程实例(提交申请) + Map variables = startProcessBo.getVariables(); + // 流程发起人 + variables.put(INITIATOR, LoginHelper.getUserIdStr()); + // 业务id + variables.put(BUSINESS_ID, businessId); + FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class) + .eq(FlowInstance::getBusinessId, businessId)); + if (ObjectUtil.isNotNull(flowInstance)) { + BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus()); + List taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId())); + taskService.mergeVariable(flowInstance, variables); + insService.updateById(flowInstance); + StartProcessReturnDTO dto = new StartProcessReturnDTO(); + dto.setProcessInstanceId(taskList.get(0).getInstanceId()); + dto.setTaskId(taskList.get(0).getId()); + return dto; + } + FlowParams flowParams = FlowParams.build() + .flowCode(startProcessBo.getFlowCode()) + .variable(startProcessBo.getVariables()) + .flowStatus(BusinessStatusEnum.DRAFT.getStatus()); + Instance instance; + try { + instance = insService.start(businessId, flowParams); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + // 申请人执行流程 + List taskList = taskService.list(new FlowTask().setInstanceId(instance.getId())); + if (taskList.size() > 1) { + throw new ServiceException("请检查流程第一个环节是否为申请人!"); + } + StartProcessReturnDTO dto = new StartProcessReturnDTO(); + dto.setProcessInstanceId(instance.getId()); + dto.setTaskId(taskList.get(0).getId()); + return dto; + } + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean completeTask(CompleteTaskBo completeTaskBo) { + try { + // 获取任务ID并查询对应的流程任务和实例信息 + Long taskId = completeTaskBo.getTaskId(); + List messageType = completeTaskBo.getMessageType(); + String notice = completeTaskBo.getNotice(); + // 获取抄送人 + List flowCopyList = completeTaskBo.getFlowCopyList(); + // 设置抄送人 + completeTaskBo.getVariables().put(FlowConstant.FLOW_COPY_LIST, flowCopyList); + // 消息类型 + completeTaskBo.getVariables().put(FlowConstant.MESSAGE_TYPE, messageType); + // 消息通知 + completeTaskBo.getVariables().put(FlowConstant.MESSAGE_NOTICE, notice); + + + FlowTask flowTask = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(flowTask)) { + throw new ServiceException("流程任务不存在或任务已审批!"); + } + Instance ins = insService.getById(flowTask.getInstanceId()); + // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 + if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { + completeTaskBo.getVariables().put(FlowConstant.SUBMIT, true); + } + // 设置弹窗处理人 + Map assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap()); + if (CollUtil.isNotEmpty(assigneeMap)) { + completeTaskBo.getVariables().putAll(assigneeMap); + } + // 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息 + FlowParams flowParams = FlowParams.build() + .variable(completeTaskBo.getVariables()) + .skipType(SkipType.PASS.getKey()) + .message(completeTaskBo.getMessage()) + .flowStatus(BusinessStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.PASS.getStatus()) + .hisTaskExt(completeTaskBo.getFileId()); + // 执行任务跳转,并根据返回的处理人设置下一步处理人 + taskService.skip(taskId, flowParams); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 设置弹窗处理人 + * + * @param assigneeMap 处理人 + * @param variablesMap 变量 + */ + private Map setPopAssigneeMap(Map assigneeMap, Map variablesMap) { + Map map = new HashMap<>(); + if (CollUtil.isEmpty(assigneeMap)) { + return map; + } + for (Map.Entry entry : assigneeMap.entrySet()) { + if (variablesMap.containsKey(entry.getKey())) { + String userIds = variablesMap.get(entry.getKey()).toString(); + if (StringUtils.isNotBlank(userIds)) { + Set hashSet = new HashSet<>(); + //弹窗传入的选人 + List popUserIds = Arrays.asList(entry.getValue().toString().split(StringUtils.SEPARATOR)); + //已有的选人 + List variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR)); + hashSet.addAll(popUserIds); + hashSet.addAll(variableUserIds); + map.put(entry.getKey(), String.join(StringUtils.SEPARATOR, hashSet)); + } + } else { + map.put(entry.getKey(), entry.getValue()); + } + } + return map; + } + + /** + * 添加抄送人 + * + * @param task 任务信息 + * @param flowCopyList 抄送人 + */ + @Override + public void setCopy(Task task, List flowCopyList) { + if (CollUtil.isEmpty(flowCopyList)) { + return; + } + // 添加抄送人记录 + FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0); + FlowNode flowNode = new FlowNode(); + flowNode.setNodeCode(flowHisTask.getTargetNodeCode()); + flowNode.setNodeName(flowHisTask.getTargetNodeName()); + //生成新的任务id + long taskId = identifierGenerator.nextId(null).longValue(); + task.setId(taskId); + task.setNodeName("【抄送】" + task.getNodeName()); + Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000); + FlowParams flowParams = FlowParams.build() + .skipType(SkipType.NONE.getKey()) + .hisStatus(TaskStatusEnum.COPY.getStatus()) + .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName)); + HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams); + hisTask.setCreateTime(updateTime); + hisTask.setUpdateTime(updateTime); + hisTaskService.save(hisTask); + List userList = flowCopyList.stream() + .map(flowCopy -> { + FlowUser flowUser = new FlowUser(); + flowUser.setType(TaskAssigneeType.COPY.getCode()); + flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId())); + flowUser.setAssociated(taskId); + return flowUser; + }).collect(Collectors.toList()); + // 批量保存抄送人员 + FlowEngine.userService().saveBatch(userList); + } + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr()); + queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus()); + Page page = this.getFlowTaskVoPage(pageQuery, queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 查询当前用户的已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + queryWrapper.in("t.approver", LoginHelper.getUserIdStr()); + queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time"); + Page page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + Page page = getFlowTaskVoPage(pageQuery, queryWrapper); + return TableDataInfo.build(page); + } + + private Page getFlowTaskVoPage(PageQuery pageQuery, QueryWrapper queryWrapper) { + Page page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper); + List records = page.getRecords(); + if (CollUtil.isNotEmpty(records)) { + List taskIds = StreamUtils.toList(records, FlowTaskVo::getId); + Map> listMap = currentTaskAllUser(taskIds); + records.forEach(t -> { + List userList = listMap.getOrDefault(t.getId(), Collections.emptyList()); + if (CollUtil.isNotEmpty(userList)) { + t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId()))); + t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName)); + } + }); + } + return page; + } + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + Page page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr()); + Page page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + private QueryWrapper buildQueryWrapper(FlowTaskBo flowTaskBo) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getNodeName()), "t.node_name", flowTaskBo.getNodeName()); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowName()), "t.flow_name", flowTaskBo.getFlowName()); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode()); + wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds()); + if (StringUtils.isNotBlank(flowTaskBo.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory())); + wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr)); + } + wrapper.orderByDesc("t.create_time"); + return wrapper; + } + + /** + * 驳回任务 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean backProcess(BackProcessBo bo) { + try { + Long taskId = bo.getTaskId(); + String notice = bo.getNotice(); + List messageType = bo.getMessageType(); + String message = bo.getMessage(); + FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } + Instance inst = insService.getById(task.getInstanceId()); + BusinessStatusEnum.checkBackStatus(inst.getFlowStatus()); + Long definitionId = task.getDefinitionId(); + String applyNodeCode = flwCommonService.applyNodeCode(definitionId); + + Map variable = new HashMap<>(); + // 消息类型 + variable.put("messageType", messageType); + // 消息通知 + variable.put("notice", notice); + + FlowParams flowParams = FlowParams.build() + .nodeCode(bo.getNodeCode()) + .variable(variable) + .message(message) + .skipType(SkipType.REJECT.getKey()) + .flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.BACK.getStatus()) + .hisTaskExt(bo.getFileId()); + taskService.skip(task.getId(), flowParams); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 获取可驳回的前置节点 + * + * @param definitionId 流程定义id + * @param nowNodeCode 当前节点 + */ + @Override + public List getBackTaskNode(Long definitionId, String nowNodeCode) { + List nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId); + if (!CollUtil.isNotEmpty(nodeCodes)) { + return nodeCodes; + } + //判断是否配置了固定驳回节点 + Node node = nodeCodes.get(0); + if (StringUtils.isNotBlank(node.getAnyNodeSkip())) { + return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId); + } + //获取可驳回的前置节点 + List nodes = nodeService.previousNodeList(definitionId, nowNodeCode); + if (CollUtil.isNotEmpty(nodes)) { + return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType())); + } + return nodes; + } + + /** + * 终止任务 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean terminationTask(FlowTerminationBo bo) { + try { + Long taskId = bo.getTaskId(); + Task task = taskService.getById(taskId); + if (task == null) { + throw new ServiceException("任务不存在!"); + } + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNotNull(instance)) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + FlowParams flowParams = FlowParams.build() + .message(bo.getComment()) + .flowStatus(BusinessStatusEnum.TERMINATION.getStatus()) + .hisStatus(TaskStatusEnum.TERMINATION.getStatus()); + taskService.termination(taskId, flowParams); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + */ + @Override + public List selectByIdList(List taskIdList) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .in(FlowTask::getId, taskIdList)); + } + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + */ + @Override + public FlowTaskVo selectById(Long taskId) { + Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + return null; + } + FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class); + Instance instance = insService.getById(task.getInstanceId()); + Definition definition = defService.getById(task.getDefinitionId()); + flowTaskVo.setFlowStatus(instance.getFlowStatus()); + flowTaskVo.setVersion(definition.getVersion()); + flowTaskVo.setFlowCode(definition.getFlowCode()); + flowTaskVo.setFlowName(definition.getFlowName()); + flowTaskVo.setBusinessId(instance.getBusinessId()); + FlowNode flowNode = this.getByNodeCode(flowTaskVo.getNodeCode(), instance.getDefinitionId()); + if (ObjectUtil.isNull(flowNode)) { + throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在"); + } + //设置按钮权限 + flowTaskVo.setButtonList(flwNodeExtService.buildButtonPermissionsFromExt(flowNode.getExt())); + flowTaskVo.setNodeRatio(flowNode.getNodeRatio()); + flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId()))); + return flowTaskVo; + } + + /** + * 获取下一节点信息 + * + * @param bo 参数 + */ + @Override + public List getNextNodeList(FlowNextNodeBo bo) { + Long taskId = bo.getTaskId(); + Map variables = bo.getVariables(); + Task task = taskService.getById(taskId); + Instance instance = insService.getById(task.getInstanceId()); + Definition definition = defService.getById(task.getDefinitionId()); + Map mergeVariable = MapUtil.mergeAll(instance.getVariableMap(), variables); + // 获取下一节点列表 + List nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null, SkipType.PASS.getKey(), mergeVariable); + List nextFlowNodes = BeanUtil.copyToList(nextNodeList, FlowNode.class); + // 只获取中间节点 + nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType())); + if (CollUtil.isNotEmpty(nextNodeList)) { + // 构建以下节点数据 + List buildNextTaskList = StreamUtils.toList(nextNodeList, node -> taskService.addTask(node, instance, definition, FlowParams.build())); + // 办理人变量替换 + ExpressionUtil.evalVariable(buildNextTaskList, + FlowParams.build() + .variable(mergeVariable) + ); + for (FlowNode flowNode : nextFlowNodes) { + buildNextTaskList.stream().filter(t -> t.getNodeCode().equals(flowNode.getNodeCode())).findFirst().ifPresent(t -> { + if (CollUtil.isNotEmpty(t.getPermissionList())) { + List users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList())); + if (CollUtil.isNotEmpty(users)) { + flowNode.setPermissionFlag(StreamUtils.join(users, e -> String.valueOf(e.getUserId()))); + } + } + }); + } + } + return nextFlowNodes; + } + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 结果 + */ + @Override + public List selectHisTaskByIdList(List taskIdList) { + return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class) + .in(FlowHisTask::getId, taskIdList)); + } + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 结果 + */ + @Override + public FlowHisTask selectHisTaskById(Long taskId) { + return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class) + .eq(FlowHisTask::getId, taskId)); + } + + /** + * 按照实例id查询任务 + * + * @param instanceIdList 流程实例id + */ + @Override + public List selectByInstIdList(List instanceIdList) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .in(FlowTask::getInstanceId, instanceIdList)); + } + + /** + * 按照实例id查询任务 + * + * @param instanceId 流程实例id + */ + @Override + public List selectByInstId(Long instanceId) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .eq(FlowTask::getInstanceId, instanceId)); + } + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean taskOperation(TaskOperationBo bo, String taskOperation) { + FlowParams flowParams = FlowParams.build() + .message(bo.getMessage()); + if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { + flowParams.ignore(true); + } + + // 根据操作类型构建 FlowParams + switch (taskOperation) { + case DELEGATE_TASK, TRANSFER_TASK -> { + ValidatorUtils.validate(bo, AddGroup.class); + flowParams.addHandlers(Collections.singletonList(bo.getUserId())); + } + case ADD_SIGNATURE -> { + ValidatorUtils.validate(bo, EditGroup.class); + flowParams.addHandlers(bo.getUserIds()); + } + case REDUCTION_SIGNATURE -> { + ValidatorUtils.validate(bo, EditGroup.class); + flowParams.reductionHandlers(bo.getUserIds()); + } + default -> { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + } + + Long taskId = bo.getTaskId(); + Task task = taskService.getById(taskId); + FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId()); + if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) { + if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) { + throw new ServiceException(task.getNodeName() + "不是会签节点!"); + } + } + // 设置任务状态并执行对应的任务操作 + switch (taskOperation) { + //委派任务 + case DELEGATE_TASK -> { + flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus()); + return taskService.depute(taskId, flowParams); + } + //转办任务 + case TRANSFER_TASK -> { + flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus()); + return taskService.transfer(taskId, flowParams); + } + //加签,增加办理人 + case ADD_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus()); + return taskService.addSignature(taskId, flowParams); + } + //减签,减少办理人 + case REDUCTION_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); + return taskService.reductionSignature(taskId, flowParams); + } + default -> { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + } + } + + /** + * 修改任务办理人(此方法将会批量修改所有任务的办理人) + * + * @param taskIdList 任务id + * @param userId 用户id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateAssignee(List taskIdList, String userId) { + if (CollUtil.isEmpty(taskIdList)) { + return false; + } + try { + List flowTasks = this.selectByIdList(taskIdList); + // 批量删除现有任务的办理人记录 + if (CollUtil.isNotEmpty(flowTasks)) { + FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); + List userList = flowTasks.stream() + .map(flowTask -> { + FlowUser flowUser = new FlowUser(); + flowUser.setType(TaskAssigneeType.APPROVER.getCode()); + flowUser.setProcessedBy(userId); + flowUser.setAssociated(flowTask.getId()); + return flowUser; + }) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(userList)) { + FlowEngine.userService().saveBatch(userList); + } + } + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + return true; + } + + /** + * 获取任务所有办理人 + * + * @param taskIdList 任务id + */ + @Override + public Map> currentTaskAllUser(List taskIdList) { + Map> map = new HashMap<>(); + // 获取与当前任务关联的用户列表 + List associatedUsers = FlowEngine.userService().getByAssociateds(taskIdList); + Map> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated); + for (Map.Entry> entry : listMap.entrySet()) { + List value = entry.getValue(); + if (CollUtil.isNotEmpty(value)) { + List userDtoList = userService.selectListByIds(StreamUtils.toList(value, e -> Convert.toLong(e.getProcessedBy()))); + map.put(entry.getKey(), userDtoList); + } + } + return map; + } + + /** + * 获取当前任务的所有办理人 + * + * @param taskId 任务id + */ + @Override + public List currentTaskAllUser(Long taskId) { + // 获取与当前任务关联的用户列表 + List userList = FlowEngine.userService().getByAssociateds(Collections.singletonList(taskId)); + if (CollUtil.isEmpty(userList)) { + return Collections.emptyList(); + } + return userService.selectListByIds(StreamUtils.toList(userList, e -> Convert.toLong(e.getProcessedBy()))); + } + + /** + * 按照节点编码查询节点 + * + * @param nodeCode 节点编码 + * @param definitionId 流程定义id + */ + @Override + public FlowNode getByNodeCode(String nodeCode, Long definitionId) { + return flowNodeMapper.selectOne(new LambdaQueryWrapper() + .eq(FlowNode::getNodeCode, nodeCode) + .eq(FlowNode::getDefinitionId, definitionId)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java new file mode 100644 index 0000000..17d1c7c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java @@ -0,0 +1,198 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.mapper.TestLeaveMapper; +import org.dromara.workflow.service.ITestLeaveService; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +/** + * 请假Service业务层处理 + * + * @author may + * @date 2023-07-21 + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +@Slf4j +public class TestLeaveServiceImpl implements ITestLeaveService { + + private final TestLeaveMapper baseMapper; + private final WorkflowService workflowService; + + /** + * spel条件表达:判断小于2 + * + * @param leaveDays 待判断的变量(可不传自行返回true或false) + * @return boolean + */ + public boolean eval(Integer leaveDays) { + if (leaveDays <= 2) { + return true; + } + return false; + } + + /** + * 查询请假 + */ + @Override + public TestLeaveVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 查询请假列表 + */ + @Override + public TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询请假列表 + */ + @Override + public List queryList(TestLeaveBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TestLeaveBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), TestLeave::getLeaveType, bo.getLeaveType()); + lqw.ge(bo.getStartLeaveDays() != null, TestLeave::getLeaveDays, bo.getStartLeaveDays()); + lqw.le(bo.getEndLeaveDays() != null, TestLeave::getLeaveDays, bo.getEndLeaveDays()); + lqw.orderByDesc(BaseEntity::getCreateTime); + return lqw; + } + + /** + * 新增请假 + */ + @Override + public TestLeaveVo insertByBo(TestLeaveBo bo) { + long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true); + // 截止日期也算一天 + bo.setLeaveDays((int) day + 1); + TestLeave add = MapstructUtils.convert(bo, TestLeave.class); + if (StringUtils.isBlank(add.getStatus())) { + add.setStatus(BusinessStatusEnum.DRAFT.getStatus()); + } + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return MapstructUtils.convert(add, TestLeaveVo.class); + } + + /** + * 修改请假 + */ + @Override + public TestLeaveVo updateByBo(TestLeaveBo bo) { + TestLeave update = MapstructUtils.convert(bo, TestLeave.class); + baseMapper.updateById(update); + return MapstructUtils.convert(update, TestLeaveVo.class); + } + + /** + * 批量删除请假 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(List ids) { + workflowService.deleteInstance(ids); + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.startsWith('leave')") + public void processHandler(ProcessEvent processEvent) { + log.info("当前任务执行了{}", processEvent.toString()); + TestLeave testLeave = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId())); + testLeave.setStatus(processEvent.getStatus()); + // 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程 + Map params = processEvent.getParams(); + if (MapUtil.isNotEmpty(params)) { + // 历史任务扩展(通常为附件) + String hisTaskExt = Convert.toStr(params.get("hisTaskExt")); + // 办理人 + String handler = Convert.toStr(params.get("handler")); + // 办理意见 + String message = Convert.toStr(params.get("message")); + } + if (processEvent.getSubmit()) { + testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); + } + baseMapper.updateById(testLeave); + } + + /** + * 执行任务创建监听 + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("当前任务创建了{}", processTaskEvent.toString()); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @EventListener(condition = "#processDeleteEvent.flowCode.startsWith('leave')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString()); + TestLeave testLeave = baseMapper.selectById(Convert.toLong(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(testLeave)) { + return; + } + baseMapper.deleteById(testLeave.getId()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java new file mode 100644 index 0000000..0c02240 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java @@ -0,0 +1,151 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.dto.CompleteTaskDTO; +import org.dromara.common.core.domain.dto.StartProcessDTO; +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; +import org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.CompleteTaskBo; +import org.dromara.workflow.domain.bo.StartProcessBo; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * 通用 工作流服务实现 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +public class WorkflowServiceImpl implements WorkflowService { + + private final IFlwInstanceService flwInstanceService; + private final IFlwDefinitionService flwDefinitionService; + private final IFlwTaskService flwTaskService; + + /** + * 删除流程实例 + * + * @param businessIds 业务id + * @return 结果 + */ + @Override + public boolean deleteInstance(List businessIds) { + return flwInstanceService.deleteByBusinessIds(businessIds); + } + + /** + * 获取当前流程状态 + * + * @param taskId 任务id + */ + @Override + public String getBusinessStatusByTaskId(Long taskId) { + FlowInstance flowInstance = flwInstanceService.selectByTaskId(taskId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY; + } + + /** + * 获取当前流程状态 + * + * @param businessId 业务id + */ + @Override + public String getBusinessStatus(String businessId) { + FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY; + } + + /** + * 设置流程变量 + * + * @param instanceId 流程实例id + * @param variables 流程变量 + */ + @Override + public void setVariable(Long instanceId, Map variables) { + flwInstanceService.setVariable(instanceId, variables); + } + + /** + * 获取流程变量 + * + * @param instanceId 流程实例id + */ + @Override + public Map instanceVariable(Long instanceId) { + return flwInstanceService.instanceVariable(instanceId); + } + + /** + * 按照业务id查询流程实例id + * + * @param businessId 业务id + * @return 结果 + */ + @Override + public Long getInstanceIdByBusinessId(String businessId) { + FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getId() : null; + } + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + @Override + public void syncDef(String tenantId) { + flwDefinitionService.syncDef(tenantId); + } + + /** + * 启动流程 + * + * @param startProcess 参数 + */ + @Override + public StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess) { + return flwTaskService.startWorkFlow(BeanUtil.toBean(startProcess, StartProcessBo.class)); + } + + /** + * 办理任务 + * 系统后台发起审批 无用户信息 需要忽略权限 + * completeTask.getVariables().put("ignore", true); + * + * @param completeTask 参数 + */ + @Override + public boolean completeTask(CompleteTaskDTO completeTask) { + return flwTaskService.completeTask(BeanUtil.toBean(completeTask, CompleteTaskBo.class)); + } + + /** + * 办理任务 + * + * @param taskId 任务ID + * @param message 办理意见 + */ + @Override + public boolean completeTask(Long taskId, String message) { + CompleteTaskBo completeTask = new CompleteTaskBo(); + completeTask.setTaskId(taskId); + completeTask.setMessage(message); + // 忽略权限(系统后台发起审批 无用户信息 需要忽略权限) + completeTask.getVariables().put("ignore", true); + return flwTaskService.completeTask(completeTask); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml new file mode 100644 index 0000000..10c948d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml new file mode 100644 index 0000000..30e2267 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml new file mode 100644 index 0000000..f539030 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml new file mode 100644 index 0000000..d52f6b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/script/bin/ry.bat b/script/bin/ry.bat new file mode 100644 index 0000000..ea98cbe --- /dev/null +++ b/script/bin/ry.bat @@ -0,0 +1,68 @@ +rem 使用者应根据自身平台编码自行转换 防止乱码 例如 win使用gbk编码 +@echo off + +rem jar平级目录 +set AppName=ruoyi-admin.jar + +rem JVM参数 +set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC" + + +ECHO. + ECHO. [1] 启动%AppName% + ECHO. [2] 关闭%AppName% + ECHO. [3] 重启%AppName% + ECHO. [4] 启动状态 %AppName% + ECHO. [5] 退 出 +ECHO. + +ECHO.请输入选择项目的序号: +set /p ID= + IF "%id%"=="1" GOTO start + IF "%id%"=="2" GOTO stop + IF "%id%"=="3" GOTO restart + IF "%id%"=="4" GOTO status + IF "%id%"=="5" EXIT +PAUSE +:start + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if defined pid ( + echo %%is running + PAUSE + ) + +start javaw %JVM_OPTS% -jar %AppName% + +echo starting…… +echo Start %AppName% success... +goto:eof + +rem 函数stop通过jps命令查找pid并结束进程 +:stop + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% does not exists) else ( + echo prepare to kill %image_name% + echo start kill %pid% ... + rem 根据进程ID,kill进程 + taskkill /f /pid %pid% + ) +goto:eof +:restart + call :stop + call :start +goto:eof +:status + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% is dead ) else ( + echo %image_name% is running + ) +goto:eof diff --git a/script/bin/ry.sh b/script/bin/ry.sh new file mode 100644 index 0000000..a6f5d9c --- /dev/null +++ b/script/bin/ry.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# ./ry.sh start 启动 stop 停止 restart 重启 status 状态 +AppName=ruoyi-admin.jar + +# JVM参数 +JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC" +APP_HOME=`pwd` +LOG_PATH=$APP_HOME/logs/$AppName.log + +if [ "$1" = "" ]; +then + echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m" + exit 1 +fi + +if [ "$AppName" = "" ]; +then + echo -e "\033[0;31m 未输入应用名 \033[0m" + exit 1 +fi + +function start() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + + if [ x"$PID" != x"" ]; then + echo "$AppName is running..." + else + nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 & + echo "Start $AppName success..." + fi +} + +function stop() +{ + echo "Stop $AppName" + + PID="" + query(){ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + } + + query + if [ x"$PID" != x"" ]; then + kill -TERM $PID + echo "$AppName (pid:$PID) exiting..." + while [ x"$PID" != x"" ] + do + sleep 1 + query + done + echo "$AppName exited." + else + echo "$AppName already stopped." + fi +} + +function restart() +{ + stop + sleep 2 + start +} + +function status() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l` + if [ $PID != 0 ];then + echo "$AppName is running..." + else + echo "$AppName is not running..." + fi +} + +case $1 in + start) + start;; + stop) + stop;; + restart) + restart;; + status) + status;; + *) + +esac diff --git a/script/docker/database.yml b/script/docker/database.yml new file mode 100644 index 0000000..6034b39 --- /dev/null +++ b/script/docker/database.yml @@ -0,0 +1,59 @@ +services: + # 此镜像仅用于测试 正式环境需自行安装数据库 + # SID: XE user: system password: oracle + oracle: + image: tekintian/oracle12c:latest + container_name: oracle + environment: + # 时区上海 + TZ: Asia/Shanghai + DBCA_TOTAL_MEMORY: 16192 + ports: + - "18080:8080" + - "1521:1521" + volumes: + # 数据挂载 + - "/docker/oracle/data:/u01/app/oracle" + network_mode: "host" + + # 此镜像仅用于测试 正式环境需自行安装数据库 + sqlserver: + image: mcr.microsoft.com/mssql/server:2017-latest + container_name: sqlserver + environment: + # 时区上海 + TZ: Asia/Shanghai + ACCEPT_EULA: "Y" + SA_PASSWORD: "Ruoyi@123" + ports: + - "1433:1433" + volumes: + # 数据挂载 + - "/docker/sqlserver/data:/var/opt/mssql" + network_mode: "host" + + postgres: + image: postgres:14.2 + container_name: postgres + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5432:5432" + volumes: + - /docker/postgres/data:/var/lib/postgresql/data + network_mode: "host" + + postgres13: + image: postgres:13.6 + container_name: postgres13 + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5433:5432" + volumes: + - /docker/postgres13/data:/var/lib/postgresql/data + network_mode: "host" diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml new file mode 100644 index 0000000..885c236 --- /dev/null +++ b/script/docker/docker-compose.yml @@ -0,0 +1,154 @@ +services: + mysql: + image: mysql:8.0.33 + container_name: mysql + environment: + # 时区上海 + TZ: Asia/Shanghai + # root 密码 + MYSQL_ROOT_PASSWORD: root + # 初始化数据库(后续的初始化sql会在这个库执行) + MYSQL_DATABASE: ry-vue + ports: + - "3306:3306" + volumes: + # 数据挂载 + - /docker/mysql/data/:/var/lib/mysql/ + # 配置挂载 + - /docker/mysql/conf/:/etc/mysql/conf.d/ + command: + # 将mysql8.0默认密码策略 修改为 原先 策略 (mysql8.0对其默认策略做了更改 会导致密码无法匹配) + --default-authentication-plugin=mysql_native_password + --character-set-server=utf8mb4 + --collation-server=utf8mb4_general_ci + --explicit_defaults_for_timestamp=true + --lower_case_table_names=1 + privileged: true + network_mode: "host" + + nginx-web: + image: nginx:1.23.4 + container_name: nginx-web + environment: + # 时区上海 + TZ: Asia/Shanghai + ports: + - "80:80" + - "443:443" + volumes: + # 证书映射 + - /docker/nginx/cert:/etc/nginx/cert + # 配置文件映射 + - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf + # 页面目录 + - /docker/nginx/html:/usr/share/nginx/html + # 日志目录 + - /docker/nginx/log:/var/log/nginx + privileged: true + network_mode: "host" + + redis: + image: redis:6.2.12 + container_name: redis + ports: + - "6379:6379" + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/redis/conf:/redis/config:rw + # 数据文件 + - /docker/redis/data/:/redis/data/:rw + command: "redis-server /redis/config/redis.conf" + privileged: true + network_mode: "host" + + minio: + image: minio/minio:RELEASE.2023-04-13T03-08-07Z + container_name: minio + ports: + # api 端口 + - "9000:9000" + # 控制台端口 + - "9001:9001" + environment: + # 时区上海 + TZ: Asia/Shanghai + # 管理后台用户名 + MINIO_ROOT_USER: ruoyi + # 管理后台密码,最小8个字符 + MINIO_ROOT_PASSWORD: ruoyi123 + # https需要指定域名 + #MINIO_SERVER_URL: "https://xxx.com:9000" + #MINIO_BROWSER_REDIRECT_URL: "https://xxx.com:9001" + # 开启压缩 on 开启 off 关闭 + MINIO_COMPRESS: "off" + # 扩展名 .pdf,.doc 为空 所有类型均压缩 + MINIO_COMPRESS_EXTENSIONS: "" + # mime 类型 application/pdf 为空 所有类型均压缩 + MINIO_COMPRESS_MIME_TYPES: "" + volumes: + # 映射当前目录下的data目录至容器内/data目录 + - /docker/minio/data:/data + # 映射配置目录 + - /docker/minio/config:/root/.minio/ + command: server --address ':9000' --console-address ':9001' /data # 指定容器中的目录 /data + privileged: true + network_mode: "host" + + ruoyi-server1: + image: ruoyi/ruoyi-server:5.3.0 + container_name: ruoyi-server1 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8080 + volumes: + # 配置文件 + - /docker/server1/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + ruoyi-server2: + image: ruoyi/ruoyi-server:5.3.0 + container_name: ruoyi-server2 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8081 + volumes: + # 配置文件 + - /docker/server2/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + ruoyi-monitor-admin: + image: ruoyi/ruoyi-monitor-admin:5.3.0 + container_name: ruoyi-monitor-admin + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/monitor/logs/:/ruoyi/monitor/logs + privileged: true + network_mode: "host" + + ruoyi-snailjob-server: + image: ruoyi/ruoyi-snailjob-server:5.3.0 + container_name: ruoyi-snailjob-server + environment: + # 时区上海 + TZ: Asia/Shanghai + ports: + - "8800:8800" + - "17888:17888" + volumes: + - /docker/snailjob/logs/:/ruoyi/snailjob/logs + privileged: true + network_mode: "host" diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf new file mode 100644 index 0000000..31fbe79 --- /dev/null +++ b/script/docker/nginx/conf/nginx.conf @@ -0,0 +1,114 @@ +worker_processes 1; + +error_log /mnt/disk1/docker/nginx/log/error.log warn; +pid /mnt/disk1/docker/nginx/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + # 限制body大小 + client_max_body_size 100m; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /mnt/disk1/docker/nginx/log/access.log main; + + upstream server { + ip_hash; + server 127.0.0.1:8899; + } + + upstream monitor-admin { + server 127.0.0.1:9090; + } + + upstream snailjob-server { + server 127.0.0.1:8800; + } + + server { + listen 80; + server_name localhost; + + # https配置参考 start + #listen 443 ssl; + + # 证书直接存放 /docker/nginx/cert/ 目录下即可 更改证书名称即可 无需更改证书路径 + #ssl on; + #ssl_certificate /etc/nginx/cert/xxx.local.crt; # /etc/nginx/cert/ 为docker映射路径 不允许更改 + #ssl_certificate_key /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 为docker映射路径 不允许更改 + #ssl_session_timeout 5m; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; + #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + #ssl_prefer_server_ciphers on; + # https配置参考 end + + # 演示环境配置 拦截除 GET POST 之外的所有请求 + # if ($request_method !~* GET|POST) { + # rewrite ^/(.*)$ /403; + # } + + # location = /403 { + # default_type application/json; + # return 200 '{"msg":"演示模式,不允许操作","code":500}'; + # } + + # 限制外网访问内网 actuator 相关路径 + location ~ ^(/[^/]*)?/actuator.*(/.*)?$ { + return 403; + } + + location / { + root /mnt/disk1/docker/nginx/html; # docker映射路径 不允许更改 + try_files $uri $uri/ /index.html; + index index.html index.htm; + } + + location /api/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 86400s; + # sse 与 websocket参数 + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_buffering off; + proxy_cache off; + proxy_pass http://server/; + } + + # https 会拦截内链所有的 http 请求 造成功能无法使用 + # 解决方案1 将 admin 服务 也配置成 https + # 解决方案2 将菜单配置为外链访问 走独立页面 http 访问 + location /admin/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://monitor-admin/admin/; + } + + location /snail-job/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://snailjob-server/snail-job/; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/script/docker/redis/conf/redis.conf b/script/docker/redis/conf/redis.conf new file mode 100644 index 0000000..72255c6 --- /dev/null +++ b/script/docker/redis/conf/redis.conf @@ -0,0 +1,28 @@ +# redis 密码 +requirepass ruoyi123 + +# key 监听器配置 +# notify-keyspace-events Ex + +# 配置持久化文件存储路径 +dir /redis/data +# 配置rdb +# 15分钟内有至少1个key被更改则进行快照 +save 900 1 +# 5分钟内有至少10个key被更改则进行快照 +save 300 10 +# 1分钟内有至少10000个key被更改则进行快照 +save 60 10000 +# 开启压缩 +rdbcompression yes +# rdb文件名 用默认的即可 +dbfilename dump.rdb + +# 开启aof +appendonly yes +# 文件名 +appendfilename "appendonly.aof" +# 持久化策略,no:不同步,everysec:每秒一次,always:总是同步,速度比较慢 +# appendfsync always +appendfsync everysec +# appendfsync no diff --git a/script/docker/redis/data/README.md b/script/docker/redis/data/README.md new file mode 100644 index 0000000..fbc5474 --- /dev/null +++ b/script/docker/redis/data/README.md @@ -0,0 +1 @@ +数据目录 请执行 `chmod 777 /docker/redis/data` 赋予读写权限 否则将无法写入数据 \ No newline at end of file diff --git a/script/leave/leave1.json b/script/leave/leave1.json new file mode 100644 index 0000000..0ffdeeb --- /dev/null +++ b/script/leave/leave1.json @@ -0,0 +1,75 @@ +{ + "flowCode" : "leave1", + "flowName" : "请假申请-普通", + "category" : "100", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "200,200|200,200", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac", + "nextNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42", + "skipType" : "PASS", + "coordinate" : "220,200;310,200" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "360,200|360,200", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42", + "nextNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf", + "skipType" : "PASS", + "coordinate" : "410,200;490,200" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf", + "nodeName" : "组长", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "540,200|540,200", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf", + "nextNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "skipType" : "PASS", + "coordinate" : "590,200;670,200" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "nodeName" : "部门主管", + "permissionFlag" : "role:3@@role:4", + "nodeRatio" : 0.000, + "coordinate" : "720,200|720,200", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "nextNodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d", + "skipType" : "PASS", + "coordinate" : "770,200;880,200" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "900,200|900,200", + "formCustom" : "N", + "ext" : "[]" + } ] +} diff --git a/script/leave/leave2.json b/script/leave/leave2.json new file mode 100644 index 0000000..7bbdbaa --- /dev/null +++ b/script/leave/leave2.json @@ -0,0 +1,111 @@ +{ + "flowCode" : "leave2", + "flowName" : "请假申请-排他网关", + "category" : "100", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "300,240|300,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a", + "nextNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd", + "skipType" : "PASS", + "coordinate" : "320,240;390,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "440,240|440,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd", + "nextNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "skipType" : "PASS", + "coordinate" : "490,240;535,240" + } ] + }, { + "nodeType" : 3, + "nodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nodeRatio" : 0.000, + "coordinate" : "560,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nextNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "skipType" : "PASS", + "skipCondition" : "le@@leaveDays|2", + "coordinate" : "560,265;560,320;670,320" + }, { + "nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nextNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605", + "skipName" : "大于两天", + "skipType" : "PASS", + "skipCondition" : "gt@@leaveDays|2", + "coordinate" : "560,215;560,160;670,160|560,187" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "nodeName" : "组长", + "permissionFlag" : "3@@4", + "nodeRatio" : 0.000, + "coordinate" : "720,320|720,320", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "skipType" : "PASS", + "coordinate" : "770,320;860,320;860,280" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "nodeName" : "总经理", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "860,240|860,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "nextNodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1", + "skipType" : "PASS", + "coordinate" : "910,240;980,240" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1000,240|1000,240", + "formCustom" : "N", + "ext" : "[]" + }, { + "nodeType" : 1, + "nodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605", + "nodeName" : "部门领导", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "720,160|720,160", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605", + "nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "skipType" : "PASS", + "coordinate" : "770,160;860,160;860,200" + } ] + } ] +} diff --git a/script/leave/leave3.json b/script/leave/leave3.json new file mode 100644 index 0000000..bb22d42 --- /dev/null +++ b/script/leave/leave3.json @@ -0,0 +1,121 @@ +{ + "flowCode" : "leave3", + "flowName" : "请假申请-并行网关", + "category" : "100", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "380,220|380,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957", + "nextNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99", + "skipType" : "PASS", + "coordinate" : "400,220;470,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "520,220|520,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99", + "nextNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "skipType" : "PASS", + "coordinate" : "570,220;655,220" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nodeRatio" : 0.000, + "coordinate" : "680,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nextNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "skipType" : "PASS", + "coordinate" : "680,195;680,140;750,140" + }, { + "nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nextNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394", + "skipType" : "PASS", + "coordinate" : "680,245;680,300;750,300" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "nodeName" : "市场部", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "800,140|800,140", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "skipType" : "PASS", + "coordinate" : "850,140;920,140;920,195" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "nodeRatio" : 0.000, + "coordinate" : "920,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "nextNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6", + "skipType" : "PASS", + "coordinate" : "945,220;975,220;975,220;960,220;960,220;990,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6", + "nodeName" : "CEO", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "1040,220|1040,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6", + "nextNodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1", + "skipType" : "PASS", + "coordinate" : "1090,220;1140,220" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1160,220|1160,220", + "formCustom" : "N", + "ext" : "[]" + }, { + "nodeType" : 1, + "nodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394", + "nodeName" : "综合部", + "permissionFlag" : "role:3@@role:4", + "nodeRatio" : 0.000, + "coordinate" : "800,300|800,300", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394", + "nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "skipType" : "PASS", + "coordinate" : "850,300;920,300;920,245" + } ] + } ] +} diff --git a/script/leave/leave4.json b/script/leave/leave4.json new file mode 100644 index 0000000..50968f8 --- /dev/null +++ b/script/leave/leave4.json @@ -0,0 +1,90 @@ +{ + "flowCode" : "leave4", + "flowName" : "请假申请-会签", + "category" : "100", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "320,240|320,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876", + "nextNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "skipType" : "PASS", + "coordinate" : "340,240;410,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "460,240|460,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "nextNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "skipType" : "PASS", + "coordinate" : "510,240;590,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "nodeName" : "百分之60通过", + "permissionFlag" : "${userList}", + "nodeRatio" : 60.000, + "coordinate" : "640,240|640,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "nextNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "skipType" : "PASS", + "coordinate" : "690,240;770,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "nodeName" : "全部审批通过", + "permissionFlag" : "role:1@@role:3", + "nodeRatio" : 100.000, + "coordinate" : "820,240|820,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "nextNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "skipType" : "PASS", + "coordinate" : "870,240;950,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "nodeName" : "CEO", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "1000,240|1000,240", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "nextNodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc", + "skipType" : "PASS", + "coordinate" : "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1120,240|1120,240", + "formCustom" : "N", + "ext" : "[]" + } ] +} diff --git a/script/leave/leave5.json b/script/leave/leave5.json new file mode 100644 index 0000000..a27b1de --- /dev/null +++ b/script/leave/leave5.json @@ -0,0 +1,121 @@ +{ + "flowCode" : "leave5", + "flowName" : "请假申请-并行会签网关", + "category" : "100", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "300,220|300,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c", + "nextNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374", + "skipType" : "PASS", + "coordinate" : "320,220;350,220;350,220;340,220;340,220;370,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "420,220|420,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374", + "nextNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "skipType" : "PASS", + "coordinate" : "470,220;535,220" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nodeRatio" : 0.000, + "coordinate" : "560,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nextNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "skipType" : "PASS", + "coordinate" : "560,245;560,320;650,320" + }, { + "nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nextNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "skipType" : "PASS", + "coordinate" : "560,195;560,120;650,120" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "nodeName" : "会签", + "permissionFlag" : "role:1@@role:3", + "nodeRatio" : 100.000, + "coordinate" : "700,320|700,320", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "skipType" : "PASS", + "coordinate" : "750,320;860,320;860,245" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "nodeRatio" : 0.000, + "coordinate" : "860,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "nextNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9", + "skipType" : "PASS", + "coordinate" : "885,220;950,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9", + "nodeName" : "CEO", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "1000,220|1000,220", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9", + "nextNodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169", + "skipType" : "PASS", + "coordinate" : "1050,220;1120,220" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1140,220|1140,220", + "formCustom" : "N", + "ext" : "[]" + }, { + "nodeType" : 1, + "nodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "nodeName" : "百分之60票签", + "permissionFlag" : "${userList}", + "nodeRatio" : 60.000, + "coordinate" : "700,120|700,120", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "skipType" : "PASS", + "coordinate" : "750,120;860,120;860,195" + } ] + } ] +} diff --git a/script/leave/leave6.json b/script/leave/leave6.json new file mode 100644 index 0000000..d21d9d2 --- /dev/null +++ b/script/leave/leave6.json @@ -0,0 +1,215 @@ +{ + "flowCode" : "leave6", + "flowName" : "请假申请-排他并行会签", + "category" : "100", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "122b89a5-7c6f-40a3-aa09-7a263f902054", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "240,300|240,300", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "122b89a5-7c6f-40a3-aa09-7a263f902054", + "nextNodeCode" : "c25a0e86-fdd1-4f03-8e22-14db70389dbd", + "skipType" : "PASS", + "coordinate" : "260,300;350,300" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "c25a0e86-fdd1-4f03-8e22-14db70389dbd", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "400,300|400,300", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "c25a0e86-fdd1-4f03-8e22-14db70389dbd", + "nextNodeCode" : "07ecda1d-7a0a-47b5-8a91-6186c9473742", + "skipType" : "PASS", + "coordinate" : "450,300;510,300" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "2bfa3919-78cf-4bc1-b59b-df463a4546f9", + "nodeName" : "副经理", + "permissionFlag" : "role:1@@role:3@@role:4", + "nodeRatio" : 0.000, + "coordinate" : "860,200|860,200", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "2bfa3919-78cf-4bc1-b59b-df463a4546f9", + "nextNodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "skipType" : "PASS", + "coordinate" : "910,200;1000,200;1000,275" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "ec17f60e-94e0-4d96-a3ce-3417e9d32d60", + "nodeName" : "组长", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "860,400|860,400", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "ec17f60e-94e0-4d96-a3ce-3417e9d32d60", + "nextNodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "skipType" : "PASS", + "coordinate" : "910,400;1000,400;1000,325" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "07ecda1d-7a0a-47b5-8a91-6186c9473742", + "nodeName" : "副组长", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "560,300|560,300", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,transfer,copy,pop\"}]", + "skipList" : [ { + "nowNodeCode" : "07ecda1d-7a0a-47b5-8a91-6186c9473742", + "nextNodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13", + "skipType" : "PASS", + "coordinate" : "610,300;675,300" + } ] + }, { + "nodeType" : 3, + "nodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13", + "nodeRatio" : 0.000, + "coordinate" : "700,300", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13", + "nextNodeCode" : "2bfa3919-78cf-4bc1-b59b-df463a4546f9", + "skipName" : "大于两天", + "skipType" : "PASS", + "skipCondition" : "default@@${leaveDays > 2}", + "coordinate" : "700,275;700,200;810,200|700,237" + }, { + "nowNodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13", + "nextNodeCode" : "ec17f60e-94e0-4d96-a3ce-3417e9d32d60", + "skipType" : "PASS", + "skipCondition" : "spel@@#{@testLeaveServiceImpl.eval(#leaveDays)}", + "coordinate" : "700,325;700,400;810,400" + } ] + }, { + "nodeType" : 3, + "nodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "nodeRatio" : 0.000, + "coordinate" : "1000,300", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32", + "nextNodeCode" : "9c93a195-cff2-4e17-ab0a-a4f264191496", + "skipType" : "PASS", + "coordinate" : "1025,300;1130,300" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "9c93a195-cff2-4e17-ab0a-a4f264191496", + "nodeName" : "经理会签", + "permissionFlag" : "1@@3", + "nodeRatio" : 100.000, + "coordinate" : "1180,300|1180,300", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,pop,addSign,subSign\"}]", + "skipList" : [ { + "nowNodeCode" : "9c93a195-cff2-4e17-ab0a-a4f264191496", + "nextNodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "skipType" : "PASS", + "coordinate" : "1230,300;1315,300" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "nodeRatio" : 0.000, + "coordinate" : "1340,300", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "nextNodeCode" : "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5", + "skipType" : "PASS", + "coordinate" : "1340,325;1340,400;1430,400" + }, { + "nowNodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992", + "nextNodeCode" : "350dfa0c-a77c-4efa-8527-10efa02d8be4", + "skipType" : "PASS", + "coordinate" : "1340,275;1340,200;1430,200" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "350dfa0c-a77c-4efa-8527-10efa02d8be4", + "nodeName" : "总经理", + "permissionFlag" : "3@@1", + "nodeRatio" : 0.000, + "coordinate" : "1480,200|1480,200", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "350dfa0c-a77c-4efa-8527-10efa02d8be4", + "nextNodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519", + "skipType" : "PASS", + "coordinate" : "1530,200;1640,200;1640,275" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5", + "nodeName" : "副总经理", + "permissionFlag" : "1@@3", + "nodeRatio" : 0.000, + "coordinate" : "1480,400|1480,400", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5", + "nextNodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519", + "skipType" : "PASS", + "coordinate" : "1530,400;1640,400;1640,325" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519", + "nodeRatio" : 0.000, + "coordinate" : "1640,300", + "formCustom" : "N", + "ext" : "[]", + "skipList" : [ { + "nowNodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519", + "nextNodeCode" : "3fcea762-b53a-4ae1-8365-7bec90444828", + "skipType" : "PASS", + "coordinate" : "1665,300;1770,300" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "3fcea762-b53a-4ae1-8365-7bec90444828", + "nodeName" : "董事", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "1820,300|1820,300", + "formCustom" : "N", + "ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]", + "skipList" : [ { + "nowNodeCode" : "3fcea762-b53a-4ae1-8365-7bec90444828", + "nextNodeCode" : "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31", + "skipType" : "PASS", + "coordinate" : "1870,300;1960,300" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1980,300|1980,300", + "formCustom" : "N", + "ext" : "[]" + } ] +} diff --git a/script/sql/menuInitValue.sql b/script/sql/menuInitValue.sql new file mode 100644 index 0000000..89f32bd --- /dev/null +++ b/script/sql/menuInitValue.sql @@ -0,0 +1,1776 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896943300447367169, '项目', '1', '1', 'project', 'project/project/index', 1, 0, 'C', '0', '0', + 'project:project:list', '#', 103, 1, sysdate(), null, null, '项目菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896943300447367170, '项目查询', 1896943300447367169, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:project:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896943300447367171, '项目新增', 1896943300447367169, '2', '#', '', 1, 0, 'F', '0', '0', 'project:project:add', + '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896943300447367172, '项目修改', 1896943300447367169, '3', '#', '', 1, 0, 'F', '0', '0', 'project:project:edit', + '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896943300447367173, '项目删除', 1896943300447367169, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:project:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896943300447367174, '项目导出', 1896943300447367169, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:project:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896949180526047233, '系统用户与项目关联', '1', '1', 'projectRelevancy', 'project/projectRelevancy/index', 1, 0, + 'C', '0', '0', 'project:projectRelevancy:list', '#', 103, 1, sysdate(), null, null, '系统用户与项目关联菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896949180526047234, '系统用户与项目关联查询', 1896949180526047233, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:projectRelevancy:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896949180526047235, '系统用户与项目关联新增', 1896949180526047233, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:projectRelevancy:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896949180526047236, '系统用户与项目关联修改', 1896949180526047233, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:projectRelevancy:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896949180526047237, '系统用户与项目关联删除', 1896949180526047233, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:projectRelevancy:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1896949180526047238, '系统用户与项目关联导出', 1896949180526047233, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:projectRelevancy:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479771016716290, '公司', '1', '1', 'company', 'materials/company/index', 1, 0, 'C', '0', '0', + 'materials:company:list', '#', 103, 1, sysdate(), null, null, '公司菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479771016716291, '公司查询', 1897479771016716290, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:company:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479771016716292, '公司新增', 1897479771016716290, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:company:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479771016716293, '公司修改', 1897479771016716290, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:company:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479771016716294, '公司删除', 1897479771016716290, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:company:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479771016716295, '公司导出', 1897479771016716290, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:company:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479769502572546, '材料出/入库', '1', '1', 'materialsInventory', 'materials/materialsInventory/index', 1, 0, + 'C', '0', '0', 'materials:materialsInventory:list', '#', 103, 1, sysdate(), null, null, '材料出/入库菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479769502572547, '材料出/入库查询', 1897479769502572546, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialsInventory:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479769502572548, '材料出/入库新增', 1897479769502572546, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialsInventory:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479769502572549, '材料出/入库修改', 1897479769502572546, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialsInventory:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479769502572550, '材料出/入库删除', 1897479769502572546, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialsInventory:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479769502572551, '材料出/入库导出', 1897479769502572546, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialsInventory:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479770626646018, '材料名称', '1', '1', 'materials', 'materials/materials/index', 1, 0, 'C', '0', '0', + 'materials:materials:list', '#', 103, 1, sysdate(), null, null, '材料名称菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479770626646019, '材料名称查询', 1897479770626646018, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materials:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479770626646020, '材料名称新增', 1897479770626646018, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materials:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479770626646021, '材料名称修改', 1897479770626646018, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materials:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479770626646022, '材料名称删除', 1897479770626646018, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materials:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897479770626646023, '材料名称导出', 1897479770626646018, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materials:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844021656604674, '项目班组', '1897103538172985346', '1', 'projectTeam', 'project/projectTeam/index', 1, 0, + 'C', '0', '0', 'project:projectTeam:list', '#', 103, 1, sysdate(), null, null, '项目班组菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844021656604675, '项目班组查询', 1897844021656604674, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeam:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844021656604676, '项目班组新增', 1897844021656604674, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeam:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844021656604677, '项目班组修改', 1897844021656604674, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeam:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844021656604678, '项目班组删除', 1897844021656604674, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeam:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844021656604679, '项目班组导出', 1897844021656604674, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeam:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937072514748444673, '项目班组下的成员', '1897844021656604674', '1', 'projectTeamMember', + 'project/projectTeamMember/index', 1, 0, 'C', '0', '0', 'project:projectTeamMember:list', '#', 103, 1, + sysdate(), null, null, '项目班组下的成员菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937072514748444674, '项目班组下的成员查询', 1937072514748444673, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeamMember:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937072514748444675, '项目班组下的成员新增', 1937072514748444673, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeamMember:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937072514748444676, '项目班组下的成员修改', 1937072514748444673, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeamMember:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937072514748444677, '项目班组下的成员删除', 1937072514748444673, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeamMember:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937072514748444678, '项目班组下的成员导出', 1937072514748444673, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:projectTeamMember:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844022721957889, '分包单位', '1897103538172985346', '1', 'contractor', 'project/contractor/index', 1, 0, + 'C', '0', '0', 'project:contractor:list', '#', 103, 1, sysdate(), null, null, '分包单位菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844022721957890, '分包单位查询', 1897844022721957889, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:contractor:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844022721957891, '分包单位新增', 1897844022721957889, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:contractor:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844022721957892, '分包单位修改', 1897844022721957889, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:contractor:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844022721957893, '分包单位删除', 1897844022721957889, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:contractor:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844022721957894, '分包单位导出', 1897844022721957889, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:contractor:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844023242051586, '施工人员', '1897103538172985346', '1', 'constructionUser', + 'project/constructionUser/index', 1, 0, 'C', '0', '0', 'project:constructionUser:list', '#', 103, 1, sysdate(), + null, null, '施工人员菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844023242051587, '施工人员查询', 1897844023242051586, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionUser:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844023242051588, '施工人员新增', 1897844023242051586, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionUser:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844023242051589, '施工人员修改', 1897844023242051586, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionUser:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844023242051590, '施工人员删除', 1897844023242051586, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionUser:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897844023242051591, '施工人员导出', 1897844023242051586, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionUser:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935931448537090, '机械', '1', '1', 'machinery', 'machinery/machinery/index', 1, 0, 'C', '0', '0', + 'machinery:machinery:list', '#', 103, 1, sysdate(), null, null, '机械菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935931448537091, '机械查询', 1897935931448537090, '1', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machinery:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935931448537092, '机械新增', 1897935931448537090, '2', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machinery:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935931448537093, '机械修改', 1897935931448537090, '3', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machinery:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935931448537094, '机械删除', 1897935931448537090, '4', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machinery:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935931448537095, '机械导出', 1897935931448537090, '5', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machinery:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935932513890306, '机械详情', '1', '1', 'machineryDetail', 'machinery/machineryDetail/index', 1, 0, 'C', '0', + '0', 'machinery:machineryDetail:list', '#', 103, 1, sysdate(), null, null, '机械详情菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935932513890307, '机械详情查询', 1897935932513890306, '1', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935932513890308, '机械详情新增', 1897935932513890306, '2', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935932513890309, '机械详情修改', 1897935932513890306, '3', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935932513890310, '机械详情删除', 1897935932513890306, '4', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1897935932513890311, '机械详情导出', 1897935932513890306, '5', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902191763472310274, '站班会', '1902191175640604673', '1', 'teamMeeting', 'safety/teamMeeting/index', 1, 0, 'C', + '0', '0', 'safety:teamMeeting:list', '#', 103, 1, sysdate(), null, null, '站班会菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902191763472310275, '站班会查询', 1902191763472310274, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:teamMeeting:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902191763472310276, '站班会新增', 1902191763472310274, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:teamMeeting:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902191763472310277, '站班会修改', 1902191763472310274, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:teamMeeting:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902191763472310278, '站班会删除', 1902191763472310274, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:teamMeeting:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902191763472310279, '站班会导出', 1902191763472310274, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:teamMeeting:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902565328299245569, '安全巡检工单', '1902191175640604673', '1', 'safetyInspection', + 'safety/safetyInspection/index', 1, 0, 'C', '0', '0', 'safety:safetyInspection:list', '#', 103, 1, sysdate(), + null, null, '安全巡检工单菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902565328299245570, '安全巡检工单查询', 1902565328299245569, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902565328299245571, '安全巡检工单新增', 1902565328299245569, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902565328299245572, '安全巡检工单修改', 1902565328299245569, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902565328299245573, '安全巡检工单删除', 1902565328299245569, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902565328299245574, '安全巡检工单导出', 1902565328299245569, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955765108738, '安全日志', '1902191175640604673', '1', 'safetyLog', 'safety/safetyLog/index', 1, 0, 'C', + '0', '0', 'safety:safetyLog:list', '#', 103, 1, sysdate(), null, null, '安全日志菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955765108739, '安全日志查询', 1902609955765108738, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955765108740, '安全日志新增', 1902609955765108738, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955765108741, '安全日志修改', 1902609955765108738, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955765108742, '安全日志删除', 1902609955765108738, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955765108743, '安全日志导出', 1902609955765108738, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955433758722, '安全周报', '1902191175640604673', '1', 'safetyWeeklyReport', + 'safety/safetyWeeklyReport/index', 1, 0, 'C', '0', '0', 'safety:safetyWeeklyReport:list', '#', 103, 1, + sysdate(), null, null, '安全周报菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955433758723, '安全周报查询', 1902609955433758722, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955433758724, '安全周报新增', 1902609955433758722, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955433758725, '安全周报修改', 1902609955433758722, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955433758726, '安全周报删除', 1902609955433758722, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1902609955433758727, '安全周报导出', 1902609955433758722, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398346084354, '题库配置', '1902191175640604673', '1', 'questionsConfig', 'safety/questionsConfig/index', + 1, 0, 'C', '0', '0', 'safety:questionsConfig:list', '#', 103, 1, sysdate(), null, null, '题库配置菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398346084355, '题库配置查询', 1904108398346084354, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionsConfig:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398346084356, '题库配置新增', 1904108398346084354, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionsConfig:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398346084357, '题库配置修改', 1904108398346084354, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionsConfig:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398346084358, '题库配置删除', 1904108398346084354, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionsConfig:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398346084359, '题库配置导出', 1904108398346084354, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionsConfig:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398077648898, '题库', '1902191175640604673', '1', 'questionBank', 'safety/questionBank/index', 1, 0, 'C', + '0', '0', 'safety:questionBank:list', '#', 103, 1, sysdate(), null, null, '题库菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398077648899, '题库查询', 1904108398077648898, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionBank:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398077648900, '题库新增', 1904108398077648898, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionBank:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398077648901, '题库修改', 1904108398077648898, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionBank:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398077648902, '题库删除', 1904108398077648898, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionBank:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108398077648903, '题库导出', 1904108398077648898, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionBank:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108397817602050, '用户试卷存储', '1902191175640604673', '1', 'questionUserAnswer', + 'safety/questionUserAnswer/index', 1, 0, 'C', '0', '0', 'safety:questionUserAnswer:list', '#', 103, 1, + sysdate(), null, null, '用户试卷存储菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108397817602051, '用户试卷存储查询', 1904108397817602050, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionUserAnswer:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108397817602052, '用户试卷存储新增', 1904108397817602050, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionUserAnswer:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108397817602053, '用户试卷存储修改', 1904108397817602050, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionUserAnswer:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108397817602054, '用户试卷存储删除', 1904108397817602050, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionUserAnswer:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904108397817602055, '用户试卷存储导出', 1904108397817602050, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:questionUserAnswer:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904710568773734402, '考勤', '1897103538172985346', '1', 'attendance', 'project/attendance/index', 1, 0, 'C', + '0', '0', 'project:attendance:list', '#', 103, 1, sysdate(), null, null, '考勤菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904710568773734403, '考勤查询', 1904710568773734402, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:attendance:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904710568773734404, '考勤新增', 1904710568773734402, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:attendance:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904710568773734405, '考勤修改', 1904710568773734402, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:attendance:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904710568773734406, '考勤删除', 1904710568773734402, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:attendance:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904710568773734407, '考勤导出', 1904710568773734402, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:attendance:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904782387791822849, '工种薪水', '1897103538172985346', '1', 'workWage', 'project/workWage/index', 1, 0, 'C', + '0', '0', 'project:workWage:list', '#', 103, 1, sysdate(), null, null, '工种薪水菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904782387791822850, '工种薪水查询', 1904782387791822849, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:workWage:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904782387791822851, '工种薪水新增', 1904782387791822849, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:workWage:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904782387791822852, '工种薪水修改', 1904782387791822849, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:workWage:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904782387791822853, '工种薪水删除', 1904782387791822849, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:workWage:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1904782387791822854, '工种薪水导出', 1904782387791822849, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:workWage:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1905067946597736450, '黑名单', '1897103538172985346', '1', 'constructionBlacklist', + 'project/constructionBlacklist/index', 1, 0, 'C', '0', '0', 'project:constructionBlacklist:list', '#', 103, 1, + sysdate(), null, null, '黑名单菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1905067946597736451, '黑名单查询', 1905067946597736450, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionBlacklist:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1905067946597736452, '黑名单新增', 1905067946597736450, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionBlacklist:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1905067946597736453, '黑名单修改', 1905067946597736450, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionBlacklist:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1905067946597736454, '黑名单删除', 1905067946597736450, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionBlacklist:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1905067946597736455, '黑名单导出', 1905067946597736450, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:constructionBlacklist:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1927984223038324738, '进度类别模版', '1913133014288699393', '1', 'progressCategoryTemplate', + 'progress/progressCategoryTemplate/index', 1, 0, 'C', '0', '0', 'progress:progressCategoryTemplate:list', '#', + 103, 1, sysdate(), null, null, '进度类别模版菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1927984223038324739, '进度类别模版查询', 1927984223038324738, '1', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategoryTemplate:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1927984223038324740, '进度类别模版新增', 1927984223038324738, '2', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategoryTemplate:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1927984223038324741, '进度类别模版修改', 1927984223038324738, '3', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategoryTemplate:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1927984223038324742, '进度类别模版删除', 1927984223038324738, '4', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategoryTemplate:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1927984223038324743, '进度类别模版导出', 1927984223038324738, '5', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategoryTemplate:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933345067448147969, '萤石摄像头', '1933341785996664834', '1', 'ys7Device', 'other/ys7Device/index', 1, 0, 'C', + '0', '0', 'other:ys7Device:list', '#', 103, 1, sysdate(), null, null, '萤石摄像头菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933345067448147970, '萤石摄像头查询', 1933345067448147969, '1', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7Device:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933345067448147971, '萤石摄像头新增', 1933345067448147969, '2', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7Device:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933345067448147972, '萤石摄像头修改', 1933345067448147969, '3', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7Device:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933345067448147973, '萤石摄像头删除', 1933345067448147969, '4', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7Device:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933345067448147974, '萤石摄像头导出', 1933345067448147969, '5', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7Device:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933445976098406401, '摄像头预置位', '1933345067448147969', '1', 'devicePreset', 'other/devicePreset/index', 1, + 0, 'C', '0', '0', 'other:devicePreset:list', '#', 103, 1, sysdate(), null, null, '摄像头预置位菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933445976098406402, '摄像头预置位查询', 1933445976098406401, '1', '#', '', 1, 0, 'F', '0', '0', + 'other:devicePreset:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933445976098406403, '摄像头预置位新增', 1933445976098406401, '2', '#', '', 1, 0, 'F', '0', '0', + 'other:devicePreset:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933445976098406404, '摄像头预置位修改', 1933445976098406401, '3', '#', '', 1, 0, 'F', '0', '0', + 'other:devicePreset:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933445976098406405, '摄像头预置位删除', 1933445976098406401, '4', '#', '', 1, 0, 'F', '0', '0', + 'other:devicePreset:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1933445976098406406, '摄像头预置位导出', 1933445976098406401, '5', '#', '', 1, 0, 'F', '0', '0', + 'other:devicePreset:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935231471757307906, '萤石摄像头图片', '1933345067448147969', '1', 'ys7DeviceImg', 'other/ys7DeviceImg/index', + 1, 0, 'C', '0', '0', 'other:ys7DeviceImg:list', '#', 103, 1, sysdate(), null, null, '萤石摄像头图片菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935231471757307907, '萤石摄像头图片查询', 1935231471757307906, '1', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7DeviceImg:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935231471757307908, '萤石摄像头图片新增', 1935231471757307906, '2', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7DeviceImg:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935231471757307909, '萤石摄像头图片修改', 1935231471757307906, '3', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7DeviceImg:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935231471757307910, '萤石摄像头图片删除', 1935231471757307906, '4', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7DeviceImg:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935231471757307911, '萤石摄像头图片导出', 1935231471757307906, '5', '#', '', 1, 0, 'F', '0', '0', + 'other:ys7DeviceImg:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935896590929661954, '违章等级', '1935597155897143297', '1', 'violationLevel', 'safety/violationLevel/index', 1, + 0, 'C', '0', '0', 'safety:violationLevel:list', '#', 103, 1, sysdate(), null, null, '违章等级菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935896590929661955, '违章等级查询', 1935896590929661954, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevel:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935896590929661956, '违章等级新增', 1935896590929661954, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevel:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935896590929661957, '违章等级修改', 1935896590929661954, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevel:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935896590929661958, '违章等级删除', 1935896590929661954, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevel:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935896590929661959, '违章等级导出', 1935896590929661954, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevel:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935909171354439681, '等级与岗位关联', '1935896590929661954', '1', 'violationLevelPost', + 'safety/violationLevelPost/index', 1, 0, 'C', '0', '0', 'safety:violationLevelPost:list', '#', 103, 1, + sysdate(), null, null, '等级与岗位关联菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935909171354439682, '等级与岗位关联查询', 1935909171354439681, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevelPost:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935909171354439683, '等级与岗位关联新增', 1935909171354439681, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevelPost:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935909171354439684, '等级与岗位关联修改', 1935909171354439681, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevelPost:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935909171354439685, '等级与岗位关联删除', 1935909171354439681, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevelPost:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1935909171354439686, '等级与岗位关联导出', 1935909171354439681, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationLevelPost:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937085861401325569, '机械详情', '1898940240252375042', '1', 'machineryDetail', + 'machinery/machineryDetail/index', 1, 0, 'C', '0', '0', 'machinery:machineryDetail:list', '#', 103, 1, + sysdate(), null, null, '机械详情菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937085861401325570, '机械详情查询', 1937085861401325569, '1', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937085861401325571, '机械详情新增', 1937085861401325569, '2', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937085861401325572, '机械详情修改', 1937085861401325569, '3', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937085861401325573, '机械详情删除', 1937085861401325569, '4', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937085861401325574, '机械详情导出', 1937085861401325569, '5', '#', '', 1, 0, 'F', '0', '0', + 'machinery:machineryDetail:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097586280235010, '安全巡检工单', '1902191175640604673', '1', 'safetyInspection', + 'safety/safetyInspection/index', 1, 0, 'C', '0', '0', 'safety:safetyInspection:list', '#', 103, 1, sysdate(), + null, null, '安全巡检工单菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097586280235011, '安全巡检工单查询', 1937097586280235010, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097586280235012, '安全巡检工单新增', 1937097586280235010, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097586280235013, '安全巡检工单修改', 1937097586280235010, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097586280235014, '安全巡检工单删除', 1937097586280235010, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097586280235015, '安全巡检工单导出', 1937097586280235010, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyInspection:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097992276279297, '安全周报', '1902191175640604673', '1', 'safetyWeeklyReport', + 'safety/safetyWeeklyReport/index', 1, 0, 'C', '0', '0', 'safety:safetyWeeklyReport:list', '#', 103, 1, + sysdate(), null, null, '安全周报菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097992276279298, '安全周报查询', 1937097992276279297, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097992276279299, '安全周报新增', 1937097992276279297, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097992276279300, '安全周报修改', 1937097992276279297, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097992276279301, '安全周报删除', 1937097992276279297, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937097992276279302, '安全周报导出', 1937097992276279297, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyWeeklyReport:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937098027248386049, '安全日志', '1902191175640604673', '1', 'safetyLog', 'safety/safetyLog/index', 1, 0, 'C', + '0', '0', 'safety:safetyLog:list', '#', 103, 1, sysdate(), null, null, '安全日志菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937098027248386050, '安全日志查询', 1937098027248386049, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937098027248386051, '安全日志新增', 1937098027248386049, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937098027248386052, '安全日志修改', 1937098027248386049, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937098027248386053, '安全日志删除', 1937098027248386049, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937098027248386054, '安全日志导出', 1937098027248386049, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:safetyLog:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100190854938626, '进度计划详情', '1925849078848049153', '1', 'progressPlanDetail', + 'progress/progressPlanDetail/index', 1, 0, 'C', '0', '0', 'progress:progressPlanDetail:list', '#', 103, 1, + sysdate(), null, null, '进度计划详情菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100190854938627, '进度计划详情查询', 1937100190854938626, '1', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressPlanDetail:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100190854938628, '进度计划详情新增', 1937100190854938626, '2', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressPlanDetail:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100190854938629, '进度计划详情修改', 1937100190854938626, '3', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressPlanDetail:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100190854938630, '进度计划详情删除', 1937100190854938626, '4', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressPlanDetail:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100190854938631, '进度计划详情导出', 1937100190854938626, '5', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressPlanDetail:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100268151767042, '进度类别', '1925849078848049153', '1', 'progressCategory', + 'progress/progressCategory/index', 1, 0, 'C', '0', '0', 'progress:progressCategory:list', '#', 103, 1, + sysdate(), null, null, '进度类别菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100268151767043, '进度类别查询', 1937100268151767042, '1', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategory:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100268151767044, '进度类别新增', 1937100268151767042, '2', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategory:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100268151767045, '进度类别修改', 1937100268151767042, '3', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategory:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100268151767046, '进度类别删除', 1937100268151767042, '4', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategory:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937100268151767047, '进度类别导出', 1937100268151767042, '5', '#', '', 1, 0, 'F', '0', '0', + 'progress:progressCategory:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937338721300996098, '识别记录', '1935597155897143297', '1', 'recognizeRecord', 'safety/recognizeRecord/index', + 1, 0, 'C', '0', '0', 'safety:recognizeRecord:list', '#', 103, 1, sysdate(), null, null, '识别记录菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937338721300996099, '识别记录查询', 1937338721300996098, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:recognizeRecord:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937338721300996100, '识别记录新增', 1937338721300996098, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:recognizeRecord:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937338721300996101, '识别记录修改', 1937338721300996098, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:recognizeRecord:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937338721300996102, '识别记录删除', 1937338721300996098, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:recognizeRecord:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937338721300996103, '识别记录导出', 1937338721300996098, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:recognizeRecord:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937790795423707138, '分包合同', '1937684147828957185', '1', 'subcontract', 'project/subcontract/index', 1, 0, + 'C', '0', '0', 'project:subcontract:list', '#', 103, 1, sysdate(), null, null, '分包合同菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937790795423707139, '分包合同查询', 1937790795423707138, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:subcontract:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937790795423707140, '分包合同新增', 1937790795423707138, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:subcontract:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937790795423707141, '分包合同修改', 1937790795423707138, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:subcontract:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937790795423707142, '分包合同删除', 1937790795423707138, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:subcontract:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937790795423707143, '分包合同导出', 1937790795423707138, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:subcontract:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825328848191490, '安全知识库', '1902191175640604673', '1', 'knowledgeDocument', + 'safety/knowledgeDocument/index', 1, 0, 'C', '0', '0', 'safety:knowledgeDocument:list', '#', 103, 1, sysdate(), + null, null, '安全知识库菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825328848191491, '安全知识库查询', 1937825328848191490, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:knowledgeDocument:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825328848191492, '安全知识库新增', 1937825328848191490, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:knowledgeDocument:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825328848191493, '安全知识库修改', 1937825328848191490, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:knowledgeDocument:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825328848191494, '安全知识库删除', 1937825328848191490, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:knowledgeDocument:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825328848191495, '安全知识库导出', 1937825328848191490, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:knowledgeDocument:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825131464245250, '质量知识库', '1912336811971096577', '1', 'knowledgeDocument', + 'quality/knowledgeDocument/index', 1, 0, 'C', '0', '0', 'quality:knowledgeDocument:list', '#', 103, 1, + sysdate(), null, null, '质量知识库菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825131464245251, '质量知识库查询', 1937825131464245250, '1', '#', '', 1, 0, 'F', '0', '0', + 'quality:knowledgeDocument:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825131464245252, '质量知识库新增', 1937825131464245250, '2', '#', '', 1, 0, 'F', '0', '0', + 'quality:knowledgeDocument:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825131464245253, '质量知识库修改', 1937825131464245250, '3', '#', '', 1, 0, 'F', '0', '0', + 'quality:knowledgeDocument:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825131464245254, '质量知识库删除', 1937825131464245250, '4', '#', '', 1, 0, 'F', '0', '0', + 'quality:knowledgeDocument:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1937825131464245255, '质量知识库导出', 1937825131464245250, '5', '#', '', 1, 0, 'F', '0', '0', + 'quality:knowledgeDocument:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938134870333067266, '分包方工器具', '1937684147828957185', '1', 'contractorTool', + 'project/contractorTool/index', 1, 0, 'C', '0', '0', 'project:contractorTool:list', '#', 103, 1, sysdate(), + null, null, '分包方工器具菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938134870333067267, '分包方工器具查询', 1938134870333067266, '1', '#', '', 1, 0, 'F', '0', '0', + 'project:contractorTool:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938134870333067268, '分包方工器具新增', 1938134870333067266, '2', '#', '', 1, 0, 'F', '0', '0', + 'project:contractorTool:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938134870333067269, '分包方工器具修改', 1938134870333067266, '3', '#', '', 1, 0, 'F', '0', '0', + 'project:contractorTool:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938134870333067270, '分包方工器具删除', 1938134870333067266, '4', '#', '', 1, 0, 'F', '0', '0', + 'project:contractorTool:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938134870333067271, '分包方工器具导出', 1938134870333067266, '5', '#', '', 1, 0, 'F', '0', '0', + 'project:contractorTool:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938171656673443841, '分包方工器具进场', '1938134870333067266', '1', 'contractorToolEntry', + 'contractor/contractorToolEntry/index', 1, 0, 'C', '0', '0', 'contractor:contractorToolEntry:list', '#', 103, 1, + sysdate(), null, null, '分包方工器具进场菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938171656673443842, '分包方工器具进场查询', 1938171656673443841, '1', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorToolEntry:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938171656673443843, '分包方工器具进场新增', 1938171656673443841, '2', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorToolEntry:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938171656673443844, '分包方工器具进场修改', 1938171656673443841, '3', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorToolEntry:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938171656673443845, '分包方工器具进场删除', 1938171656673443841, '4', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorToolEntry:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938171656673443846, '分包方工器具进场导出', 1938171656673443841, '5', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorToolEntry:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938446866786041857, '分包方物料', '1937684147828957185', '1', 'contractorMaterial', + 'contractor/contractorMaterial/index', 1, 0, 'C', '0', '0', 'contractor:contractorMaterial:list', '#', 103, 1, + sysdate(), null, null, '分包方物料菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938446866786041858, '分包方物料查询', 1938446866786041857, '1', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorMaterial:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938446866786041859, '分包方物料新增', 1938446866786041857, '2', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorMaterial:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938446866786041860, '分包方物料修改', 1938446866786041857, '3', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorMaterial:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938446866786041861, '分包方物料删除', 1938446866786041857, '4', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorMaterial:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1938446866786041862, '分包方物料导出', 1938446866786041857, '5', '#', '', 1, 0, 'F', '0', '0', + 'contractor:contractorMaterial:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940302123455496193, '技术标准管理', '1940300237524451330', '1', 'technicalStandard', + 'design/technicalStandard/index', 1, 0, 'C', '0', '0', 'design:technicalStandard:list', '#', 103, 1, sysdate(), + null, null, '技术标准管理菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940302123455496194, '技术标准管理查询', 1940302123455496193, '1', '#', '', 1, 0, 'F', '0', '0', + 'design:technicalStandard:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940302123455496195, '技术标准管理新增', 1940302123455496193, '2', '#', '', 1, 0, 'F', '0', '0', + 'design:technicalStandard:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940302123455496196, '技术标准管理修改', 1940302123455496193, '3', '#', '', 1, 0, 'F', '0', '0', + 'design:technicalStandard:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940302123455496197, '技术标准管理删除', 1940302123455496193, '4', '#', '', 1, 0, 'F', '0', '0', + 'design:technicalStandard:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940302123455496198, '技术标准管理导出', 1940302123455496193, '5', '#', '', 1, 0, 'F', '0', '0', + 'design:technicalStandard:export', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu +values ('5', '测试菜单', '0', '5', 'demo', null, '', 1, 0, 'M', '0', '0', '', 'star', 103, 1, sysdate(), null, null, + '测试菜单'); + +-- 请假测试相关按钮 +insert into sys_menu +VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', '', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', + 103, 1, sysdate(), NULL, NULL, '请假申请菜单'); +insert into sys_menu +VALUES (11639, '请假申请查询', 11638, 1, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, + sysdate(), NULL, NULL, ''); +insert into sys_menu +VALUES (11640, '请假申请新增', 11638, 2, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), + NULL, NULL, ''); +insert into sys_menu +VALUES (11641, '请假申请修改', 11638, 3, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, + sysdate(), NULL, NULL, ''); +insert into sys_menu +VALUES (11642, '请假申请删除', 11638, 4, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, + sysdate(), NULL, NULL, ''); +insert into sys_menu +VALUES (11643, '请假申请导出', 11638, 5, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, + sysdate(), NULL, NULL, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940367276851081217, '图纸管理', '1940300237524451330', '1', 'drawing', 'design/drawing/index', 1, 0, 'C', '0', + '0', 'design:drawing:list', '#', 103, 1, sysdate(), null, null, '图纸管理菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940367276851081218, '图纸管理查询', 1940367276851081217, '1', '#', '', 1, 0, 'F', '0', '0', + 'design:drawing:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940367276851081219, '图纸管理新增', 1940367276851081217, '2', '#', '', 1, 0, 'F', '0', '0', + 'design:drawing:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940367276851081220, '图纸管理修改', 1940367276851081217, '3', '#', '', 1, 0, 'F', '0', '0', + 'design:drawing:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940367276851081221, '图纸管理删除', 1940367276851081217, '4', '#', '', 1, 0, 'F', '0', '0', + 'design:drawing:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940367276851081222, '图纸管理导出', 1940367276851081217, '5', '#', '', 1, 0, 'F', '0', '0', + 'design:drawing:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940612372729274369, '专项方案管理', '1940300237524451330', '1', 'specialScheme', 'design/specialScheme/index', + 1, 0, 'C', '0', '0', 'design:specialScheme:list', '#', 103, 1, sysdate(), null, null, '专项方案管理菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940612372729274370, '专项方案管理查询', 1940612372729274369, '1', '#', '', 1, 0, 'F', '0', '0', + 'design:specialScheme:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940612372729274371, '专项方案管理新增', 1940612372729274369, '2', '#', '', 1, 0, 'F', '0', '0', + 'design:specialScheme:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940612372729274372, '专项方案管理修改', 1940612372729274369, '3', '#', '', 1, 0, 'F', '0', '0', + 'design:specialScheme:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940612372729274373, '专项方案管理删除', 1940612372729274369, '4', '#', '', 1, 0, 'F', '0', '0', + 'design:specialScheme:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940612372729274374, '专项方案管理导出', 1940612372729274369, '5', '#', '', 1, 0, 'F', '0', '0', + 'design:specialScheme:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940723160391405569, '设计变更管理', '1940300237524451330', '1', 'designChange', 'design/designChange/index', 1, + 0, 'C', '0', '0', 'design:designChange:list', '#', 103, 1, sysdate(), null, null, '设计变更管理菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940723160391405570, '设计变更管理查询', 1940723160391405569, '1', '#', '', 1, 0, 'F', '0', '0', + 'design:designChange:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940723160391405571, '设计变更管理新增', 1940723160391405569, '2', '#', '', 1, 0, 'F', '0', '0', + 'design:designChange:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940723160391405572, '设计变更管理修改', 1940723160391405569, '3', '#', '', 1, 0, 'F', '0', '0', + 'design:designChange:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940723160391405573, '设计变更管理删除', 1940723160391405569, '4', '#', '', 1, 0, 'F', '0', '0', + 'design:designChange:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1940723160391405574, '设计变更管理导出', 1940723160391405569, '5', '#', '', 1, 0, 'F', '0', '0', + 'design:designChange:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027796600016898, '物料领料单', '1940386534691717121', '1', 'materialIssue', 'materials/materialIssue/index', + 1, 0, 'C', '0', '0', 'materials:materialIssue:list', '#', 103, 1, sysdate(), null, null, '物料领料单菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027796600016899, '物料领料单查询', 1941027796600016898, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027796600016900, '物料领料单新增', 1941027796600016898, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027796600016901, '物料领料单修改', 1941027796600016898, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027796600016902, '物料领料单删除', 1941027796600016898, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027796600016903, '物料领料单导出', 1941027796600016898, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027798210629634, '物料接收单', '1940386534691717121', '1', 'materialReceive', + 'materials/materialReceive/index', 1, 0, 'C', '0', '0', 'materials:materialReceive:list', '#', 103, 1, + sysdate(), null, null, '物料接收单菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027798210629635, '物料接收单查询', 1941027798210629634, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027798210629636, '物料接收单新增', 1941027798210629634, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027798210629637, '物料接收单修改', 1941027798210629634, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027798210629638, '物料接收单删除', 1941027798210629634, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941027798210629639, '物料接收单导出', 1941027798210629634, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028782785744898, '物料领料单', '1940389874213339138', '1', 'materialIssue', 'materials/materialIssue/index', + 1, 0, 'C', '0', '0', 'materials:materialIssue:list', '#', 103, 1, sysdate(), null, null, '物料领料单菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028782785744899, '物料领料单查询', 1941028782785744898, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028782785744900, '物料领料单新增', 1941028782785744898, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028782785744901, '物料领料单修改', 1941028782785744898, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028782785744902, '物料领料单删除', 1941028782785744898, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028782785744903, '物料领料单导出', 1941028782785744898, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssue:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028820853248002, '物料接收单', '1940389874213339138', '1', 'materialReceive', + 'materials/materialReceive/index', 1, 0, 'C', '0', '0', 'materials:materialReceive:list', '#', 103, 1, + sysdate(), null, null, '物料接收单菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028820853248003, '物料接收单查询', 1941028820853248002, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028820853248004, '物料接收单新增', 1941028820853248002, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028820853248005, '物料接收单修改', 1941028820853248002, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028820853248006, '物料接收单删除', 1941028820853248002, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941028820853248007, '物料接收单导出', 1941028820853248002, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceive:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030734919684097, '物料领料单明细项', '1941027796600016898', '1', 'materialIssueItem', + 'materials/materialIssueItem/index', 1, 0, 'C', '0', '0', 'materials:materialIssueItem:list', '#', 103, 1, + sysdate(), null, null, '物料领料单明细项菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030734919684098, '物料领料单明细项查询', 1941030734919684097, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030734919684099, '物料领料单明细项新增', 1941030734919684097, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030734919684100, '物料领料单明细项修改', 1941030734919684097, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030734919684101, '物料领料单明细项删除', 1941030734919684097, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030734919684102, '物料领料单明细项导出', 1941030734919684097, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030735251034113, '物料接收单明细项', '1941027798210629634', '1', 'materialReceiveItem', + 'materials/materialReceiveItem/index', 1, 0, 'C', '0', '0', 'materials:materialReceiveItem:list', '#', 103, 1, + sysdate(), null, null, '物料接收单明细项菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030735251034114, '物料接收单明细项查询', 1941030735251034113, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030735251034115, '物料接收单明细项新增', 1941030735251034113, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030735251034116, '物料接收单明细项修改', 1941030735251034113, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030735251034117, '物料接收单明细项删除', 1941030735251034113, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941030735251034118, '物料接收单明细项导出', 1941030735251034113, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032197632929794, '物料接收单明细项', '1941028820853248002', '1', 'materialReceiveItem', + 'materials/materialReceiveItem/index', 1, 0, 'C', '0', '0', 'materials:materialReceiveItem:list', '#', 103, 1, + sysdate(), null, null, '物料接收单明细项菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032197632929795, '物料接收单明细项查询', 1941032197632929794, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032197632929796, '物料接收单明细项新增', 1941032197632929794, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032197632929797, '物料接收单明细项修改', 1941032197632929794, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032197632929798, '物料接收单明细项删除', 1941032197632929794, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032197632929799, '物料接收单明细项导出', 1941032197632929794, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialReceiveItem:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032233947213826, '物料领料单明细项', '1941028782785744898', '1', 'materialIssueItem', + 'materials/materialIssueItem/index', 1, 0, 'C', '0', '0', 'materials:materialIssueItem:list', '#', 103, 1, + sysdate(), null, null, '物料领料单明细项菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032233947213827, '物料领料单明细项查询', 1941032233947213826, '1', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032233947213828, '物料领料单明细项新增', 1941032233947213826, '2', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032233947213829, '物料领料单明细项修改', 1941032233947213826, '3', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032233947213830, '物料领料单明细项删除', 1941032233947213826, '4', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1941032233947213831, '物料领料单明细项导出', 1941032233947213826, '5', '#', '', 1, 0, 'F', '0', '0', + 'materials:materialIssueItem:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1942399191372275713, '无人机配置', '1922479275240435713', '1', 'droneConfig', 'drone/droneConfig/index', 1, 0, + 'C', '0', '0', 'drone:droneConfig:list', '#', 103, 1, sysdate(), null, null, '无人机配置菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1942399191372275714, '无人机配置查询', 1942399191372275713, '1', '#', '', 1, 0, 'F', '0', '0', + 'drone:droneConfig:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1942399191372275715, '无人机配置新增', 1942399191372275713, '2', '#', '', 1, 0, 'F', '0', '0', + 'drone:droneConfig:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1942399191372275716, '无人机配置修改', 1942399191372275713, '3', '#', '', 1, 0, 'F', '0', '0', + 'drone:droneConfig:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1942399191372275717, '无人机配置删除', 1942399191372275713, '4', '#', '', 1, 0, 'F', '0', '0', + 'drone:droneConfig:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1942399191372275718, '无人机配置导出', 1942399191372275713, '5', '#', '', 1, 0, 'F', '0', '0', + 'drone:droneConfig:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1947491501058625537, '违规记录', '1935597155897143297', '1', 'violationRecord', 'safety/violationRecord/index', + 1, 0, 'C', '0', '0', 'safety:violationRecord:list', '#', 103, 1, sysdate(), null, null, '违规记录菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1947491501058625538, '违规记录查询', 1947491501058625537, '1', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationRecord:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1947491501058625539, '违规记录新增', 1947491501058625537, '2', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationRecord:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1947491501058625540, '违规记录修改', 1947491501058625537, '3', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationRecord:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1947491501058625541, '违规记录删除', 1947491501058625537, '4', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationRecord:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, + status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values (1947491501058625542, '违规记录导出', 1947491501058625537, '5', '#', '', 1, 0, 'F', '0', '0', + 'safety:violationRecord:export', '#', 103, 1, sysdate(), null, null, ''); diff --git a/script/sql/oracle/oracle_ry_job.sql b/script/sql/oracle/oracle_ry_job.sql new file mode 100644 index 0000000..c2dbbfa --- /dev/null +++ b/script/sql/oracle/oracle_ry_job.sql @@ -0,0 +1,914 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : Oracle + Date: 2024-12-27 22:22:15 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id number GENERATED ALWAYS AS IDENTITY, + name varchar2(64) NULL, + unique_id varchar2(64) NULL, + description varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_namespace + ADD CONSTRAINT pk_sj_namespace PRIMARY KEY (id); + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name); + +COMMENT ON COLUMN sj_namespace.id IS '主键'; +COMMENT ON COLUMN sj_namespace.name IS '名称'; +COMMENT ON COLUMN sj_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN sj_namespace.description IS '描述'; +COMMENT ON COLUMN sj_namespace.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_namespace.update_dt IS '修改时间'; +COMMENT ON TABLE sj_namespace IS '命名空间'; + +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Development', 'dev', '', 0, sysdate, sysdate); +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Production', 'prod', '', 0, sysdate, sysdate); + +-- sj_group_config +CREATE TABLE sj_group_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + description varchar2(256) DEFAULT '' NULL, + token varchar2(64) DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' NULL, + group_status smallint DEFAULT 0 NOT NULL, + version number NOT NULL, + group_partition number NOT NULL, + id_generator_mode smallint DEFAULT 1 NOT NULL, + init_scene smallint DEFAULT 0 NOT NULL, + bucket_index number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_group_config + ADD CONSTRAINT pk_sj_group_config PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_group_config.id IS '主键'; +COMMENT ON COLUMN sj_group_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_group_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_group_config.description IS '组描述'; +COMMENT ON COLUMN sj_group_config.token IS 'token'; +COMMENT ON COLUMN sj_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_group_config.version IS '版本号'; +COMMENT ON COLUMN sj_group_config.group_partition IS '分区'; +COMMENT ON COLUMN sj_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN sj_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN sj_group_config.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_group_config IS '组配置'; + +INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate); +INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate); + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + notify_name varchar2(64) DEFAULT '' NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + notify_status smallint DEFAULT 0 NOT NULL, + recipient_ids varchar2(128) NULL, + notify_threshold number DEFAULT 0 NOT NULL, + notify_scene smallint DEFAULT 0 NOT NULL, + rate_limiter_status smallint DEFAULT 0 NOT NULL, + rate_limiter_threshold number DEFAULT 0 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_notify_config + ADD CONSTRAINT pk_sj_notify_config PRIMARY KEY (id); + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_notify_config.id IS '主键'; +COMMENT ON COLUMN sj_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_notify_config.notify_name IS '通知名称'; +COMMENT ON COLUMN sj_notify_config.system_task_type IS '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.recipient_ids IS '接收人id列表'; +COMMENT ON COLUMN sj_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN sj_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN sj_notify_config.description IS '描述'; +COMMENT ON COLUMN sj_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_config IS '通知配置'; + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + recipient_name varchar2(64) NULL, + notify_type smallint DEFAULT 0 NOT NULL, + notify_attribute varchar2(512) NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_notify_recipient + ADD CONSTRAINT pk_sj_notify_recipient PRIMARY KEY (id); + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); + +COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; +COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; +COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; +COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; +COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_recipient.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_recipient IS '告警通知接收人'; + +-- sj_retry_dead_letter_0 +CREATE TABLE sj_retry_dead_letter_0 +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + unique_id varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_name varchar2(64) NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + args_str clob NULL, + ext_attrs clob NULL, + task_type smallint DEFAULT 1 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_dead_letter_0 + ADD CONSTRAINT pk_sj_retry_dead_letter_0 PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id); +CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no); +CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt); + +COMMENT ON COLUMN sj_retry_dead_letter_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_dead_letter_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_dead_letter_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_dead_letter_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_dead_letter_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_dead_letter_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_dead_letter_0.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_dead_letter_0 IS '死信队列表'; + +-- sj_retry_task_0 +CREATE TABLE sj_retry_task_0 +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + unique_id varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_name varchar2(64) NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + args_str clob NULL, + ext_attrs clob NULL, + next_trigger_at date NOT NULL, + retry_count number DEFAULT 0 NOT NULL, + retry_status smallint DEFAULT 0 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task_0 + ADD CONSTRAINT pk_sj_retry_task_0 PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type); +CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status); +CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id); +CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no); +CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt); + +COMMENT ON COLUMN sj_retry_task_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_0.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_retry_task_0.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_retry_task_0.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN sj_retry_task_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_0.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_0.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_0 IS '任务表'; + +-- sj_retry_task_log +CREATE TABLE sj_retry_task_log +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + unique_id varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_name varchar2(64) NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + args_str clob NULL, + ext_attrs clob NULL, + retry_status smallint DEFAULT 0 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task_log + ADD CONSTRAINT pk_sj_retry_task_log PRIMARY KEY (id); + +CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status); +CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id); +CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id); +CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no); +CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt); + +COMMENT ON COLUMN sj_retry_task_log.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_log.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_log.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_log.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_log.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_log.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_log.retry_status IS '重试状态 0、重试中 1、成功 2、最大次数'; +COMMENT ON COLUMN sj_retry_task_log.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_log.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_log.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_log IS '任务日志基础信息表'; + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + unique_id varchar2(64) NULL, + message clob NULL, + log_num number DEFAULT 1 NOT NULL, + real_time number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task_log_message + ADD CONSTRAINT pk_sj_retry_task_log_message PRIMARY KEY (id); + +CREATE INDEX idx_sj_rt_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id); +CREATE INDEX idx_sj_rt_log_message_02 ON sj_retry_task_log_message (create_dt); + +COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log_message.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_task_log_message IS '任务调度日志信息记录表'; + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + scene_name varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_status smallint DEFAULT 0 NOT NULL, + max_retry_count number DEFAULT 5 NOT NULL, + back_off smallint DEFAULT 1 NOT NULL, + trigger_interval varchar2(16) DEFAULT '' NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + deadline_request number DEFAULT 60000 NOT NULL, + executor_timeout number DEFAULT 5 NOT NULL, + route_key smallint DEFAULT 4 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_scene_config + ADD CONSTRAINT pk_sj_retry_scene_config PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name); + +COMMENT ON COLUMN sj_retry_scene_config.id IS '主键'; +COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_retry_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN sj_retry_scene_config.description IS '描述'; +COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_scene_config IS '场景配置'; + +-- sj_server_node +CREATE TABLE sj_server_node +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + host_id varchar2(64) NULL, + host_ip varchar2(64) NULL, + host_port number NOT NULL, + expire_at date NOT NULL, + node_type smallint NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_server_node + ADD CONSTRAINT pk_sj_server_node PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip); + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name); +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type); + +COMMENT ON COLUMN sj_server_node.id IS '主键'; +COMMENT ON COLUMN sj_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_server_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_server_node.host_id IS '主机id'; +COMMENT ON COLUMN sj_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN sj_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN sj_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN sj_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN sj_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_server_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_server_node IS '服务器节点'; + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name varchar2(64) NOT NULL, + lock_until timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, + locked_at timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, + locked_by varchar2(255) NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_distributed_lock + ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (name); + +COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN sj_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN sj_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_distributed_lock.update_dt IS '修改时间'; +COMMENT ON TABLE sj_distributed_lock IS '锁定表'; + +-- sj_system_user +CREATE TABLE sj_system_user +( + id number GENERATED ALWAYS AS IDENTITY, + username varchar2(64) NULL, + password varchar2(128) NULL, + role smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_system_user + ADD CONSTRAINT pk_sj_system_user PRIMARY KEY (id); + +COMMENT ON COLUMN sj_system_user.id IS '主键'; +COMMENT ON COLUMN sj_system_user.username IS '账号'; +COMMENT ON COLUMN sj_system_user.password IS '密码'; +COMMENT ON COLUMN sj_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN sj_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user IS '系统用户表'; + +-- pwd: admin +INSERT INTO sj_system_user(username, password, role, create_dt, update_dt) VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, sysdate, sysdate); + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id number GENERATED ALWAYS AS IDENTITY, + group_name varchar2(64) NULL, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + system_user_id number NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_system_user_permission + ADD CONSTRAINT pk_sj_system_user_permission PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_su_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); + +COMMENT ON COLUMN sj_system_user_permission.id IS '主键'; +COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN sj_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user_permission.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user_permission IS '系统用户权限表'; + +-- sj_sequence_alloc +CREATE TABLE sj_sequence_alloc +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + max_id number DEFAULT 1 NOT NULL, + step number DEFAULT 100 NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_sequence_alloc + ADD CONSTRAINT pk_sj_sequence_alloc PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name); + +COMMENT ON COLUMN sj_sequence_alloc.id IS '主键'; +COMMENT ON COLUMN sj_sequence_alloc.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_sequence_alloc.group_name IS '组名称'; +COMMENT ON COLUMN sj_sequence_alloc.max_id IS '最大id'; +COMMENT ON COLUMN sj_sequence_alloc.step IS '步长'; +COMMENT ON COLUMN sj_sequence_alloc.update_dt IS '更新时间'; +COMMENT ON TABLE sj_sequence_alloc IS '号段模式序号ID分配表'; + +-- sj_job +CREATE TABLE sj_job +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_name varchar2(64) NULL, + args_str clob DEFAULT NULL NULL, + args_type smallint DEFAULT 1 NOT NULL, + next_trigger_at number NOT NULL, + job_status smallint DEFAULT 1 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + route_key smallint DEFAULT 4 NOT NULL, + executor_type smallint DEFAULT 1 NOT NULL, + executor_info varchar2(255) DEFAULT NULL NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar2(255) NULL, + block_strategy smallint DEFAULT 1 NOT NULL, + executor_timeout number DEFAULT 0 NOT NULL, + max_retry_times number DEFAULT 0 NOT NULL, + parallel_num number DEFAULT 1 NOT NULL, + retry_interval number DEFAULT 0 NOT NULL, + bucket_index number DEFAULT 0 NOT NULL, + resident smallint DEFAULT 0 NOT NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + owner_id number NULL, + description varchar2(256) DEFAULT '' NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job + ADD CONSTRAINT pk_sj_job PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name); +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index); +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt); + +COMMENT ON COLUMN sj_job.id IS '主键'; +COMMENT ON COLUMN sj_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job.group_name IS '组名称'; +COMMENT ON COLUMN sj_job.job_name IS '名称'; +COMMENT ON COLUMN sj_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_job.job_status IS '任务状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN sj_job.route_key IS '路由策略'; +COMMENT ON COLUMN sj_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN sj_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN sj_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN sj_job.parallel_num IS '并行数'; +COMMENT ON COLUMN sj_job.retry_interval IS '重试间隔 ( s ) '; +COMMENT ON COLUMN sj_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN sj_job.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_job.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_job.description IS '描述'; +COMMENT ON COLUMN sj_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job IS '任务信息'; + +INSERT INTO sj_job(namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, notify_ids, owner_id, description, ext_attrs, deleted, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', 'demo-job', NULL, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1,'', '', 0, sysdate, sysdate); + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + task_batch_id number NOT NULL, + task_id number NOT NULL, + message clob NULL, + log_num number DEFAULT 1 NOT NULL, + real_time number DEFAULT 0 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_log_message + ADD CONSTRAINT pk_sj_job_log_message PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt); +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_log_message.id IS '主键'; +COMMENT ON COLUMN sj_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN sj_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN sj_job_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_job_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_job_log_message IS '调度日志'; + +-- sj_job_task +CREATE TABLE sj_job_task +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + task_batch_id number NOT NULL, + parent_id number DEFAULT 0 NOT NULL, + task_status smallint DEFAULT 0 NOT NULL, + retry_count number DEFAULT 0 NOT NULL, + mr_stage smallint DEFAULT NULL NULL, + leaf smallint DEFAULT '1' NOT NULL, + task_name varchar2(255) DEFAULT '' NULL, + client_info varchar2(128) DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + result_message clob NULL, + args_str clob DEFAULT NULL NULL, + args_type smallint DEFAULT 1 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_task + ADD CONSTRAINT pk_sj_job_task PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status); +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt); +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_task.id IS '主键'; +COMMENT ON COLUMN sj_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; +COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; +COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; +COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task IS '任务实例'; + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + workflow_node_id number DEFAULT 0 NOT NULL, + parent_workflow_node_id number DEFAULT 0 NOT NULL, + workflow_task_batch_id number DEFAULT 0 NOT NULL, + task_batch_status smallint DEFAULT 0 NOT NULL, + operation_reason smallint DEFAULT 0 NOT NULL, + execution_at number DEFAULT 0 NOT NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + parent_id varchar2(64) DEFAULT '' NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_task_batch + ADD CONSTRAINT pk_sj_job_task_batch PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt); +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON COLUMN sj_job_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task_batch.job_id IS '任务id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '工作流任务父批次id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '工作流任务批次id'; +COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task_batch IS '任务批次'; + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + business_id number NOT NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL, + success_num number DEFAULT 0 NOT NULL, + fail_num number DEFAULT 0 NOT NULL, + fail_reason varchar2(512) DEFAULT '' NULL, + stop_num number DEFAULT 0 NOT NULL, + stop_reason varchar2(512) DEFAULT '' NULL, + cancel_num number DEFAULT 0 NOT NULL, + cancel_reason varchar2(512) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_summary + ADD CONSTRAINT pk_sj_job_summary PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id); + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id); + +COMMENT ON COLUMN sj_job_summary.id IS '主键'; +COMMENT ON COLUMN sj_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_summary.business_id IS '业务id ( job_id或workflow_id ) '; +COMMENT ON COLUMN sj_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.cancel_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job'; + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + scene_name varchar2(50) DEFAULT '' NULL, + trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL, + running_num number DEFAULT 0 NOT NULL, + finish_num number DEFAULT 0 NOT NULL, + max_count_num number DEFAULT 0 NOT NULL, + suspend_num number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_summary + ADD CONSTRAINT pk_sj_retry_summary PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at); + +COMMENT ON COLUMN sj_retry_summary.id IS '主键'; +COMMENT ON COLUMN sj_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN sj_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN sj_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN sj_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN sj_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry'; + +-- sj_workflow +CREATE TABLE sj_workflow +( + id number GENERATED ALWAYS AS IDENTITY, + workflow_name varchar2(64) NULL, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + workflow_status smallint DEFAULT 1 NOT NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar2(255) NULL, + next_trigger_at number NOT NULL, + block_strategy smallint DEFAULT 1 NOT NULL, + executor_timeout number DEFAULT 0 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + bucket_index number DEFAULT 0 NOT NULL, + version number NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow + ADD CONSTRAINT pk_sj_workflow PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt); +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow.id IS '主键'; +COMMENT ON COLUMN sj_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN sj_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_workflow.description IS '描述'; +COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; +COMMENT ON COLUMN sj_workflow.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_workflow.version IS '版本号'; +COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow IS '工作流'; + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + node_name varchar2(64) NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + workflow_id number NOT NULL, + node_type smallint DEFAULT 1 NOT NULL, + expression_type smallint DEFAULT 0 NOT NULL, + fail_strategy smallint DEFAULT 1 NOT NULL, + workflow_node_status smallint DEFAULT 1 NOT NULL, + priority_level number DEFAULT 1 NOT NULL, + node_info clob DEFAULT NULL NULL, + version number NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow_node + ADD CONSTRAINT pk_sj_workflow_node PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt); +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_node.id IS '主键'; +COMMENT ON COLUMN sj_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN sj_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN sj_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN sj_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN sj_workflow_node.node_info IS '节点信息 '; +COMMENT ON COLUMN sj_workflow_node.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_node IS '工作流节点'; + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + workflow_id number NOT NULL, + task_batch_status smallint DEFAULT 0 NOT NULL, + operation_reason smallint DEFAULT 0 NOT NULL, + flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + execution_at number DEFAULT 0 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + version number DEFAULT 1 NOT NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow_task_batch + ADD CONSTRAINT pk_sj_workflow_task_batch PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt); +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; +COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_task_batch IS '工作流批次'; diff --git a/script/sql/oracle/oracle_ry_vue_5.X.sql b/script/sql/oracle/oracle_ry_vue_5.X.sql new file mode 100644 index 0000000..94024c9 --- /dev/null +++ b/script/sql/oracle/oracle_ry_vue_5.X.sql @@ -0,0 +1,1391 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id number(20) not null, + user_id number(20) not null, + tenant_id varchar2(20) default '000000', + auth_id varchar2(255) not null, + source varchar2(255) not null, + open_id varchar2(255) default null, + user_name varchar2(30) not null, + nick_name varchar2(30) default '', + email varchar2(255) default '', + avatar varchar2(500) default '', + access_token varchar2(255) not null, + expire_in number(20) default null, + refresh_token varchar2(255) default null, + access_code varchar2(255) default null, + union_id varchar2(255) default null, + scope varchar2(255) default null, + token_type varchar2(255) default null, + id_token varchar2(2000) default null, + mac_algorithm varchar2(255) default null, + mac_key varchar2(255) default null, + code varchar2(255) default null, + oauth_token varchar2(255) default null, + oauth_token_secret varchar2(255) default null, + create_dept number(20), + create_by number(20), + create_time date, + update_by number(20), + update_time date, + del_flag char(1) default '0' +); + +alter table sys_social add constraint pk_sys_social primary key (id); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 1代表删除)'; + +-- ---------------------------- +-- 租户表 +-- ---------------------------- +create table sys_tenant ( + id number(20) not null, + tenant_id varchar2(20) not null, + contact_user_name varchar2(20) default '', + contact_phone varchar2(20) default '', + company_name varchar2(50) default '', + license_number varchar2(30) default '', + address varchar2(200) default '', + intro varchar2(200) default '', + domain varchar2(200) default '', + remark varchar2(200) default '', + package_id number(20) default null, + expire_time date default null, + account_count number(4) default -1, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_tenant add constraint pk_sys_tenant primary key (id); + +comment on table sys_tenant is '租户表'; +comment on column sys_tenant.tenant_id is '租户编号'; +comment on column sys_tenant.contact_phone is '联系电话'; +comment on column sys_tenant.company_name is '企业名称'; +comment on column sys_tenant.company_name is '联系人'; +comment on column sys_tenant.license_number is '统一社会信用代码'; +comment on column sys_tenant.address is '地址'; +comment on column sys_tenant.intro is '企业简介'; +comment on column sys_tenant.remark is '备注'; +comment on column sys_tenant.package_id is '租户套餐编号'; +comment on column sys_tenant.expire_time is '过期时间'; +comment on column sys_tenant.account_count is '用户数量(-1不限制)'; +comment on column sys_tenant.status is '租户状态(0正常 1停用)'; +comment on column sys_tenant.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant.create_dept is '创建部门'; +comment on column sys_tenant.create_by is '创建者'; +comment on column sys_tenant.create_time is '创建时间'; +comment on column sys_tenant.update_by is '更新者'; +comment on column sys_tenant.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-租户表数据 +-- ---------------------------- + +insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有限公司', null, null, '多租户通用后台管理管理系统', null, null, null, null, -1, '0', '0', 103, 1, sysdate, null, null); + + +-- ---------------------------- +-- 租户套餐表 +-- ---------------------------- +create table sys_tenant_package ( + package_id number(20) not null, + package_name varchar2(20) default '', + menu_ids varchar2(3000) default '', + remark varchar2(200) default '', + menu_check_strictly number(1) default 1, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_tenant_package add constraint pk_sys_tenant_package primary key (package_id); + +comment on table sys_tenant_package is '租户套餐表'; +comment on column sys_tenant_package.package_id is '租户套餐id'; +comment on column sys_tenant_package.package_name is '套餐名称'; +comment on column sys_tenant_package.menu_ids is '关联菜单id'; +comment on column sys_tenant_package.remark is '备注'; +comment on column sys_tenant_package.status is '状态(0正常 1停用)'; +comment on column sys_tenant_package.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant_package.create_dept is '创建部门'; +comment on column sys_tenant_package.create_by is '创建者'; +comment on column sys_tenant_package.create_time is '创建时间'; +comment on column sys_tenant_package.update_by is '更新者'; +comment on column sys_tenant_package.update_time is '更新时间'; + + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table sys_dept ( + dept_id number(20) not null, + tenant_id varchar2(20) default '000000', + parent_id number(20) default 0, + ancestors varchar2(500) default '', + dept_name varchar2(30) default '', + dept_category varchar2(100) default null, + order_num number(4) default 0, + leader number(20) default null, + phone varchar2(11) default null, + email varchar2(50) default null, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_dept add constraint pk_sys_dept primary key (dept_id); + +comment on table sys_dept is '部门表'; +comment on column sys_dept.dept_id is '部门id'; +comment on column sys_dept.tenant_id is '租户编号'; +comment on column sys_dept.parent_id is '父部门id'; +comment on column sys_dept.ancestors is '祖级列表'; +comment on column sys_dept.dept_name is '部门名称'; +comment on column sys_dept.dept_category is '部门类别编码'; +comment on column sys_dept.order_num is '显示顺序'; +comment on column sys_dept.leader is '负责人'; +comment on column sys_dept.phone is '联系电话'; +comment on column sys_dept.email is '邮箱'; +comment on column sys_dept.status is '部门状态(0正常 1停用)'; +comment on column sys_dept.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_dept.create_dept is '创建部门'; +comment on column sys_dept.create_by is '创建者'; +comment on column sys_dept.create_time is '创建时间'; +comment on column sys_dept.update_by is '更新者'; +comment on column sys_dept.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- + +insert into sys_dept values(100, '000000', 0, '0', 'XXX科技', null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(101, '000000', 100, '0,100', '深圳总公司', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(102, '000000', 100, '0,100', '长沙分公司', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(103, '000000', 101, '0,100,101', '研发部门', null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(104, '000000', 101, '0,100,101', '市场部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(105, '000000', 101, '0,100,101', '测试部门', null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(106, '000000', 101, '0,100,101', '财务部门', null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(107, '000000', 101, '0,100,101', '运维部门', null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(108, '000000', 102, '0,100,102', '市场部门', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table sys_user ( + user_id number(20) not null, + tenant_id varchar2(20) default '000000', + dept_id number(20) default null, + user_name varchar2(40) not null, + nick_name varchar2(40) not null, + user_type varchar2(10) default 'sys_user', + email varchar2(50) default '', + phonenumber varchar2(11) default '', + sex char(1) default '0', + avatar number(20) default null, + password varchar2(100) default '', + status char(1) default '0', + del_flag char(1) default '0', + login_ip varchar2(128) default '', + login_date date, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default '' +); + +alter table sys_user add constraint pk_sys_user primary key (user_id); + +comment on table sys_user is '用户信息表'; +comment on column sys_user.user_id is '用户ID'; +comment on column sys_user.tenant_id is '租户编号'; +comment on column sys_user.dept_id is '部门ID'; +comment on column sys_user.user_name is '用户账号'; +comment on column sys_user.nick_name is '用户昵称'; +comment on column sys_user.user_type is '用户类型(sys_user系统用户)'; +comment on column sys_user.email is '用户邮箱'; +comment on column sys_user.phonenumber is '手机号码'; +comment on column sys_user.sex is '用户性别(0男 1女 2未知)'; +comment on column sys_user.avatar is '头像路径'; +comment on column sys_user.password is '密码'; +comment on column sys_user.status is '帐号状态(0正常 1停用)'; +comment on column sys_user.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_user.login_ip is '最后登录IP'; +comment on column sys_user.login_date is '最后登录时间'; +comment on column sys_user.create_dept is '创建部门'; +comment on column sys_user.create_by is '创建者'; +comment on column sys_user.create_time is '创建时间'; +comment on column sys_user.update_by is '更新者'; +comment on column sys_user.update_time is '更新时间'; +comment on column sys_user.remark is '备注'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '管理员'); +insert into sys_user values(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, ''); +insert into sys_user values(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, ''); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table sys_post ( + post_id number(20) not null, + tenant_id varchar2(20) default '000000', + dept_id number(20) not null, + post_code varchar2(64) not null, + post_category varchar2(64) default null, + post_name varchar2(50) not null, + post_sort number(4) not null, + status char(1) not null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) +); + +alter table sys_post add constraint pk_sys_post primary key (post_id); + +comment on table sys_post is '岗位信息表'; +comment on column sys_post.post_id is '岗位ID'; +comment on column sys_post.tenant_id is '租户编号'; +comment on column sys_post.dept_id is '部门id'; +comment on column sys_post.post_code is '岗位编码'; +comment on column sys_post.post_category is '岗位类别编码'; +comment on column sys_post.post_name is '岗位名称'; +comment on column sys_post.post_sort is '显示顺序'; +comment on column sys_post.status is '状态(0正常 1停用)'; +comment on column sys_post.create_dept is '创建部门'; +comment on column sys_post.create_by is '创建者'; +comment on column sys_post.create_time is '创建时间'; +comment on column sys_post.update_by is '更新者'; +comment on column sys_post.update_time is '更新时间'; +comment on column sys_post.remark is '备注'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, '000000', 103, 'ceo', null, '董事长', 1, '0', 103, 1, sysdate, null, null, ''); +insert into sys_post values(2, '000000', 100, 'se', null, '项目经理', 2, '0', 103, 1, sysdate, null, null, ''); +insert into sys_post values(3, '000000', 100, 'hr', null, '人力资源', 3, '0', 103, 1, sysdate, null, null, ''); +insert into sys_post values(4, '000000', 100, 'user', null, '普通员工', 4, '0', 103, 1, sysdate, null, null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table sys_role ( + role_id number(20) not null, + tenant_id varchar2(20) default '000000', + role_name varchar2(30) not null, + role_key varchar2(100) not null, + role_sort number(4) not null, + data_scope char(1) default '1', + menu_check_strictly number(1) default 1, + dept_check_strictly number(1) default 1, + status char(1) not null, + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_role add constraint pk_sys_role primary key (role_id); + +comment on table sys_role is '角色信息表'; +comment on column sys_role.role_id is '角色ID'; +comment on column sys_role.tenant_id is '租户编号'; +comment on column sys_role.role_name is '角色名称'; +comment on column sys_role.role_key is '角色权限字符串'; +comment on column sys_role.role_sort is '显示顺序'; +comment on column sys_role.data_scope is '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +comment on column sys_role.menu_check_strictly is '菜单树选择项是否关联显示'; +comment on column sys_role.dept_check_strictly is '部门树选择项是否关联显示'; +comment on column sys_role.status is '角色状态(0正常 1停用)'; +comment on column sys_role.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_role.create_dept is '创建部门'; +comment on column sys_role.create_by is '创建者'; +comment on column sys_role.create_time is '创建时间'; +comment on column sys_role.update_by is '更新者'; +comment on column sys_role.update_time is '更新时间'; +comment on column sys_role.remark is '备注'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values('1', '000000', '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 103, 1, sysdate, null, null, '超级管理员'); +insert into sys_role values('3', '000000', '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate, null, null, null); +insert into sys_role values('4', '000000', '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate, null, null, null); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table sys_menu ( + menu_id number(20) not null, + menu_name varchar2(50) not null, + parent_id number(20) default 0, + order_num number(4) default 0, + path varchar2(200) default '', + component varchar2(255) default null, + query_param varchar2(255) default null, + is_frame number(1) default 1, + is_cache number(1) default 0, + menu_type char(1) default '', + visible char(1) default 0, + status char(1) default 0, + perms varchar2(100) default null, + icon varchar2(100) default '#', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date , + remark varchar2(500) default '' +); + +alter table sys_menu add constraint pk_sys_menu primary key (menu_id); + +comment on table sys_menu is '菜单权限表'; +comment on column sys_menu.menu_id is '菜单ID'; +comment on column sys_menu.menu_name is '菜单名称'; +comment on column sys_menu.parent_id is '父菜单ID'; +comment on column sys_menu.order_num is '显示顺序'; +comment on column sys_menu.path is '请求地址'; +comment on column sys_menu.component is '路由地址'; +comment on column sys_menu.query_param is '路由参数'; +comment on column sys_menu.is_frame is '是否为外链(0是 1否)'; +comment on column sys_menu.is_cache is '是否缓存(0缓存 1不缓存)'; +comment on column sys_menu.menu_type is '菜单类型(M目录 C菜单 F按钮)'; +comment on column sys_menu.visible is '显示状态(0显示 1隐藏)'; +comment on column sys_menu.status is '菜单状态(0正常 1停用)'; +comment on column sys_menu.perms is '权限标识'; +comment on column sys_menu.icon is '菜单图标'; +comment on column sys_menu.create_dept is '创建部门'; +comment on column sys_menu.create_by is '创建者'; +comment on column sys_menu.create_time is '创建时间'; +comment on column sys_menu.update_by is '更新者'; +comment on column sys_menu.update_time is '更新时间'; +comment on column sys_menu.remark is '备注'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', 1, 0, 'M', '0', '0', '', 'system', 103, 1, sysdate, null, null, '系统管理目录'); +insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', null, '', 1, 0, 'M', '0', '0', '', 'chart', 103, 1, sysdate, null, null, '租户管理目录'); +insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 103, 1, sysdate, null, null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 103, 1, sysdate, null, null, '系统工具目录'); +insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide', 103, 1, sysdate, null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu values('5', '测试菜单', '0', '5', 'demo', null, '', 1, 0, 'M', '0', '0', null, 'star', 103, 1, sysdate, null, null, ''); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 103, 1, sysdate, null, null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, sysdate, null, null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 103, 1, sysdate, null, null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, sysdate, null, null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 103, 1, sysdate, null, null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 103, 1, sysdate, null, null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 103, 1, sysdate, null, null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 103, 1, sysdate, null, null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 103, 1, sysdate, null, null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, sysdate, null, null, '在线用户菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, sysdate, null, null, '缓存监控菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, sysdate, null, null, '代码生成菜单'); +insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', 1, 0, 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, sysdate, null, null, '租户管理菜单'); +insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, sysdate, null, null, '租户套餐管理菜单'); +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate, null, null, '客户端管理菜单'); +-- springboot-admin监控 +insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', 'monitor/admin/index', '', 1, 0, 'C', '0', '0', 'monitor:admin:list', 'dashboard', 103, 1, sysdate, null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, sysdate, null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values('120', '任务调度中心', '2', '5', 'snailjob', 'monitor/snailjob/index', '', 1, 0, 'C', '0', '0', 'monitor:snailjob:list', 'job', 103, 1, sysdate, null, null, 'snailjob控制台菜单'); + +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, sysdate, null, null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 103, 1, sysdate, null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1001', '用户查询', '100', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1002', '用户新增', '100', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1003', '用户修改', '100', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1004', '用户删除', '100', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1005', '用户导出', '100', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1006', '用户导入', '100', '6', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1007', '重置密码', '100', '7', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 103, 1, sysdate, null, null, ''); +-- 角色管理按钮 +insert into sys_menu values('1008', '角色查询', '101', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1009', '角色新增', '101', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1010', '角色修改', '101', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1011', '角色删除', '101', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1012', '角色导出', '101', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 103, 1, sysdate, null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 103, 1, sysdate, null, null, ''); +-- 部门管理按钮 +insert into sys_menu values('1017', '部门查询', '103', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1018', '部门新增', '103', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1019', '部门修改', '103', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1020', '部门删除', '103', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 103, 1, sysdate, null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 103, 1, sysdate, null, null, ''); +-- 字典管理按钮 +insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 103, 1, sysdate, null, null, ''); +-- 参数设置按钮 +insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 103, 1, sysdate, null, null, ''); +-- 通知公告按钮 +insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 103, 1, sysdate, null, null, ''); +-- 操作日志按钮 +insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 103, 1, sysdate, null, null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate, null, null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, sysdate, null, null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 103, 1, sysdate, null, null, ''); +-- oss相关按钮 +insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, sysdate, null, null, ''); +-- 租户管理相关按钮 +insert into sys_menu values('1606', '租户查询', '121', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1607', '租户新增', '121', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1608', '租户修改', '121', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1609', '租户删除', '121', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1610', '租户导出', '121', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:export', '#', 103, 1, sysdate, null, null, ''); +-- 租户套餐管理相关按钮 +insert into sys_menu values('1611', '租户套餐查询', '122', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1612', '租户套餐新增', '122', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1613', '租户套餐修改', '122', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1614', '租户套餐删除', '122', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1615', '租户套餐导出', '122', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:export', '#', 103, 1, sysdate, null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate, null, null, ''); +-- 测试菜单 +insert into sys_menu values('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate, null, null, '测试单表菜单'); +insert into sys_menu values('1501', '测试单表查询', '1500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1502', '测试单表新增', '1500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1503', '测试单表修改', '1500', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1504', '测试单表删除', '1500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1505', '测试单表导出', '1500', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate, null, null, '测试树表菜单'); +insert into sys_menu values('1507', '测试树表查询', '1506', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1508', '测试树表新增', '1506', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1509', '测试树表修改', '1506', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1510', '测试树表删除', '1506', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1511', '测试树表导出', '1506', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate, null, null, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table sys_user_role ( + user_id number(20) not null, + role_id number(20) not null +); + +alter table sys_user_role add constraint pk_sys_user_role primary key (user_id, role_id); + +comment on table sys_user_role is '用户和角色关联表'; +comment on column sys_user_role.user_id is '用户ID'; +comment on column sys_user_role.role_id is '角色ID'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table sys_role_menu ( + role_id number(20) not null, + menu_id number(20) not null +); + +alter table sys_role_menu add constraint pk_sys_role_menu primary key (role_id, menu_id); + +comment on table sys_role_menu is '角色和菜单关联表'; +comment on column sys_role_menu.role_id is '角色ID'; +comment on column sys_role_menu.menu_id is '菜单ID'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '118'); +insert into sys_role_menu values ('3', '123'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1050'); +insert into sys_role_menu values ('3', '1061'); +insert into sys_role_menu values ('3', '1062'); +insert into sys_role_menu values ('3', '1063'); +insert into sys_role_menu values ('3', '1064'); +insert into sys_role_menu values ('3', '1065'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('3', '1600'); +insert into sys_role_menu values ('3', '1601'); +insert into sys_role_menu values ('3', '1602'); +insert into sys_role_menu values ('3', '1603'); +insert into sys_role_menu values ('3', '1620'); +insert into sys_role_menu values ('3', '1621'); +insert into sys_role_menu values ('3', '1622'); +insert into sys_role_menu values ('3', '1623'); +insert into sys_role_menu values ('3', '11618'); +insert into sys_role_menu values ('3', '11619'); +insert into sys_role_menu values ('3', '11629'); +insert into sys_role_menu values ('3', '11632'); +insert into sys_role_menu values ('3', '11633'); +insert into sys_role_menu values ('3', '11638'); +insert into sys_role_menu values ('3', '11639'); +insert into sys_role_menu values ('3', '11640'); +insert into sys_role_menu values ('3', '11641'); +insert into sys_role_menu values ('3', '11642'); +insert into sys_role_menu values ('3', '11643'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table sys_role_dept ( + role_id number(20) not null, + dept_id number(20) not null +); + +alter table sys_role_dept add constraint pk_sys_role_dept primary key (role_id, dept_id); + +comment on table sys_role_dept is '角色和部门关联表'; +comment on column sys_role_dept.role_id is '角色ID'; +comment on column sys_role_dept.dept_id is '部门ID'; + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table sys_user_post ( + user_id number(20) not null, + post_id number(20) not null +); + +alter table sys_user_post add constraint pk_sys_user_post primary key (user_id, post_id); + +comment on table sys_user_post is '用户与岗位关联表'; +comment on column sys_user_post.user_id is '用户ID'; +comment on column sys_user_post.post_id is '岗位ID'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table sys_oper_log ( + oper_id number(20) not null, + tenant_id varchar2(20) default '000000', + title varchar2(50) default '', + business_type number(2) default 0, + method varchar2(100) default '', + request_method varchar2(10) default '', + operator_type number(1) default 0, + oper_name varchar2(50) default '', + dept_name varchar2(50) default '', + oper_url varchar2(255) default '', + oper_ip varchar2(128) default '', + oper_location varchar2(255) default '', + oper_param varchar2(4000) default '', + json_result varchar2(4000) default '', + status number(1) default 0, + error_msg varchar2(4000) default '', + oper_time date, + cost_time number(20) default 0 +); + +alter table sys_oper_log add constraint pk_sys_oper_log primary key (oper_id); +create index idx_sys_oper_log_bt on sys_oper_log (business_type); +create index idx_sys_oper_log_s on sys_oper_log (status); +create index idx_sys_oper_log_ot on sys_oper_log (oper_time); + +comment on table sys_oper_log is '操作日志记录'; +comment on column sys_oper_log.oper_id is '日志主键'; +comment on column sys_oper_log.tenant_id is '租户编号'; +comment on column sys_oper_log.title is '模块标题'; +comment on column sys_oper_log.business_type is '业务类型(0其它 1新增 2修改 3删除)'; +comment on column sys_oper_log.method is '方法名称'; +comment on column sys_oper_log.request_method is '请求方式'; +comment on column sys_oper_log.operator_type is '操作类别(0其它 1后台用户 2手机端用户)'; +comment on column sys_oper_log.oper_name is '操作人员'; +comment on column sys_oper_log.dept_name is '部门名称'; +comment on column sys_oper_log.oper_url is '请求URL'; +comment on column sys_oper_log.oper_ip is '主机地址'; +comment on column sys_oper_log.oper_location is '操作地点'; +comment on column sys_oper_log.oper_param is '请求参数'; +comment on column sys_oper_log.json_result is '返回参数'; +comment on column sys_oper_log.status is '操作状态(0正常 1异常)'; +comment on column sys_oper_log.error_msg is '错误消息'; +comment on column sys_oper_log.oper_time is '操作时间'; +comment on column sys_oper_log.cost_time is '消耗时间'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table sys_dict_type ( + dict_id number(20) not null, + tenant_id varchar2(20) default '000000', + dict_name varchar2(100) default '', + dict_type varchar2(100) default '', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_dict_type add constraint pk_sys_dict_type primary key (dict_id); +create unique index sys_dict_type_index1 on sys_dict_type (tenant_id, dict_type); + +comment on table sys_dict_type is '字典类型表'; +comment on column sys_dict_type.dict_id is '字典主键'; +comment on column sys_dict_type.tenant_id is '租户编号'; +comment on column sys_dict_type.dict_name is '字典名称'; +comment on column sys_dict_type.dict_type is '字典类型'; +comment on column sys_dict_type.create_dept is '创建部门'; +comment on column sys_dict_type.create_by is '创建者'; +comment on column sys_dict_type.create_time is '创建时间'; +comment on column sys_dict_type.update_by is '更新者'; +comment on column sys_dict_type.update_time is '更新时间'; +comment on column sys_dict_type.remark is '备注'; + +insert into sys_dict_type values(1, '000000', '用户性别', 'sys_user_sex', 103, 1, sysdate, null, null, '用户性别列表'); +insert into sys_dict_type values(2, '000000', '菜单状态', 'sys_show_hide', 103, 1, sysdate, null, null, '菜单状态列表'); +insert into sys_dict_type values(3, '000000', '系统开关', 'sys_normal_disable', 103, 1, sysdate, null, null, '系统开关列表'); +insert into sys_dict_type values(6, '000000', '系统是否', 'sys_yes_no', 103, 1, sysdate, null, null, '系统是否列表'); +insert into sys_dict_type values(7, '000000', '通知类型', 'sys_notice_type', 103, 1, sysdate, null, null, '通知类型列表'); +insert into sys_dict_type values(8, '000000', '通知状态', 'sys_notice_status', 103, 1, sysdate, null, null, '通知状态列表'); +insert into sys_dict_type values(9, '000000', '操作类型', 'sys_oper_type', 103, 1, sysdate, null, null, '操作类型列表'); +insert into sys_dict_type values(10, '000000', '系统状态', 'sys_common_status', 103, 1, sysdate, null, null, '登录状态列表'); +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, sysdate, null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, sysdate, null, null, '客户端设备类型'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table sys_dict_data ( + dict_code number(20) not null, + tenant_id varchar2(20) default '000000', + dict_sort number(4) default 0, + dict_label varchar2(100) default '', + dict_value varchar2(100) default '', + dict_type varchar2(100) default '', + css_class varchar2(100) default null, + list_class varchar2(100) default null, + is_default char(1) default 'N', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_dict_data add constraint pk_sys_dict_data primary key (dict_code); + +comment on table sys_dict_data is '字典数据表'; +comment on column sys_dict_data.dict_code is '字典主键'; +comment on column sys_dict_data.tenant_id is '租户编号'; +comment on column sys_dict_data.dict_sort is '字典排序'; +comment on column sys_dict_data.dict_label is '字典标签'; +comment on column sys_dict_data.dict_value is '字典键值'; +comment on column sys_dict_data.dict_type is '字典类型'; +comment on column sys_dict_data.css_class is '样式属性(其他样式扩展)'; +comment on column sys_dict_data.list_class is '表格回显样式'; +comment on column sys_dict_data.is_default is '是否默认(Y是 N否)'; +comment on column sys_dict_data.create_dept is '创建部门'; +comment on column sys_dict_data.create_by is '创建者'; +comment on column sys_dict_data.create_time is '创建时间'; +comment on column sys_dict_data.update_by is '更新者'; +comment on column sys_dict_data.update_time is '更新时间'; +comment on column sys_dict_data.remark is '备注'; + +insert into sys_dict_data values(1, '000000', 1, '男', '0', 'sys_user_sex', '', '', 'Y', 103, 1, sysdate, null, null, '性别男'); +insert into sys_dict_data values(2, '000000', 2, '女', '1', 'sys_user_sex', '', '', 'N', 103, 1, sysdate, null, null, '性别女'); +insert into sys_dict_data values(3, '000000', 3, '未知', '2', 'sys_user_sex', '', '', 'N', 103, 1, sysdate, null, null, '性别未知'); +insert into sys_dict_data values(4, '000000', 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 103, 1, sysdate, null, null, '显示菜单'); +insert into sys_dict_data values(5, '000000', 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 103, 1, sysdate, null, null, '隐藏菜单'); +insert into sys_dict_data values(6, '000000', 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 103, 1, sysdate, null, null, '正常状态'); +insert into sys_dict_data values(7, '000000', 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 103, 1, sysdate, null, null, '停用状态'); +insert into sys_dict_data values(12, '000000', 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 103, 1, sysdate, null, null, '系统默认是'); +insert into sys_dict_data values(13, '000000', 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 103, 1, sysdate, null, null, '系统默认否'); +insert into sys_dict_data values(14, '000000', 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 103, 1, sysdate, null, null, '通知'); +insert into sys_dict_data values(15, '000000', 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 103, 1, sysdate, null, null, '公告'); +insert into sys_dict_data values(16, '000000', 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 103, 1, sysdate, null, null, '正常状态'); +insert into sys_dict_data values(17, '000000', 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 103, 1, sysdate, null, null, '关闭状态'); +insert into sys_dict_data values(29, '000000', 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate, null, null, '其他操作'); +insert into sys_dict_data values(18, '000000', 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate, null, null, '新增操作'); +insert into sys_dict_data values(19, '000000', 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate, null, null, '修改操作'); +insert into sys_dict_data values(20, '000000', 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate, null, null, '删除操作'); +insert into sys_dict_data values(21, '000000', 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 103, 1, sysdate, null, null, '授权操作'); +insert into sys_dict_data values(22, '000000', 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate, null, null, '导出操作'); +insert into sys_dict_data values(23, '000000', 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate, null, null, '导入操作'); +insert into sys_dict_data values(24, '000000', 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate, null, null, '强退操作'); +insert into sys_dict_data values(25, '000000', 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate, null, null, '生成操作'); +insert into sys_dict_data values(26, '000000', 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate, null, null, '清空操作'); +insert into sys_dict_data values(27, '000000', 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 103, 1, sysdate, null, null, '正常状态'); +insert into sys_dict_data values(28, '000000', 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 103, 1, sysdate, null, null, '停用状态'); +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table sys_config ( + config_id number(20) not null, + tenant_id varchar2(20) default '000000', + config_name varchar2(100) default '', + config_key varchar2(100) default '', + config_value varchar2(100) default '', + config_type char(1) default 'N', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); +alter table sys_config add constraint pk_sys_config primary key (config_id); + +comment on table sys_config is '参数配置表'; +comment on column sys_config.config_id is '参数主键'; +comment on column sys_config.tenant_id is '租户编号'; +comment on column sys_config.config_name is '参数名称'; +comment on column sys_config.config_key is '参数键名'; +comment on column sys_config.config_value is '参数键值'; +comment on column sys_config.config_type is '系统内置(Y是 N否)'; +comment on column sys_config.create_dept is '创建部门'; +comment on column sys_config.create_by is '创建者'; +comment on column sys_config.create_time is '创建时间'; +comment on column sys_config.update_by is '更新者'; +comment on column sys_config.update_time is '更新时间'; +comment on column sys_config.remark is '备注'; + +insert into sys_config values(1, '000000', '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 103, 1, sysdate, null, null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '000000', '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 103, 1, sysdate, null, null, '初始化密码 123456' ); +insert into sys_config values(3, '000000', '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 103, 1, sysdate, null, null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(5, '000000', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 103, 1, sysdate, null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(11, '000000', 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 103, 1, sysdate, null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table sys_logininfor ( + info_id number(20) not null, + tenant_id varchar2(20) default '000000', + user_name varchar2(50) default '', + client_key varchar2(32) default '', + device_type varchar2(32) default '', + ipaddr varchar2(128) default '', + login_location varchar2(255) default '', + browser varchar2(50) default '', + os varchar2(50) default '', + status char(1) default '0', + msg varchar2(255) default '', + login_time date +); + +alter table sys_logininfor add constraint pk_sys_logininfor primary key (info_id); +create index idx_sys_logininfor_s on sys_logininfor (status); +create index idx_sys_logininfor_lt on sys_logininfor (login_time); + +comment on table sys_logininfor is '系统访问记录'; +comment on column sys_logininfor.info_id is '访问ID'; +comment on column sys_logininfor.tenant_id is '租户编号'; +comment on column sys_logininfor.user_name is '登录账号'; +comment on column sys_logininfor.client_key is '客户端'; +comment on column sys_logininfor.device_type is '设备类型'; +comment on column sys_logininfor.ipaddr is '登录IP地址'; +comment on column sys_logininfor.login_location is '登录地点'; +comment on column sys_logininfor.browser is '浏览器类型'; +comment on column sys_logininfor.os is '操作系统'; +comment on column sys_logininfor.status is '登录状态(0成功 1失败)'; +comment on column sys_logininfor.msg is '提示消息'; +comment on column sys_logininfor.login_time is '访问时间'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table sys_notice ( + notice_id number(20) not null, + tenant_id varchar2(20) default '000000', + notice_title varchar2(50) not null, + notice_type char(1) not null, + notice_content clob default null, + status char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(255) default null +); + +alter table sys_notice add constraint pk_sys_notice primary key (notice_id); + +comment on table sys_notice is '通知公告表'; +comment on column sys_notice.notice_id is '公告主键'; +comment on column sys_notice.tenant_id is '租户编号'; +comment on column sys_notice.notice_title is '公告标题'; +comment on column sys_notice.notice_type is '公告类型(1通知 2公告)'; +comment on column sys_notice.notice_content is '公告内容'; +comment on column sys_notice.status is '公告状态(0正常 1关闭)'; +comment on column sys_notice.create_dept is '创建部门'; +comment on column sys_notice.create_by is '创建者'; +comment on column sys_notice.create_time is '创建时间'; +comment on column sys_notice.update_by is '更新者'; +comment on column sys_notice.update_time is '更新时间'; +comment on column sys_notice.remark is '备注'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '000000', '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 103, 1, sysdate, null, null, '管理员'); +insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 103, 1, sysdate, null, null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +create table gen_table ( + table_id number(20) not null, + data_name varchar2(200) default '', + table_name varchar2(200) default '', + table_comment varchar2(500) default '', + sub_table_name varchar2(64) default null, + sub_table_fk_name varchar2(64) default null, + class_name varchar2(100) default '', + tpl_category varchar2(200) default 'crud', + package_name varchar2(100), + module_name varchar2(30), + business_name varchar2(30), + function_name varchar2(50), + function_author varchar2(50), + gen_type char(1) default '0', + gen_path varchar2(200) default '/', + options varchar2(1000), + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table gen_table add constraint pk_gen_table primary key (table_id); + +comment on table gen_table is '代码生成业务表'; +comment on column gen_table.table_id is '编号'; +comment on column gen_table.data_name is '数据源名称'; +comment on column gen_table.table_name is '表名称'; +comment on column gen_table.table_comment is '表描述'; +comment on column gen_table.sub_table_name is '关联子表的表名'; +comment on column gen_table.sub_table_fk_name is '子表关联的外键名'; +comment on column gen_table.class_name is '实体类名称'; +comment on column gen_table.tpl_category is '使用的模板(crud单表操作 tree树表操作)'; +comment on column gen_table.package_name is '生成包路径'; +comment on column gen_table.module_name is '生成模块名'; +comment on column gen_table.business_name is '生成业务名'; +comment on column gen_table.function_name is '生成功能名'; +comment on column gen_table.function_author is '生成功能作者'; +comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)'; +comment on column gen_table.gen_path is '生成路径(不填默认项目路径)'; +comment on column gen_table.options is '其它生成选项'; +comment on column gen_table.create_dept is '创建部门'; +comment on column gen_table.create_by is '创建者'; +comment on column gen_table.create_time is '创建时间'; +comment on column gen_table.update_by is '更新者'; +comment on column gen_table.update_time is '更新时间'; +comment on column gen_table.remark is '备注'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +create table gen_table_column ( + column_id number(20) not null, + table_id number(20), + column_name varchar2(200), + column_comment varchar2(500), + column_type varchar2(100), + java_type varchar2(500), + java_field varchar2(200), + is_pk char(1), + is_increment char(1), + is_required char(1), + is_insert char(1), + is_edit char(1), + is_list char(1), + is_query char(1), + query_type varchar2(200) default 'EQ', + html_type varchar2(200), + dict_type varchar2(200) default '', + sort number(4), + create_dept number(20) default null, + create_by number(20) default null, + create_time date , + update_by number(20) default null, + update_time date +); + +alter table gen_table_column add constraint pk_gen_table_column primary key (column_id); + +comment on table gen_table_column is '代码生成业务表字段'; +comment on column gen_table_column.column_id is '编号'; +comment on column gen_table_column.table_id is '归属表编号'; +comment on column gen_table_column.column_name is '列名称'; +comment on column gen_table_column.column_comment is '列描述'; +comment on column gen_table_column.column_type is '列类型'; +comment on column gen_table_column.java_type is 'JAVA类型'; +comment on column gen_table_column.java_field is 'JAVA字段名'; +comment on column gen_table_column.is_pk is '是否主键(1是)'; +comment on column gen_table_column.is_increment is '是否自增(1是)'; +comment on column gen_table_column.is_required is '是否必填(1是)'; +comment on column gen_table_column.is_insert is '是否为插入字段(1是)'; +comment on column gen_table_column.is_edit is '是否编辑字段(1是)'; +comment on column gen_table_column.is_list is '是否列表字段(1是)'; +comment on column gen_table_column.is_query is '是否查询字段(1是)'; +comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)'; +comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)'; +comment on column gen_table_column.dict_type is '字典类型'; +comment on column gen_table_column.sort is '排序'; +comment on column gen_table_column.create_dept is '创建部门'; +comment on column gen_table_column.create_by is '创建者'; +comment on column gen_table_column.create_time is '创建时间'; +comment on column gen_table_column.update_by is '更新者'; +comment on column gen_table_column.update_time is '更新时间'; + + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table sys_oss ( + oss_id number(20) not null, + tenant_id varchar2(20) default '000000', + file_name varchar2(255) not null, + original_name varchar2(255) not null, + file_suffix varchar2(10) not null, + url varchar2(500) not null, + service varchar2(20) default 'minio' not null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_oss add constraint pk_sys_oss primary key (oss_id); + +comment on table sys_oss is 'OSS对象存储表'; +comment on column sys_oss.oss_id is '对象存储主键'; +comment on column sys_oss.tenant_id is '租户编码'; +comment on column sys_oss.file_name is '文件名'; +comment on column sys_oss.original_name is '原名'; +comment on column sys_oss.file_suffix is '文件后缀名'; +comment on column sys_oss.url is 'URL地址'; +comment on column sys_oss.service is '服务商'; +comment on column sys_oss.create_dept is '创建部门'; +comment on column sys_oss.create_time is '创建时间'; +comment on column sys_oss.create_by is '上传者'; +comment on column sys_oss.update_time is '更新时间'; +comment on column sys_oss.update_by is '更新者'; + + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table sys_oss_config ( + oss_config_id number(20) not null, + tenant_id varchar2(20) default '000000', + config_key varchar2(20) not null, + access_key varchar2(255) default '', + secret_key varchar2(255) default '', + bucket_name varchar2(255) default '', + prefix varchar2(255) default '', + endpoint varchar2(255) default '', + domain varchar2(255) default '', + is_https char(1) default 'N', + region varchar2(255) default '', + access_policy char(1) default '1' not null, + status char(1) default '1', + ext1 varchar2(255) default '', + remark varchar2(500) default null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_oss_config add constraint pk_sys_oss_config primary key (oss_config_id); + +comment on table sys_oss_config is '对象存储配置表'; +comment on column sys_oss_config.oss_config_id is '主键'; +comment on column sys_oss_config.tenant_id is '租户编码'; +comment on column sys_oss_config.config_key is '配置key'; +comment on column sys_oss_config.access_key is 'accesskey'; +comment on column sys_oss_config.secret_key is '秘钥'; +comment on column sys_oss_config.bucket_name is '桶名称'; +comment on column sys_oss_config.prefix is '前缀'; +comment on column sys_oss_config.endpoint is '访问站点'; +comment on column sys_oss_config.domain is '自定义域名'; +comment on column sys_oss_config.is_https is '是否https(Y=是,N=否)'; +comment on column sys_oss_config.region is '域'; +comment on column sys_oss_config.access_policy is '桶权限类型(0=private 1=public 2=custom)'; +comment on column sys_oss_config.status is '是否默认(0=是,1=否)'; +comment on column sys_oss_config.ext1 is '扩展字段'; +comment on column sys_oss_config.remark is '备注'; +comment on column sys_oss_config.create_dept is '创建部门'; +comment on column sys_oss_config.create_by is '创建者'; +comment on column sys_oss_config.create_time is '创建时间'; +comment on column sys_oss_config.update_by is '更新者'; +comment on column sys_oss_config.update_time is '更新时间'; + +insert into sys_oss_config values (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '','N', '', '1', '0', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1250000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '','N', '', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id number(20) not null, + client_id varchar2(64) default null, + client_key varchar2(32) default null, + client_secret varchar2(255) default null, + grant_type varchar2(255) default null, + device_type varchar2(32) default null, + active_timeout number(11) default 1800, + timeout number(11) default 604800, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_client add constraint pk_sys_client primary key (id); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); + +create table test_demo ( + id number(20) not null, + tenant_id varchar2(20) default '000000', + dept_id number(20) default null, + user_id number(20) default null, + order_num number(10) default 0, + test_key varchar2(255) default null, + value varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_demo add constraint pk_test_demo primary key (id); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.tenant_id is '租户编号'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table test_tree ( + id number(20) not null, + tenant_id varchar2(20) default '000000', + parent_id number(20) default 0, + dept_id number(20) default null, + user_id number(20) default null, + tree_name varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_tree add constraint pk_test_tree primary key (id); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.tenant_id is '租户编号'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +insert into test_demo values (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate, 1, null, null, 0); + +insert into test_tree values (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate, 1, null, null, 0); + + +-- ---------------------------- +-- 钩子 ,用于session连接之后 自动设置默认的date类型格式化 简化时间查询 +-- 如需设置其它配置 可在此钩子内任意增加处理语句 +-- 例如: SELECT * FROM sys_user WHERE create_time BETWEEN '2022-03-01 00:00:00' AND '2022-04-01 00:00:00' +-- ---------------------------- +create or replace trigger login_trg +after logon on database +begin +execute immediate 'alter session set nls_date_format=''YYYY-MM-DD HH24:MI:SS'''; +end; diff --git a/script/sql/oracle/oracle_ry_workflow.sql b/script/sql/oracle/oracle_ry_workflow.sql new file mode 100644 index 0000000..b515b78 --- /dev/null +++ b/script/sql/oracle/oracle_ry_workflow.sql @@ -0,0 +1,414 @@ +create table FLOW_DEFINITION +( + ID NUMBER(20) not null, + FLOW_CODE VARCHAR2(40) not null, + FLOW_NAME VARCHAR2(100) not null, + CATEGORY VARCHAR2(100), + VERSION VARCHAR2(20) not null, + IS_PUBLISH NUMBER(1) default 0 not null, + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + ACTIVITY_STATUS NUMBER(1) default 1, + LISTENER_TYPE VARCHAR2(100), + LISTENER_PATH VARCHAR2(500), + EXT VARCHAR2(500), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_DEFINITION add constraint PK_FLOW_DEFINITION primary key (ID); + +comment on table FLOW_DEFINITION is '流程定义表'; +comment on column FLOW_DEFINITION.ID is '主键id'; +comment on column FLOW_DEFINITION.FLOW_CODE is '流程编码'; +comment on column FLOW_DEFINITION.FLOW_NAME is '流程名称'; +comment on column FLOW_DEFINITION.CATEGORY is '流程类别'; +comment on column FLOW_DEFINITION.VERSION is '流程版本'; +comment on column FLOW_DEFINITION.IS_PUBLISH is '是否发布 (0未发布 1已发布 9失效)'; +comment on column FLOW_DEFINITION.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_DEFINITION.FORM_PATH is '审批表单路径'; +comment on column FLOW_DEFINITION.ACTIVITY_STATUS is '流程激活状态(0挂起 1激活)'; +comment on column FLOW_DEFINITION.LISTENER_TYPE is '监听器类型'; +comment on column FLOW_DEFINITION.LISTENER_PATH is '监听器路径'; +comment on column FLOW_DEFINITION.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_DEFINITION.CREATE_TIME is '创建时间'; +comment on column FLOW_DEFINITION.UPDATE_TIME is '更新时间'; +comment on column FLOW_DEFINITION.DEL_FLAG is '删除标志'; +comment on column FLOW_DEFINITION.TENANT_ID is '租户id'; + +create table FLOW_NODE +( + ID NUMBER(20) not null, + NODE_TYPE NUMBER(1) not null, + DEFINITION_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100) not null, + NODE_NAME VARCHAR2(100), + NODE_RATIO NUMBER(6, 3), + COORDINATE VARCHAR2(100), + SKIP_ANY_NODE VARCHAR2(100) default 'N', + ANY_NODE_SKIP VARCHAR2(100), + LISTENER_TYPE VARCHAR2(100), + LISTENER_PATH VARCHAR2(500), + HANDLER_TYPE VARCHAR2(100), + HANDLER_PATH VARCHAR2(400), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + VERSION VARCHAR2(20), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40), + PERMISSION_FLAG VARCHAR2(200) +); + +alter table FLOW_NODE add constraint PK_FLOW_NODE primary key (ID); + +comment on table FLOW_NODE is '流程节点表'; +comment on column FLOW_NODE.ID is '主键id'; +comment on column FLOW_NODE.NODE_TYPE is '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_NODE.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_NODE.NODE_CODE is '流程节点编码'; +comment on column FLOW_NODE.NODE_NAME is '流程节点名称'; +comment on column FLOW_NODE.NODE_RATIO is '流程签署比例值'; +comment on column FLOW_NODE.COORDINATE is '坐标'; +comment on column FLOW_NODE.SKIP_ANY_NODE is '是否可以退回任意节点(Y是 N否)即将删除'; +comment on column FLOW_NODE.ANY_NODE_SKIP is '任意结点跳转'; +comment on column FLOW_NODE.LISTENER_TYPE is '监听器类型'; +comment on column FLOW_NODE.LISTENER_PATH is '监听器路径'; +comment on column FLOW_NODE.HANDLER_TYPE is '处理器类型'; +comment on column FLOW_NODE.HANDLER_PATH is '处理器路径'; +comment on column FLOW_NODE.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_NODE.FORM_PATH is '审批表单路径'; +comment on column FLOW_NODE.VERSION is '版本'; +comment on column FLOW_NODE.CREATE_TIME is '创建时间'; +comment on column FLOW_NODE.UPDATE_TIME is '更新时间'; +comment on column FLOW_NODE.DEL_FLAG is '删除标志'; +comment on column FLOW_NODE.TENANT_ID is '租户id'; +comment on column FLOW_NODE.PERMISSION_FLAG is '权限标识(权限类型:权限标识,可以多个,用逗号隔开)'; + +create table FLOW_SKIP +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + NOW_NODE_CODE VARCHAR2(100) not null, + NOW_NODE_TYPE NUMBER(1), + NEXT_NODE_CODE VARCHAR2(100) not null, + NEXT_NODE_TYPE NUMBER(1), + SKIP_NAME VARCHAR2(100), + SKIP_TYPE VARCHAR2(40), + SKIP_CONDITION VARCHAR2(200), + COORDINATE VARCHAR2(100), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_SKIP add constraint PK_FLOW_SKIP primary key (ID); + +comment on table FLOW_SKIP is '节点跳转关联表'; +comment on column FLOW_SKIP.ID is '主键id'; +comment on column FLOW_SKIP.DEFINITION_ID is '流程定义id'; +comment on column FLOW_SKIP.NOW_NODE_CODE is '当前流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.NOW_NODE_TYPE is '下一个流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.NEXT_NODE_CODE is '下一个流程节点编码'; +comment on column FLOW_SKIP.NEXT_NODE_TYPE is '下一个流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.SKIP_NAME is '跳转名称'; +comment on column FLOW_SKIP.SKIP_TYPE is '跳转类型 (PASS审批通过 REJECT退回)'; +comment on column FLOW_SKIP.SKIP_CONDITION is '跳转条件'; +comment on column FLOW_SKIP.COORDINATE is '坐标'; +comment on column FLOW_SKIP.CREATE_TIME is '创建时间'; +comment on column FLOW_SKIP.UPDATE_TIME is '更新时间'; +comment on column FLOW_SKIP.DEL_FLAG is '删除标志'; +comment on column FLOW_SKIP.TENANT_ID is '租户id'; + +create table FLOW_INSTANCE +( + ID NUMBER not null, + DEFINITION_ID NUMBER not null, + BUSINESS_ID VARCHAR2(40) not null, + NODE_TYPE NUMBER(1), + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + VARIABLE CLOB, + FLOW_STATUS VARCHAR2(20), + ACTIVITY_STATUS NUMBER(1) default 1, + DEF_JSON CLOB, + CREATE_BY VARCHAR2(64) default '', + CREATE_TIME DATE, + UPDATE_TIME DATE, + EXT VARCHAR2(500), + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_INSTANCE add constraint PK_FLOW_INSTANCE primary key (ID); + +comment on table FLOW_INSTANCE is '流程实例表'; +comment on column FLOW_INSTANCE.ID is '主键id'; +comment on column FLOW_INSTANCE.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_INSTANCE.BUSINESS_ID is '业务id'; +comment on column FLOW_INSTANCE.NODE_TYPE is '开始节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_INSTANCE.NODE_CODE is '开始节点编码'; +comment on column FLOW_INSTANCE.NODE_NAME is '开始节点名称'; +comment on column FLOW_INSTANCE.VARIABLE is '任务变量'; +comment on column FLOW_INSTANCE.FLOW_STATUS is '流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回 8已完成 9已退回 10失效)'; +comment on column FLOW_INSTANCE.ACTIVITY_STATUS is '流程激活状态(0挂起 1激活)'; +comment on column FLOW_INSTANCE.DEF_JSON is '流程定义json'; +comment on column FLOW_INSTANCE.CREATE_BY is '创建者'; +comment on column FLOW_INSTANCE.CREATE_TIME is '创建时间'; +comment on column FLOW_INSTANCE.UPDATE_TIME is '更新时间'; +comment on column FLOW_INSTANCE.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_INSTANCE.DEL_FLAG is '删除标志'; +comment on column FLOW_INSTANCE.TENANT_ID is '租户id'; + +create table FLOW_TASK +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + INSTANCE_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + NODE_TYPE NUMBER(1), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_TASK add constraint PK_FLOW_TASK primary key (ID); + +comment on table FLOW_TASK is '待办任务表'; +comment on column FLOW_TASK.ID is '主键id'; +comment on column FLOW_TASK.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_TASK.INSTANCE_ID is '对应flow_instance表的id'; +comment on column FLOW_TASK.NODE_CODE is '节点编码'; +comment on column FLOW_TASK.NODE_NAME is '节点名称'; +comment on column FLOW_TASK.NODE_TYPE is '节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_TASK.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_TASK.FORM_PATH is '审批表单路径'; +comment on column FLOW_TASK.CREATE_TIME is '创建时间'; +comment on column FLOW_TASK.UPDATE_TIME is '更新时间'; +comment on column FLOW_TASK.DEL_FLAG is '删除标志'; +comment on column FLOW_TASK.TENANT_ID is '租户id'; + +create table FLOW_HIS_TASK +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + INSTANCE_ID NUMBER(20) not null, + TASK_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + NODE_TYPE NUMBER(1), + TARGET_NODE_CODE VARCHAR2(200), + TARGET_NODE_NAME VARCHAR2(200), + APPROVER VARCHAR2(40), + COOPERATE_TYPE NUMBER(1) default 0, + COLLABORATOR VARCHAR2(40), + SKIP_TYPE VARCHAR2(10), + FLOW_STATUS VARCHAR2(20), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + MESSAGE VARCHAR2(500), + VARIABLE CLOB, + EXT VARCHAR2(500), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) + +); + +alter table FLOW_HIS_TASK add constraint PK_FLOW_HIS_TASK primary key (ID); + +comment on table FLOW_HIS_TASK is '历史任务记录表'; +comment on column FLOW_HIS_TASK.ID is '主键id'; +comment on column FLOW_HIS_TASK.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_HIS_TASK.INSTANCE_ID is '对应flow_instance表的id'; +comment on column FLOW_HIS_TASK.TASK_ID is '对应flow_task表的id'; +comment on column FLOW_HIS_TASK.NODE_CODE is '开始节点编码'; +comment on column FLOW_HIS_TASK.NODE_NAME is '开始节点名称'; +comment on column FLOW_HIS_TASK.NODE_TYPE is '开始节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_HIS_TASK.TARGET_NODE_CODE is '目标节点编码'; +comment on column FLOW_HIS_TASK.TARGET_NODE_NAME is '目标节点名称'; +comment on column FLOW_HIS_TASK.SKIP_TYPE is '流转类型(PASS通过 REJECT退回 NONE无动作)'; +comment on column FLOW_HIS_TASK.FLOW_STATUS is '流程状态(1审批中 2 审批通过 9已退回 10失效)'; +comment on column FLOW_HIS_TASK.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_HIS_TASK.FORM_PATH is '审批表单路径'; +comment on column FLOW_HIS_TASK.MESSAGE is '审批意见'; +comment on column FLOW_HIS_TASK.VARIABLE is '任务变量'; +comment on column FLOW_HIS_TASK.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_HIS_TASK.CREATE_TIME is '任务开始时间'; +comment on column FLOW_HIS_TASK.UPDATE_TIME is '审批完成时间'; +comment on column FLOW_HIS_TASK.DEL_FLAG is '删除标志'; +comment on column FLOW_HIS_TASK.TENANT_ID is '租户id'; +comment on column FLOW_HIS_TASK.APPROVER is '审批者'; +comment on column FLOW_HIS_TASK.COOPERATE_TYPE is '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)'; +comment on column FLOW_HIS_TASK.COLLABORATOR is '协作人'; + +create table FLOW_USER +( + ID NUMBER(20) not null, + TYPE VARCHAR2(1) not null, + PROCESSED_BY VARCHAR2(80), + ASSOCIATED NUMBER(20) not null, + CREATE_TIME DATE, + CREATE_BY VARCHAR2(80), + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_USER add constraint PK_FLOW_USER primary key (ID); + +comment on table FLOW_USER is '待办任务表'; +comment on column FLOW_USER.ID is '主键id'; +comment on column FLOW_USER.TYPE is '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)'; +comment on column FLOW_USER.PROCESSED_BY is '权限人)'; +comment on column FLOW_USER.ASSOCIATED is '任务表id'; +comment on column FLOW_USER.CREATE_TIME is '创建时间'; +comment on column FLOW_USER.CREATE_BY is '节点名称'; +comment on column FLOW_USER.UPDATE_TIME is '更新时间'; +comment on column FLOW_USER.DEL_FLAG is '删除标志'; +comment on column FLOW_USER.TENANT_ID is '租户id'; + +create index USER_PROCESSED_TYPE on FLOW_USER (PROCESSED_BY, TYPE); + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +CREATE TABLE flow_category +( + category_id NUMBER (20) NOT NULL, + tenant_id VARCHAR2 (20) DEFAULT '000000', + parent_id NUMBER (20) DEFAULT 0, + ancestors VARCHAR2 (500) DEFAULT '', + category_name VARCHAR2 (30) NOT NULL, + order_num NUMBER (4) DEFAULT 0, + del_flag CHAR(1) DEFAULT '0', + create_dept NUMBER (20), + create_by NUMBER (20), + create_time DATE, + update_by NUMBER (20), + update_time DATE +); + +alter table flow_category add constraint pk_flow_category primary key (category_id); + +COMMENT ON TABLE flow_category IS '流程分类'; +COMMENT ON COLUMN flow_category.category_id IS '流程分类ID'; +COMMENT ON COLUMN flow_category.tenant_id IS '租户编号'; +COMMENT ON COLUMN flow_category.parent_id IS '父流程分类id'; +COMMENT ON COLUMN flow_category.ancestors IS '祖级列表'; +COMMENT ON COLUMN flow_category.category_name IS '流程分类名称'; +COMMENT ON COLUMN flow_category.order_num IS '显示顺序'; +COMMENT ON COLUMN flow_category.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_category.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_category.create_by IS '创建者'; +COMMENT ON COLUMN flow_category.create_time IS '创建时间'; +COMMENT ON COLUMN flow_category.update_by IS '更新者'; +COMMENT ON COLUMN flow_category.update_time IS '更新时间'; + +INSERT INTO flow_category VALUES (100, '000000', 0, '0', 'OA审批', 0, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (101, '000000', 100, '0,100', '假勤管理', 0, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (102, '000000', 100, '0,100', '人事管理', 1, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (103, '000000', 101, '0,100,101', '请假', 0, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (104, '000000', 101, '0,100,101', '出差', 1, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (105, '000000', 101, '0,100,101', '加班', 2, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (106, '000000', 101, '0,100,101', '换班', 3, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (107, '000000', 101, '0,100,101', '外出', 4, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (108, '000000', 102, '0,100,102', '转正', 1, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (109, '000000', 102, '0,100,102', '离职', 2, '0', 103, 1, SYSDATE, NULL, NULL); + + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +CREATE TABLE test_leave +( + id NUMBER (20) NOT NULL, + tenant_id VARCHAR2 (20) DEFAULT '000000', + leave_type VARCHAR2 (255) NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + leave_days NUMBER (10) NOT NULL, + remark VARCHAR2 (255), + status VARCHAR2 (255), + create_dept NUMBER (20), + create_by NUMBER (20), + create_time DATE, + update_by NUMBER (20), + update_time DATE +); + +alter table test_leave add constraint pk_test_leave primary key (id); + +COMMENT ON TABLE test_leave IS '请假申请表'; +COMMENT ON COLUMN test_leave.id IS 'ID'; +COMMENT ON COLUMN test_leave.tenant_id IS '租户编号'; +COMMENT ON COLUMN test_leave.leave_type IS '请假类型'; +COMMENT ON COLUMN test_leave.start_date IS '开始时间'; +COMMENT ON COLUMN test_leave.end_date IS '结束时间'; +COMMENT ON COLUMN test_leave.leave_days IS '请假天数'; +COMMENT ON COLUMN test_leave.remark IS '请假原因'; +COMMENT ON COLUMN test_leave.status IS '状态'; +COMMENT ON COLUMN test_leave.create_dept IS '创建部门'; +COMMENT ON COLUMN test_leave.create_by IS '创建者'; +COMMENT ON COLUMN test_leave.create_time IS '创建时间'; +COMMENT ON COLUMN test_leave.update_by IS '更新者'; +COMMENT ON COLUMN test_leave.update_time IS '更新时间'; + +INSERT INTO sys_menu VALUES ('11616', '工作流', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_menu VALUES ('11623', '流程分类查询', '11622', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11624', '流程分类新增', '11622', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:add', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11625', '流程分类修改', '11622', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11627', '流程分类导出', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_menu VALUES ('11638', '请假申请', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, SYSDATE, NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu VALUES ('11639', '请假申请查询', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11640', '请假申请新增', '11638', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11641', '请假申请修改', '11638', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11642', '请假申请删除', '11638', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11643', '请假申请导出', '11638', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, SYSDATE, NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, SYSDATE, NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (15, '000000', '任务状态', 'wf_task_status', 103, 1, SYSDATE, NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, SYSDATE, NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '已完成'); +INSERT INTO sys_dict_data VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已作废'); +INSERT INTO sys_dict_data VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已退回'); +INSERT INTO sys_dict_data VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '动态表单'); +INSERT INTO sys_dict_data VALUES (48, '000000', 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (49, '000000', 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (50, '000000', 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (51, '000000', 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (52, '000000', 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (53, '000000', 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (54, '000000', 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (55, '000000', 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (56, '000000', 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (57, '000000', 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (58, '000000', 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (59, '000000', 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '超时'); diff --git a/script/sql/postgres/postgres_ry_job.sql b/script/sql/postgres/postgres_ry_job.sql new file mode 100644 index 0000000..1a08a99 --- /dev/null +++ b/script/sql/postgres/postgres_ry_job.sql @@ -0,0 +1,845 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : PostgreSQL + Date: 2024-12-27 22:13:49 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id bigserial PRIMARY KEY, + name varchar(64) NOT NULL, + unique_id varchar(64) NOT NULL, + description varchar(256) NOT NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name); + +COMMENT ON COLUMN sj_namespace.id IS '主键'; +COMMENT ON COLUMN sj_namespace.name IS '名称'; +COMMENT ON COLUMN sj_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN sj_namespace.description IS '描述'; +COMMENT ON COLUMN sj_namespace.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_namespace.update_dt IS '修改时间'; +COMMENT ON TABLE sj_namespace IS '命名空间'; + +INSERT INTO sj_namespace VALUES (1, 'Development', 'dev', '', 0, now(), now()); +INSERT INTO sj_namespace VALUES (2, 'Production', 'prod', '', 0, now(), now()); + +-- sj_group_config +CREATE TABLE sj_group_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + description varchar(256) NOT NULL DEFAULT '', + token varchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status smallint NOT NULL DEFAULT 0, + version int NOT NULL, + group_partition int NOT NULL, + id_generator_mode smallint NOT NULL DEFAULT 1, + init_scene smallint NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_group_config.id IS '主键'; +COMMENT ON COLUMN sj_group_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_group_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_group_config.description IS '组描述'; +COMMENT ON COLUMN sj_group_config.token IS 'token'; +COMMENT ON COLUMN sj_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_group_config.version IS '版本号'; +COMMENT ON COLUMN sj_group_config.group_partition IS '分区'; +COMMENT ON COLUMN sj_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN sj_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN sj_group_config.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_group_config IS '组配置'; + +INSERT INTO sj_group_config VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); +INSERT INTO sj_group_config VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + notify_name varchar(64) NOT NULL DEFAULT '', + system_task_type smallint NOT NULL DEFAULT 3, + notify_status smallint NOT NULL DEFAULT 0, + recipient_ids varchar(128) NOT NULL, + notify_threshold int NOT NULL DEFAULT 0, + notify_scene smallint NOT NULL DEFAULT 0, + rate_limiter_status smallint NOT NULL DEFAULT 0, + rate_limiter_threshold int NOT NULL DEFAULT 0, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_notify_config.id IS '主键'; +COMMENT ON COLUMN sj_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_notify_config.notify_name IS '通知名称'; +COMMENT ON COLUMN sj_notify_config.system_task_type IS '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.recipient_ids IS '接收人id列表'; +COMMENT ON COLUMN sj_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN sj_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN sj_notify_config.description IS '描述'; +COMMENT ON COLUMN sj_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_config IS '通知配置'; + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + recipient_name varchar(64) NOT NULL, + notify_type smallint NOT NULL DEFAULT 0, + notify_attribute varchar(512) NOT NULL, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); + +COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; +COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; +COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; +COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; +COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_recipient.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_recipient IS '告警通知接收人'; + +-- sj_retry_dead_letter_0 +CREATE TABLE sj_retry_dead_letter_0 +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_name varchar(64) NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + args_str text NOT NULL, + ext_attrs text NOT NULL, + task_type smallint NOT NULL DEFAULT 1, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id); +CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no); +CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt); + +COMMENT ON COLUMN sj_retry_dead_letter_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_dead_letter_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_dead_letter_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_dead_letter_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_dead_letter_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_dead_letter_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_dead_letter_0.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_dead_letter_0 IS '死信队列表'; + +-- sj_retry_task_0 +CREATE TABLE sj_retry_task_0 +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_name varchar(64) NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + args_str text NOT NULL, + ext_attrs text NOT NULL, + next_trigger_at timestamp NOT NULL, + retry_count int NOT NULL DEFAULT 0, + retry_status smallint NOT NULL DEFAULT 0, + task_type smallint NOT NULL DEFAULT 1, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type); +CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status); +CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id); +CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no); +CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt); + +COMMENT ON COLUMN sj_retry_task_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_0.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_retry_task_0.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_retry_task_0.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN sj_retry_task_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_0.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_0.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_0 IS '任务表'; + +-- sj_retry_task_log +CREATE TABLE sj_retry_task_log +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_name varchar(64) NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + args_str text NOT NULL, + ext_attrs text NOT NULL, + retry_status smallint NOT NULL DEFAULT 0, + task_type smallint NOT NULL DEFAULT 1, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status); +CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id); +CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id); +CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no); +CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt); + +COMMENT ON COLUMN sj_retry_task_log.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_log.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_log.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_log.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_log.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_log.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_log.retry_status IS '重试状态 0、重试中 1、成功 2、最大次数'; +COMMENT ON COLUMN sj_retry_task_log.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_log.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_log.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_log IS '任务日志基础信息表'; + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + unique_id varchar(64) NOT NULL, + message text NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id); +CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt); + +COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log_message.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_task_log_message IS '任务调度日志信息记录表'; + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_status smallint NOT NULL DEFAULT 0, + max_retry_count int NOT NULL DEFAULT 5, + back_off smallint NOT NULL DEFAULT 1, + trigger_interval varchar(16) NOT NULL DEFAULT '', + notify_ids varchar(128) NOT NULL DEFAULT '', + deadline_request bigint NOT NULL DEFAULT 60000, + executor_timeout int NOT NULL DEFAULT 5, + route_key smallint NOT NULL DEFAULT 4, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name); + +COMMENT ON COLUMN sj_retry_scene_config.id IS '主键'; +COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_retry_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN sj_retry_scene_config.description IS '描述'; +COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_scene_config IS '场景配置'; + +-- sj_server_node +CREATE TABLE sj_server_node +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + host_id varchar(64) NOT NULL, + host_ip varchar(64) NOT NULL, + host_port int NOT NULL, + expire_at timestamp NOT NULL, + node_type smallint NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip); + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name); +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type); + +COMMENT ON COLUMN sj_server_node.id IS '主键'; +COMMENT ON COLUMN sj_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_server_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_server_node.host_id IS '主机id'; +COMMENT ON COLUMN sj_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN sj_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN sj_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN sj_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN sj_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_server_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_server_node IS '服务器节点'; + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name varchar(64) PRIMARY KEY, + lock_until timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + locked_at timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + locked_by varchar(255) NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN sj_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN sj_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_distributed_lock.update_dt IS '修改时间'; +COMMENT ON TABLE sj_distributed_lock IS '锁定表'; + +-- sj_system_user +CREATE TABLE sj_system_user +( + id bigserial PRIMARY KEY, + username varchar(64) NOT NULL, + password varchar(128) NOT NULL, + role smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sj_system_user.id IS '主键'; +COMMENT ON COLUMN sj_system_user.username IS '账号'; +COMMENT ON COLUMN sj_system_user.password IS '密码'; +COMMENT ON COLUMN sj_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN sj_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user IS '系统用户表'; + +-- pwd: admin +INSERT INTO sj_system_user VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now()); + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id bigserial PRIMARY KEY, + group_name varchar(64) NOT NULL, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + system_user_id bigint NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); + +COMMENT ON COLUMN sj_system_user_permission.id IS '主键'; +COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN sj_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user_permission.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user_permission IS '系统用户权限表'; + +-- sj_sequence_alloc +CREATE TABLE sj_sequence_alloc +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + max_id bigint NOT NULL DEFAULT 1, + step int NOT NULL DEFAULT 100, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name); + +COMMENT ON COLUMN sj_sequence_alloc.id IS '主键'; +COMMENT ON COLUMN sj_sequence_alloc.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_sequence_alloc.group_name IS '组名称'; +COMMENT ON COLUMN sj_sequence_alloc.max_id IS '最大id'; +COMMENT ON COLUMN sj_sequence_alloc.step IS '步长'; +COMMENT ON COLUMN sj_sequence_alloc.update_dt IS '更新时间'; +COMMENT ON TABLE sj_sequence_alloc IS '号段模式序号ID分配表'; + +-- sj_job +CREATE TABLE sj_job +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_name varchar(64) NOT NULL, + args_str text NULL DEFAULT NULL, + args_type smallint NOT NULL DEFAULT 1, + next_trigger_at bigint NOT NULL, + job_status smallint NOT NULL DEFAULT 1, + task_type smallint NOT NULL DEFAULT 1, + route_key smallint NOT NULL DEFAULT 4, + executor_type smallint NOT NULL DEFAULT 1, + executor_info varchar(255) NULL DEFAULT NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar(255) NOT NULL, + block_strategy smallint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + max_retry_times int NOT NULL DEFAULT 0, + parallel_num int NOT NULL DEFAULT 1, + retry_interval int NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + resident smallint NOT NULL DEFAULT 0, + notify_ids varchar(128) NOT NULL DEFAULT '', + owner_id bigint NULL, + description varchar(256) NOT NULL DEFAULT '', + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name); +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index); +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt); + +COMMENT ON COLUMN sj_job.id IS '主键'; +COMMENT ON COLUMN sj_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job.group_name IS '组名称'; +COMMENT ON COLUMN sj_job.job_name IS '名称'; +COMMENT ON COLUMN sj_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_job.job_status IS '任务状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN sj_job.route_key IS '路由策略'; +COMMENT ON COLUMN sj_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN sj_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN sj_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN sj_job.parallel_num IS '并行数'; +COMMENT ON COLUMN sj_job.retry_interval IS '重试间隔 ( s ) '; +COMMENT ON COLUMN sj_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN sj_job.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_job.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_job.description IS '描述'; +COMMENT ON COLUMN sj_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job IS '任务信息'; + +INSERT INTO sj_job VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '', '', 0, now(), now()); + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + task_id bigint NOT NULL, + message text NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt); +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_log_message.id IS '主键'; +COMMENT ON COLUMN sj_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN sj_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN sj_job_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_job_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_job_log_message IS '调度日志'; + +-- sj_job_task +CREATE TABLE sj_job_task +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + parent_id bigint NOT NULL DEFAULT 0, + task_status smallint NOT NULL DEFAULT 0, + retry_count int NOT NULL DEFAULT 0, + mr_stage smallint NULL DEFAULT NULL, + leaf smallint NOT NULL DEFAULT '1', + task_name varchar(255) NOT NULL DEFAULT '', + client_info varchar(128) NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + result_message text NOT NULL, + args_str text NULL DEFAULT NULL, + args_type smallint NOT NULL DEFAULT 1, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status); +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt); +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_task.id IS '主键'; +COMMENT ON COLUMN sj_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; +COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; +COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; +COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task IS '任务实例'; + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_node_id bigint NOT NULL DEFAULT 0, + parent_workflow_node_id bigint NOT NULL DEFAULT 0, + workflow_task_batch_id bigint NOT NULL DEFAULT 0, + task_batch_status smallint NOT NULL DEFAULT 0, + operation_reason smallint NOT NULL DEFAULT 0, + execution_at bigint NOT NULL DEFAULT 0, + system_task_type smallint NOT NULL DEFAULT 3, + parent_id varchar(64) NOT NULL DEFAULT '', + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt); +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON COLUMN sj_job_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task_batch.job_id IS '任务id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '工作流任务父批次id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '工作流任务批次id'; +COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task_batch IS '任务批次'; + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + business_id bigint NOT NULL, + system_task_type smallint NOT NULL DEFAULT 3, + trigger_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + success_num int NOT NULL DEFAULT 0, + fail_num int NOT NULL DEFAULT 0, + fail_reason varchar(512) NOT NULL DEFAULT '', + stop_num int NOT NULL DEFAULT 0, + stop_reason varchar(512) NOT NULL DEFAULT '', + cancel_num int NOT NULL DEFAULT 0, + cancel_reason varchar(512) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id); + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id); + +COMMENT ON COLUMN sj_job_summary.id IS '主键'; +COMMENT ON COLUMN sj_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_summary.business_id IS '业务id ( job_id或workflow_id ) '; +COMMENT ON COLUMN sj_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.cancel_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job'; + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + scene_name varchar(50) NOT NULL DEFAULT '', + trigger_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + running_num int NOT NULL DEFAULT 0, + finish_num int NOT NULL DEFAULT 0, + max_count_num int NOT NULL DEFAULT 0, + suspend_num int NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at); + +COMMENT ON COLUMN sj_retry_summary.id IS '主键'; +COMMENT ON COLUMN sj_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN sj_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN sj_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN sj_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN sj_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry'; + +-- sj_workflow +CREATE TABLE sj_workflow +( + id bigserial PRIMARY KEY, + workflow_name varchar(64) NOT NULL, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + workflow_status smallint NOT NULL DEFAULT 1, + trigger_type smallint NOT NULL, + trigger_interval varchar(255) NOT NULL, + next_trigger_at bigint NOT NULL, + block_strategy smallint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + description varchar(256) NOT NULL DEFAULT '', + flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + notify_ids varchar(128) NOT NULL DEFAULT '', + bucket_index int NOT NULL DEFAULT 0, + version int NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt); +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow.id IS '主键'; +COMMENT ON COLUMN sj_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN sj_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_workflow.description IS '描述'; +COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; +COMMENT ON COLUMN sj_workflow.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_workflow.version IS '版本号'; +COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow IS '工作流'; + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_id bigint NOT NULL, + node_type smallint NOT NULL DEFAULT 1, + expression_type smallint NOT NULL DEFAULT 0, + fail_strategy smallint NOT NULL DEFAULT 1, + workflow_node_status smallint NOT NULL DEFAULT 1, + priority_level int NOT NULL DEFAULT 1, + node_info text NULL DEFAULT NULL, + version int NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt); +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_node.id IS '主键'; +COMMENT ON COLUMN sj_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN sj_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN sj_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN sj_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN sj_workflow_node.node_info IS '节点信息 '; +COMMENT ON COLUMN sj_workflow_node.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_node IS '工作流节点'; + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + workflow_id bigint NOT NULL, + task_batch_status smallint NOT NULL DEFAULT 0, + operation_reason smallint NOT NULL DEFAULT 0, + flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + execution_at bigint NOT NULL DEFAULT 0, + ext_attrs varchar(256) NULL DEFAULT '', + version int NOT NULL DEFAULT 1, + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt); +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; +COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_task_batch IS '工作流批次'; diff --git a/script/sql/postgres/postgres_ry_vue_5.X.sql b/script/sql/postgres/postgres_ry_vue_5.X.sql new file mode 100644 index 0000000..d18cfeb --- /dev/null +++ b/script/sql/postgres/postgres_ry_vue_5.X.sql @@ -0,0 +1,1383 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id int8 not null, + user_id int8 not null, + tenant_id varchar(20) default '000000'::varchar, + auth_id varchar(255) not null, + source varchar(255) not null, + open_id varchar(255) default null::varchar, + user_name varchar(30) not null, + nick_name varchar(30) default ''::varchar, + email varchar(255) default ''::varchar, + avatar varchar(500) default ''::varchar, + access_token varchar(255) not null, + expire_in int8 default null, + refresh_token varchar(255) default null::varchar, + access_code varchar(255) default null::varchar, + union_id varchar(255) default null::varchar, + scope varchar(255) default null::varchar, + token_type varchar(255) default null::varchar, + id_token varchar(2000) default null::varchar, + mac_algorithm varchar(255) default null::varchar, + mac_key varchar(255) default null::varchar, + code varchar(255) default null::varchar, + oauth_token varchar(255) default null::varchar, + oauth_token_secret varchar(255) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + del_flag char default '0'::bpchar, + constraint "pk_sys_social" primary key (id) +); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 1代表删除)'; + +-- ---------------------------- +-- 租户表 +-- ---------------------------- +create table if not exists sys_tenant +( + id int8, + tenant_id varchar(20) not null, + contact_user_name varchar(20) default null::varchar, + contact_phone varchar(20) default null::varchar, + company_name varchar(50) default null::varchar, + license_number varchar(30) default null::varchar, + address varchar(200) default null::varchar, + intro varchar(200) default null::varchar, + domain varchar(200) default null::varchar, + remark varchar(200) default null::varchar, + package_id int8, + expire_time timestamp, + account_count int4 default -1, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint "pk_sys_tenant" primary key (id) +); + + +comment on table sys_tenant is '租户表'; +comment on column sys_tenant.tenant_id is '租户编号'; +comment on column sys_tenant.contact_phone is '联系电话'; +comment on column sys_tenant.company_name is '企业名称'; +comment on column sys_tenant.company_name is '联系人'; +comment on column sys_tenant.license_number is '统一社会信用代码'; +comment on column sys_tenant.address is '地址'; +comment on column sys_tenant.intro is '企业简介'; +comment on column sys_tenant.domain is '域名'; +comment on column sys_tenant.remark is '备注'; +comment on column sys_tenant.package_id is '租户套餐编号'; +comment on column sys_tenant.expire_time is '过期时间'; +comment on column sys_tenant.account_count is '用户数量(-1不限制)'; +comment on column sys_tenant.status is '租户状态(0正常 1停用)'; +comment on column sys_tenant.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant.create_dept is '创建部门'; +comment on column sys_tenant.create_by is '创建者'; +comment on column sys_tenant.create_time is '创建时间'; +comment on column sys_tenant.update_by is '更新者'; +comment on column sys_tenant.update_time is '更新时间'; + + +-- ---------------------------- +-- 初始化-租户表数据 +-- ---------------------------- + +insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有限公司', null, null, '多租户通用后台管理管理系统', null, null, null, null, -1, '0', '0', 103, 1, now(), null, null); + + +-- ---------------------------- +-- 租户套餐表 +-- ---------------------------- +create table if not exists sys_tenant_package +( + package_id int8, + package_name varchar(20) default ''::varchar, + menu_ids varchar(3000) default ''::varchar, + remark varchar(200) default ''::varchar, + menu_check_strictly bool default true, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint "pk_sys_tenant_package" primary key (package_id) +); + + +comment on table sys_tenant_package is '租户套餐表'; +comment on column sys_tenant_package.package_id is '租户套餐id'; +comment on column sys_tenant_package.package_name is '套餐名称'; +comment on column sys_tenant_package.menu_ids is '关联菜单id'; +comment on column sys_tenant_package.remark is '备注'; +comment on column sys_tenant_package.status is '状态(0正常 1停用)'; +comment on column sys_tenant_package.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant_package.create_dept is '创建部门'; +comment on column sys_tenant_package.create_by is '创建者'; +comment on column sys_tenant_package.create_time is '创建时间'; +comment on column sys_tenant_package.update_by is '更新者'; +comment on column sys_tenant_package.update_time is '更新时间'; + + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table if not exists sys_dept +( + dept_id int8, + tenant_id varchar(20) default '000000'::varchar, + parent_id int8 default 0, + ancestors varchar(500)default ''::varchar, + dept_name varchar(30) default ''::varchar, + dept_category varchar(100) default null::varchar, + order_num int4 default 0, + leader int8 default null, + phone varchar(11) default null::varchar, + email varchar(50) default null::varchar, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint "sys_dept_pk" primary key (dept_id) +); + +comment on table sys_dept is '部门表'; +comment on column sys_dept.dept_id is '部门ID'; +comment on column sys_dept.tenant_id is '租户编号'; +comment on column sys_dept.parent_id is '父部门ID'; +comment on column sys_dept.ancestors is '祖级列表'; +comment on column sys_dept.dept_name is '部门名称'; +comment on column sys_dept.dept_category is '部门类别编码'; +comment on column sys_dept.order_num is '显示顺序'; +comment on column sys_dept.leader is '负责人'; +comment on column sys_dept.phone is '联系电话'; +comment on column sys_dept.email is '邮箱'; +comment on column sys_dept.status is '部门状态(0正常 1停用)'; +comment on column sys_dept.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_dept.create_dept is '创建部门'; +comment on column sys_dept.create_by is '创建者'; +comment on column sys_dept.create_time is '创建时间'; +comment on column sys_dept.update_by is '更新者'; +comment on column sys_dept.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- +insert into sys_dept values(100, '000000', 0, '0', 'XXX科技', null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(101, '000000', 100, '0,100', '深圳总公司', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(102, '000000', 100, '0,100', '长沙分公司', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(103, '000000', 101, '0,100,101', '研发部门', null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(104, '000000', 101, '0,100,101', '市场部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(105, '000000', 101, '0,100,101', '测试部门', null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(106, '000000', 101, '0,100,101', '财务部门', null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(107, '000000', 101, '0,100,101', '运维部门', null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(108, '000000', 102, '0,100,102', '市场部门', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table if not exists sys_user +( + user_id int8, + tenant_id varchar(20) default '000000'::varchar, + dept_id int8, + user_name varchar(30) not null, + nick_name varchar(30) not null, + user_type varchar(10) default 'sys_user'::varchar, + email varchar(50) default ''::varchar, + phonenumber varchar(11) default ''::varchar, + sex char default '0'::bpchar, + avatar int8, + password varchar(100) default ''::varchar, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + login_ip varchar(128) default ''::varchar, + login_date timestamp, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_user_pk" primary key (user_id) +); + +comment on table sys_user is '用户信息表'; +comment on column sys_user.user_id is '用户ID'; +comment on column sys_user.tenant_id is '租户编号'; +comment on column sys_user.dept_id is '部门ID'; +comment on column sys_user.user_name is '用户账号'; +comment on column sys_user.nick_name is '用户昵称'; +comment on column sys_user.user_type is '用户类型(sys_user系统用户)'; +comment on column sys_user.email is '用户邮箱'; +comment on column sys_user.phonenumber is '手机号码'; +comment on column sys_user.sex is '用户性别(0男 1女 2未知)'; +comment on column sys_user.avatar is '头像地址'; +comment on column sys_user.password is '密码'; +comment on column sys_user.status is '帐号状态(0正常 1停用)'; +comment on column sys_user.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_user.login_ip is '最后登陆IP'; +comment on column sys_user.login_date is '最后登陆时间'; +comment on column sys_user.create_dept is '创建部门'; +comment on column sys_user.create_by is '创建者'; +comment on column sys_user.create_time is '创建时间'; +comment on column sys_user.update_by is '更新者'; +comment on column sys_user.update_time is '更新时间'; +comment on column sys_user.remark is '备注'; + +-- ---------------------------- + +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '管理员'); +insert into sys_user VALUES(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 3, now(), NULL); +insert into sys_user VALUES(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 4, now(), NULL); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table if not exists sys_post +( + post_id int8, + tenant_id varchar(20) default '000000'::varchar, + dept_id int8, + post_code varchar(64) not null, + post_category varchar(100) default null, + post_name varchar(50) not null, + post_sort int4 not null, + status char not null, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_post_pk" primary key (post_id) +); + +comment on table sys_post is '岗位信息表'; +comment on column sys_post.post_id is '岗位ID'; +comment on column sys_post.tenant_id is '租户编号'; +comment on column sys_post.dept_id is '部门id'; +comment on column sys_post.post_code is '岗位编码'; +comment on column sys_post.post_category is '岗位类别编码'; +comment on column sys_post.post_name is '岗位名称'; +comment on column sys_post.post_sort is '显示顺序'; +comment on column sys_post.status is '状态(0正常 1停用)'; +comment on column sys_post.create_dept is '创建部门'; +comment on column sys_post.create_by is '创建者'; +comment on column sys_post.create_time is '创建时间'; +comment on column sys_post.update_by is '更新者'; +comment on column sys_post.update_time is '更新时间'; +comment on column sys_post.remark is '备注'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, '000000', 103, 'ceo', null, '董事长', 1, '0', 103, 1, now(), null, null, ''); +insert into sys_post values(2, '000000', 100, 'se', null, '项目经理', 2, '0', 103, 1, now(), null, null, ''); +insert into sys_post values(3, '000000', 100, 'hr', null, '人力资源', 3, '0', 103, 1, now(), null, null, ''); +insert into sys_post values(4, '000000', 100, 'user', null, '普通员工', 4, '0', 103, 1, now(), null, null, ''); + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table if not exists sys_role +( + role_id int8, + tenant_id varchar(20) default '000000'::varchar, + role_name varchar(30) not null, + role_key varchar(100) not null, + role_sort int4 not null, + data_scope char default '1'::bpchar, + menu_check_strictly bool default true, + dept_check_strictly bool default true, + status char not null, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_role_pk" primary key (role_id) +); + +comment on table sys_role is '角色信息表'; +comment on column sys_role.role_id is '角色ID'; +comment on column sys_role.tenant_id is '租户编号'; +comment on column sys_role.role_name is '角色名称'; +comment on column sys_role.role_key is '角色权限字符串'; +comment on column sys_role.role_sort is '显示顺序'; +comment on column sys_role.data_scope is '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +comment on column sys_role.menu_check_strictly is '菜单树选择项是否关联显示'; +comment on column sys_role.dept_check_strictly is '部门树选择项是否关联显示'; +comment on column sys_role.status is '角色状态(0正常 1停用)'; +comment on column sys_role.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_role.create_dept is '创建部门'; +comment on column sys_role.create_by is '创建者'; +comment on column sys_role.create_time is '创建时间'; +comment on column sys_role.update_by is '更新者'; +comment on column sys_role.update_time is '更新时间'; +comment on column sys_role.remark is '备注'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values('1', '000000', '超级管理员', 'superadmin', 1, '1', 't', 't', '0', '0', 103, 1, now(), null, null, '超级管理员'); +insert into sys_role values('3', '000000', '本部门及以下', 'test1', 3, '4', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, ''); +insert into sys_role values('4', '000000', '仅本人', 'test2', 4, '5', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, ''); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table if not exists sys_menu +( + menu_id int8, + menu_name varchar(50) not null, + parent_id int8 default 0, + order_num int4 default 0, + path varchar(200) default ''::varchar, + component varchar(255) default null::varchar, + query_param varchar(255) default null::varchar, + is_frame char default '1'::bpchar, + is_cache char default '0'::bpchar, + menu_type char default ''::bpchar, + visible char default '0'::bpchar, + status char default '0'::bpchar, + perms varchar(100) default null::varchar, + icon varchar(100) default '#'::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default ''::varchar, + constraint "sys_menu_pk" primary key (menu_id) +); + +comment on table sys_menu is '菜单权限表'; +comment on column sys_menu.menu_id is '菜单ID'; +comment on column sys_menu.menu_name is '菜单名称'; +comment on column sys_menu.parent_id is '父菜单ID'; +comment on column sys_menu.order_num is '显示顺序'; +comment on column sys_menu.path is '路由地址'; +comment on column sys_menu.component is '组件路径'; +comment on column sys_menu.query_param is '路由参数'; +comment on column sys_menu.is_frame is '是否为外链(0是 1否)'; +comment on column sys_menu.is_cache is '是否缓存(0缓存 1不缓存)'; +comment on column sys_menu.menu_type is '菜单类型(M目录 C菜单 F按钮)'; +comment on column sys_menu.visible is '显示状态(0显示 1隐藏)'; +comment on column sys_menu.status is '菜单状态(0正常 1停用)'; +comment on column sys_menu.perms is '权限标识'; +comment on column sys_menu.icon is '菜单图标'; +comment on column sys_menu.create_dept is '创建部门'; +comment on column sys_menu.create_by is '创建者'; +comment on column sys_menu.create_time is '创建时间'; +comment on column sys_menu.update_by is '更新者'; +comment on column sys_menu.update_time is '更新时间'; +comment on column sys_menu.remark is '备注'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '1', '0', 'M', '0', '0', '', 'system', 103, 1, now(), null, null, '系统管理目录'); +insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', null, '', '1', '0', 'M', '0', '0', '', 'chart', 103, 1, now(), null, null, '租户管理目录'); +insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), null, null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', '1', '0', 'M', '0', '0', '', 'tool', 103, 1, now(), null, null, '系统工具目录'); +insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', '0', '0', 'M', '0', '0', '', 'guide', 103, 1, now(), null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu VALUES('5', '测试菜单', '0', '5', 'demo', null, '', '1', '0', 'M', '0', '0', null, 'star', 103, 1, now(), null, null, '测试菜单'); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '1', '0', 'C', '0', '0', 'system:user:list', 'user', 103, 1, now(), null, null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '1', '0', 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, now(), null, null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', '1', '0', 'C', '0', '0', 'system:menu:list', 'tree-table', 103, 1, now(), null, null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', '1', '0', 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, now(), null, null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', '1', '0', 'C', '0', '0', 'system:post:list', 'post', 103, 1, now(), null, null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', '1', '0', 'C', '0', '0', 'system:dict:list', 'dict', 103, 1, now(), null, null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', '1', '0', 'C', '0', '0', 'system:config:list', 'edit', 103, 1, now(), null, null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', '1', '0', 'C', '0', '0', 'system:notice:list', 'message', 103, 1, now(), null, null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', '1', '0', 'M', '0', '0', '', 'log', 103, 1, now(), null, null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', '1', '0', 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, now(), null, null, '在线用户菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', '1', '0', 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, now(), null, null, '缓存监控菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', '1', '0', 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, now(), null, null, '代码生成菜单'); +insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', '1', '0', 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, now(), null, null, '租户管理菜单'); +insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', '1', '0', 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, now(), null, null, '租户套餐管理菜单'); +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', '1', '0', 'C', '0', '0', 'system:client:list', 'international', 103, 1, now(), null, null, '客户端管理菜单'); + +-- springboot-admin监控 +insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', 'monitor/admin/index', '', '1', '0', 'C', '0', '0', 'monitor:admin:list', 'dashboard', 103, 1, now(), null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', '1', '0', 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, now(), null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values('120', '任务调度中心', '2', '6', 'snailjob', 'monitor/snailjob/index', '', '1', '0', 'C', '0', '0', 'monitor:snailjob:list', 'job', 103, 1, now(), null, null, 'SnailJob控制台菜单'); + +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', '1', '0', 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, now(), null, null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', '1', '0', 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 103, 1, now(), null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1001', '用户查询', '100', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:user:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1002', '用户新增', '100', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:user:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1003', '用户修改', '100', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:user:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1004', '用户删除', '100', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:user:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1005', '用户导出', '100', '5', '', '', '', '1', '0', 'F', '0', '0', 'system:user:export', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1006', '用户导入', '100', '6', '', '', '', '1', '0', 'F', '0', '0', 'system:user:import', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1007', '重置密码', '100', '7', '', '', '', '1', '0', 'F', '0', '0', 'system:user:resetPwd', '#', 103, 1, now(), null, null, ''); +-- 角色管理按钮 +insert into sys_menu values('1008', '角色查询', '101', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:role:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1009', '角色新增', '101', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:role:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1010', '角色修改', '101', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:role:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1011', '角色删除', '101', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:role:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1012', '角色导出', '101', '5', '', '', '', '1', '0', 'F', '0', '0', 'system:role:export', '#', 103, 1, now(), null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:remove', '#', 103, 1, now(), null, null, ''); +-- 部门管理按钮 +insert into sys_menu values('1017', '部门查询', '103', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1018', '部门新增', '103', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1019', '部门修改', '103', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1020', '部门删除', '103', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:remove', '#', 103, 1, now(), null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:post:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:post:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:post:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:post:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', '', '1', '0', 'F', '0', '0', 'system:post:export', '#', 103, 1, now(), null, null, ''); +-- 字典管理按钮 +insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:export', '#', 103, 1, now(), null, null, ''); +-- 参数设置按钮 +insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:export', '#', 103, 1, now(), null, null, ''); +-- 通知公告按钮 +insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:remove', '#', 103, 1, now(), null, null, ''); +-- 操作日志按钮 +insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:export', '#', 103, 1, now(), null, null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, now(), null, null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, now(), null, null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:import', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:preview', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:code', '#', 103, 1, now(), null, null, ''); +-- oss相关按钮 +insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:upload', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:download', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, now(), null, null, ''); +-- 租户管理相关按钮 +insert into sys_menu values('1606', '租户查询', '121', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1607', '租户新增', '121', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1608', '租户修改', '121', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1609', '租户删除', '121', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1610', '租户导出', '121', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:export', '#', 103, 1, now(), null, null, ''); +-- 租户套餐管理相关按钮 +insert into sys_menu values('1611', '租户套餐查询', '122', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1612', '租户套餐新增', '122', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1613', '租户套餐修改', '122', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1614', '租户套餐删除', '122', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1615', '租户套餐导出', '122', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:export', '#', 103, 1, now(), null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:export', '#', 103, 1, now(), null, null, ''); +-- 测试菜单 +INSERT INTO sys_menu VALUES('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', '1', '0', 'C', '0', '0', 'demo:demo:list', '#', 103, 1, now(), NULL, NULL, '测试单表菜单'); +INSERT INTO sys_menu VALUES('1501', '测试单表查询', '1500', '1', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1502', '测试单表新增', '1500', '2', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1503', '测试单表修改', '1500', '3', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1504', '测试单表删除', '1500', '4', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1505', '测试单表导出', '1500', '5', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:export', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', '1', '0', 'C', '0', '0', 'demo:tree:list', '#', 103, 1, now(), NULL, NULL, '测试树表菜单'); +INSERT INTO sys_menu VALUES('1507', '测试树表查询', '1506', '1', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1508', '测试树表新增', '1506', '2', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1509', '测试树表修改', '1506', '3', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1510', '测试树表删除', '1506', '4', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1511', '测试树表导出', '1506', '5', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:export', '#', 103, 1, now(), NULL, NULL, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table if not exists sys_user_role +( + user_id int8 not null, + role_id int8 not null, + constraint sys_user_role_pk primary key (user_id, role_id) +); + +comment on table sys_user_role is '用户和角色关联表'; +comment on column sys_user_role.user_id is '用户ID'; +comment on column sys_user_role.role_id is '角色ID'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table if not exists sys_role_menu +( + role_id int8 not null, + menu_id int8 not null, + constraint sys_role_menu_pk primary key (role_id, menu_id) +); + +comment on table sys_role_menu is '角色和菜单关联表'; +comment on column sys_role_menu.role_id is '角色ID'; +comment on column sys_role_menu.menu_id is '菜单ID'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '118'); +insert into sys_role_menu values ('3', '123'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1050'); +insert into sys_role_menu values ('3', '1061'); +insert into sys_role_menu values ('3', '1062'); +insert into sys_role_menu values ('3', '1063'); +insert into sys_role_menu values ('3', '1064'); +insert into sys_role_menu values ('3', '1065'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('3', '1600'); +insert into sys_role_menu values ('3', '1601'); +insert into sys_role_menu values ('3', '1602'); +insert into sys_role_menu values ('3', '1603'); +insert into sys_role_menu values ('3', '1620'); +insert into sys_role_menu values ('3', '1621'); +insert into sys_role_menu values ('3', '1622'); +insert into sys_role_menu values ('3', '1623'); +insert into sys_role_menu values ('3', '11618'); +insert into sys_role_menu values ('3', '11619'); +insert into sys_role_menu values ('3', '11629'); +insert into sys_role_menu values ('3', '11632'); +insert into sys_role_menu values ('3', '11633'); +insert into sys_role_menu values ('3', '11638'); +insert into sys_role_menu values ('3', '11639'); +insert into sys_role_menu values ('3', '11640'); +insert into sys_role_menu values ('3', '11641'); +insert into sys_role_menu values ('3', '11642'); +insert into sys_role_menu values ('3', '11643'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table if not exists sys_role_dept +( + role_id int8 not null, + dept_id int8 not null, + constraint sys_role_dept_pk primary key (role_id, dept_id) +); + +comment on table sys_role_dept is '角色和部门关联表'; +comment on column sys_role_dept.role_id is '角色ID'; +comment on column sys_role_dept.dept_id is '部门ID'; + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table if not exists sys_user_post +( + user_id int8 not null, + post_id int8 not null, + constraint sys_user_post_pk primary key (user_id, post_id) +); + +comment on table sys_user_post is '用户与岗位关联表'; +comment on column sys_user_post.user_id is '用户ID'; +comment on column sys_user_post.post_id is '岗位ID'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table if not exists sys_oper_log +( + oper_id int8, + tenant_id varchar(20) default '000000'::varchar, + title varchar(50) default ''::varchar, + business_type int4 default 0, + method varchar(100) default ''::varchar, + request_method varchar(10) default ''::varchar, + operator_type int4 default 0, + oper_name varchar(50) default ''::varchar, + dept_name varchar(50) default ''::varchar, + oper_url varchar(255) default ''::varchar, + oper_ip varchar(128) default ''::varchar, + oper_location varchar(255) default ''::varchar, + oper_param varchar(4000) default ''::varchar, + json_result varchar(4000) default ''::varchar, + status int4 default 0, + error_msg varchar(4000) default ''::varchar, + oper_time timestamp, + cost_time int8 default 0, + constraint sys_oper_log_pk primary key (oper_id) +); + +create index idx_sys_oper_log_bt ON sys_oper_log (business_type); +create index idx_sys_oper_log_s ON sys_oper_log (status); +create index idx_sys_oper_log_ot ON sys_oper_log (oper_time); + +comment on table sys_oper_log is '操作日志记录'; +comment on column sys_oper_log.oper_id is '日志主键'; +comment on column sys_oper_log.tenant_id is '租户编号'; +comment on column sys_oper_log.title is '模块标题'; +comment on column sys_oper_log.business_type is '业务类型(0其它 1新增 2修改 3删除)'; +comment on column sys_oper_log.method is '方法名称'; +comment on column sys_oper_log.request_method is '请求方式'; +comment on column sys_oper_log.operator_type is '操作类别(0其它 1后台用户 2手机端用户)'; +comment on column sys_oper_log.oper_name is '操作人员'; +comment on column sys_oper_log.dept_name is '部门名称'; +comment on column sys_oper_log.oper_url is '请求URL'; +comment on column sys_oper_log.oper_ip is '主机地址'; +comment on column sys_oper_log.oper_location is '操作地点'; +comment on column sys_oper_log.oper_param is '请求参数'; +comment on column sys_oper_log.json_result is '返回参数'; +comment on column sys_oper_log.status is '操作状态(0正常 1异常)'; +comment on column sys_oper_log.error_msg is '错误消息'; +comment on column sys_oper_log.oper_time is '操作时间'; +comment on column sys_oper_log.cost_time is '消耗时间'; + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table if not exists sys_dict_type +( + dict_id int8, + tenant_id varchar(20) default '000000'::varchar, + dict_name varchar(100) default ''::varchar, + dict_type varchar(100) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_dict_type_pk primary key (dict_id) +); + +create unique index sys_dict_type_index1 ON sys_dict_type (tenant_id, dict_type); + +comment on table sys_dict_type is '字典类型表'; +comment on column sys_dict_type.dict_id is '字典主键'; +comment on column sys_dict_type.tenant_id is '租户编号'; +comment on column sys_dict_type.dict_name is '字典名称'; +comment on column sys_dict_type.dict_type is '字典类型'; +comment on column sys_dict_type.create_dept is '创建部门'; +comment on column sys_dict_type.create_by is '创建者'; +comment on column sys_dict_type.create_time is '创建时间'; +comment on column sys_dict_type.update_by is '更新者'; +comment on column sys_dict_type.update_time is '更新时间'; +comment on column sys_dict_type.remark is '备注'; + +insert into sys_dict_type values(1, '000000', '用户性别', 'sys_user_sex', 103, 1, now(), null, null, '用户性别列表'); +insert into sys_dict_type values(2, '000000', '菜单状态', 'sys_show_hide', 103, 1, now(), null, null, '菜单状态列表'); +insert into sys_dict_type values(3, '000000', '系统开关', 'sys_normal_disable', 103, 1, now(), null, null, '系统开关列表'); +insert into sys_dict_type values(6, '000000', '系统是否', 'sys_yes_no', 103, 1, now(), null, null, '系统是否列表'); +insert into sys_dict_type values(7, '000000', '通知类型', 'sys_notice_type', 103, 1, now(), null, null, '通知类型列表'); +insert into sys_dict_type values(8, '000000', '通知状态', 'sys_notice_status', 103, 1, now(), null, null, '通知状态列表'); +insert into sys_dict_type values(9, '000000', '操作类型', 'sys_oper_type', 103, 1, now(), null, null, '操作类型列表'); +insert into sys_dict_type values(10, '000000', '系统状态', 'sys_common_status', 103, 1, now(), null, null, '登录状态列表'); +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, now(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, now(), null, null, '客户端设备类型'); + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table if not exists sys_dict_data +( + dict_code int8, + tenant_id varchar(20) default '000000'::varchar, + dict_sort int4 default 0, + dict_label varchar(100) default ''::varchar, + dict_value varchar(100) default ''::varchar, + dict_type varchar(100) default ''::varchar, + css_class varchar(100) default null::varchar, + list_class varchar(100) default null::varchar, + is_default char default 'N'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_dict_data_pk primary key (dict_code) +); + +comment on table sys_dict_data is '字典数据表'; +comment on column sys_dict_data.dict_code is '字典编码'; +comment on column sys_dict_type.tenant_id is '租户编号'; +comment on column sys_dict_data.dict_sort is '字典排序'; +comment on column sys_dict_data.dict_label is '字典标签'; +comment on column sys_dict_data.dict_value is '字典键值'; +comment on column sys_dict_data.dict_type is '字典类型'; +comment on column sys_dict_data.css_class is '样式属性(其他样式扩展)'; +comment on column sys_dict_data.list_class is '表格回显样式'; +comment on column sys_dict_data.is_default is '是否默认(Y是 N否)'; +comment on column sys_dict_data.create_dept is '创建部门'; +comment on column sys_dict_data.create_by is '创建者'; +comment on column sys_dict_data.create_time is '创建时间'; +comment on column sys_dict_data.update_by is '更新者'; +comment on column sys_dict_data.update_time is '更新时间'; +comment on column sys_dict_data.remark is '备注'; + +insert into sys_dict_data values(1, '000000', 1, '男', '0', 'sys_user_sex', '', '', 'Y', 103, 1, now(), null, null, '性别男'); +insert into sys_dict_data values(2, '000000', 2, '女', '1', 'sys_user_sex', '', '', 'N', 103, 1, now(), null, null, '性别女'); +insert into sys_dict_data values(3, '000000', 3, '未知', '2', 'sys_user_sex', '', '', 'N', 103, 1, now(), null, null, '性别未知'); +insert into sys_dict_data values(4, '000000', 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 103, 1, now(), null, null, '显示菜单'); +insert into sys_dict_data values(5, '000000', 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 103, 1, now(), null, null, '隐藏菜单'); +insert into sys_dict_data values(6, '000000', 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 103, 1, now(), null, null, '正常状态'); +insert into sys_dict_data values(7, '000000', 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 103, 1, now(), null, null, '停用状态'); +insert into sys_dict_data values(12, '000000', 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 103, 1, now(), null, null, '系统默认是'); +insert into sys_dict_data values(13, '000000', 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 103, 1, now(), null, null, '系统默认否'); +insert into sys_dict_data values(14, '000000', 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 103, 1, now(), null, null, '通知'); +insert into sys_dict_data values(15, '000000', 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 103, 1, now(), null, null, '公告'); +insert into sys_dict_data values(16, '000000', 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 103, 1, now(), null, null, '正常状态'); +insert into sys_dict_data values(17, '000000', 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 103, 1, now(), null, null, '关闭状态'); +insert into sys_dict_data values(29, '000000', 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 103, 1, now(), null, null, '其他操作'); +insert into sys_dict_data values(18, '000000', 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 103, 1, now(), null, null, '新增操作'); +insert into sys_dict_data values(19, '000000', 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 103, 1, now(), null, null, '修改操作'); +insert into sys_dict_data values(20, '000000', 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 103, 1, now(), null, null, '删除操作'); +insert into sys_dict_data values(21, '000000', 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 103, 1, now(), null, null, '授权操作'); +insert into sys_dict_data values(22, '000000', 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 103, 1, now(), null, null, '导出操作'); +insert into sys_dict_data values(23, '000000', 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 103, 1, now(), null, null, '导入操作'); +insert into sys_dict_data values(24, '000000', 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 103, 1, now(), null, null, '强退操作'); +insert into sys_dict_data values(25, '000000', 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 103, 1, now(), null, null, '生成操作'); +insert into sys_dict_data values(26, '000000', 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 103, 1, now(), null, null, '清空操作'); +insert into sys_dict_data values(27, '000000', 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 103, 1, now(), null, null, '正常状态'); +insert into sys_dict_data values(28, '000000', 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 103, 1, now(), null, null, '停用状态'); +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table if not exists sys_config +( + config_id int8, + tenant_id varchar(20) default '000000'::varchar, + config_name varchar(100) default ''::varchar, + config_key varchar(100) default ''::varchar, + config_value varchar(500) default ''::varchar, + config_type char default 'N'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_config_pk primary key (config_id) +); + +comment on table sys_config is '参数配置表'; +comment on column sys_config.config_id is '参数主键'; +comment on column sys_config.tenant_id is '租户编号'; +comment on column sys_config.config_name is '参数名称'; +comment on column sys_config.config_key is '参数键名'; +comment on column sys_config.config_value is '参数键值'; +comment on column sys_config.config_type is '系统内置(Y是 N否)'; +comment on column sys_config.create_dept is '创建部门'; +comment on column sys_config.create_by is '创建者'; +comment on column sys_config.create_time is '创建时间'; +comment on column sys_config.update_by is '更新者'; +comment on column sys_config.update_time is '更新时间'; +comment on column sys_config.remark is '备注'; + +insert into sys_config values(1, '000000', '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 103, 1, now(), null, null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '000000', '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 103, 1, now(), null, null, '初始化密码 123456' ); +insert into sys_config values(3, '000000', '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 103, 1, now(), null, null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(5, '000000', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 103, 1, now(), null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(11, '000000', 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 103, 1, now(), null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table if not exists sys_logininfor +( + info_id int8, + tenant_id varchar(20) default '000000'::varchar, + user_name varchar(50) default ''::varchar, + client_key varchar(32) default ''::varchar, + device_type varchar(32) default ''::varchar, + ipaddr varchar(128) default ''::varchar, + login_location varchar(255) default ''::varchar, + browser varchar(50) default ''::varchar, + os varchar(50) default ''::varchar, + status char default '0'::bpchar, + msg varchar(255) default ''::varchar, + login_time timestamp, + constraint sys_logininfor_pk primary key (info_id) +); + +create index idx_sys_logininfor_s ON sys_logininfor (status); +create index idx_sys_logininfor_lt ON sys_logininfor (login_time); + +comment on table sys_logininfor is '系统访问记录'; +comment on column sys_logininfor.info_id is '访问ID'; +comment on column sys_logininfor.tenant_id is '租户编号'; +comment on column sys_logininfor.user_name is '用户账号'; +comment on column sys_logininfor.client_key is '客户端'; +comment on column sys_logininfor.device_type is '设备类型'; +comment on column sys_logininfor.ipaddr is '登录IP地址'; +comment on column sys_logininfor.login_location is '登录地点'; +comment on column sys_logininfor.browser is '浏览器类型'; +comment on column sys_logininfor.os is '操作系统'; +comment on column sys_logininfor.status is '登录状态(0成功 1失败)'; +comment on column sys_logininfor.msg is '提示消息'; +comment on column sys_logininfor.login_time is '访问时间'; + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table if not exists sys_notice +( + notice_id int8, + tenant_id varchar(20) default '000000'::varchar, + notice_title varchar(50) not null, + notice_type char not null, + notice_content text, + status char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(255) default null::varchar, + constraint sys_notice_pk primary key (notice_id) +); + +comment on table sys_notice is '通知公告表'; +comment on column sys_notice.notice_id is '公告ID'; +comment on column sys_notice.tenant_id is '租户编号'; +comment on column sys_notice.notice_title is '公告标题'; +comment on column sys_notice.notice_type is '公告类型(1通知 2公告)'; +comment on column sys_notice.notice_content is '公告内容'; +comment on column sys_notice.status is '公告状态(0正常 1关闭)'; +comment on column sys_notice.create_dept is '创建部门'; +comment on column sys_notice.create_by is '创建者'; +comment on column sys_notice.create_time is '创建时间'; +comment on column sys_notice.update_by is '更新者'; +comment on column sys_notice.update_time is '更新时间'; +comment on column sys_notice.remark is '备注'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '000000', '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 103, 1, now(), null, null, '管理员'); +insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 103, 1, now(), null, null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +create table if not exists gen_table +( + table_id int8, + data_name varchar(200) default ''::varchar, + table_name varchar(200) default ''::varchar, + table_comment varchar(500) default ''::varchar, + sub_table_name varchar(64) default ''::varchar, + sub_table_fk_name varchar(64) default ''::varchar, + class_name varchar(100) default ''::varchar, + tpl_category varchar(200) default 'crud'::varchar, + package_name varchar(100) default null::varchar, + module_name varchar(30) default null::varchar, + business_name varchar(30) default null::varchar, + function_name varchar(50) default null::varchar, + function_author varchar(50) default null::varchar, + gen_type char default '0'::bpchar not null, + gen_path varchar(200) default '/'::varchar, + options varchar(1000) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint gen_table_pk primary key (table_id) +); + +comment on table gen_table is '代码生成业务表'; +comment on column gen_table.table_id is '编号'; +comment on column gen_table.data_name is '数据源名称'; +comment on column gen_table.table_name is '表名称'; +comment on column gen_table.table_comment is '表描述'; +comment on column gen_table.sub_table_name is '关联子表的表名'; +comment on column gen_table.sub_table_fk_name is '子表关联的外键名'; +comment on column gen_table.class_name is '实体类名称'; +comment on column gen_table.tpl_category is '使用的模板(CRUD单表操作 TREE树表操作)'; +comment on column gen_table.package_name is '生成包路径'; +comment on column gen_table.module_name is '生成模块名'; +comment on column gen_table.business_name is '生成业务名'; +comment on column gen_table.function_name is '生成功能名'; +comment on column gen_table.function_author is '生成功能作者'; +comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)'; +comment on column gen_table.gen_path is '生成路径(不填默认项目路径)'; +comment on column gen_table.options is '其它生成选项'; +comment on column gen_table.create_dept is '创建部门'; +comment on column gen_table.create_by is '创建者'; +comment on column gen_table.create_time is '创建时间'; +comment on column gen_table.update_by is '更新者'; +comment on column gen_table.update_time is '更新时间'; +comment on column gen_table.remark is '备注'; + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +create table if not exists gen_table_column +( + column_id int8, + table_id int8, + column_name varchar(200) default null::varchar, + column_comment varchar(500) default null::varchar, + column_type varchar(100) default null::varchar, + java_type varchar(500) default null::varchar, + java_field varchar(200) default null::varchar, + is_pk char default null::bpchar, + is_increment char default null::bpchar, + is_required char default null::bpchar, + is_insert char default null::bpchar, + is_edit char default null::bpchar, + is_list char default null::bpchar, + is_query char default null::bpchar, + query_type varchar(200) default 'EQ'::varchar, + html_type varchar(200) default null::varchar, + dict_type varchar(200) default ''::varchar, + sort int4, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint gen_table_column_pk primary key (column_id) +); + +comment on table gen_table_column is '代码生成业务表字段'; +comment on column gen_table_column.column_id is '编号'; +comment on column gen_table_column.table_id is '归属表编号'; +comment on column gen_table_column.column_name is '列名称'; +comment on column gen_table_column.column_comment is '列描述'; +comment on column gen_table_column.column_type is '列类型'; +comment on column gen_table_column.java_type is 'JAVA类型'; +comment on column gen_table_column.java_field is 'JAVA字段名'; +comment on column gen_table_column.is_pk is '是否主键(1是)'; +comment on column gen_table_column.is_increment is '是否自增(1是)'; +comment on column gen_table_column.is_required is '是否必填(1是)'; +comment on column gen_table_column.is_insert is '是否为插入字段(1是)'; +comment on column gen_table_column.is_edit is '是否编辑字段(1是)'; +comment on column gen_table_column.is_list is '是否列表字段(1是)'; +comment on column gen_table_column.is_query is '是否查询字段(1是)'; +comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)'; +comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)'; +comment on column gen_table_column.dict_type is '字典类型'; +comment on column gen_table_column.sort is '排序'; +comment on column gen_table_column.create_dept is '创建部门'; +comment on column gen_table_column.create_by is '创建者'; +comment on column gen_table_column.create_time is '创建时间'; +comment on column gen_table_column.update_by is '更新者'; +comment on column gen_table_column.update_time is '更新时间'; + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table if not exists sys_oss +( + oss_id int8, + tenant_id varchar(20) default '000000'::varchar, + file_name varchar(255) default ''::varchar not null, + original_name varchar(255) default ''::varchar not null, + file_suffix varchar(10) default ''::varchar not null, + url varchar(500) default ''::varchar not null, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + service varchar(20) default 'minio'::varchar, + constraint sys_oss_pk primary key (oss_id) +); + +comment on table sys_oss is 'OSS对象存储表'; +comment on column sys_oss.oss_id is '对象存储主键'; +comment on column sys_oss.tenant_id is '租户编码'; +comment on column sys_oss.file_name is '文件名'; +comment on column sys_oss.original_name is '原名'; +comment on column sys_oss.file_suffix is '文件后缀名'; +comment on column sys_oss.url is 'URL地址'; +comment on column sys_oss.create_by is '上传人'; +comment on column sys_oss.create_dept is '创建部门'; +comment on column sys_oss.create_time is '创建时间'; +comment on column sys_oss.update_by is '更新者'; +comment on column sys_oss.update_time is '更新时间'; +comment on column sys_oss.service is '服务商'; + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table if not exists sys_oss_config +( + oss_config_id int8, + tenant_id varchar(20) default '000000'::varchar, + config_key varchar(20) default ''::varchar not null, + access_key varchar(255) default ''::varchar, + secret_key varchar(255) default ''::varchar, + bucket_name varchar(255) default ''::varchar, + prefix varchar(255) default ''::varchar, + endpoint varchar(255) default ''::varchar, + domain varchar(255) default ''::varchar, + is_https char default 'N'::bpchar, + region varchar(255) default ''::varchar, + access_policy char(1) default '1'::bpchar not null, + status char default '1'::bpchar, + ext1 varchar(255) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default ''::varchar, + constraint sys_oss_config_pk primary key (oss_config_id) +); + +comment on table sys_oss_config is '对象存储配置表'; +comment on column sys_oss_config.oss_config_id is '主键'; +comment on column sys_oss_config.tenant_id is '租户编码'; +comment on column sys_oss_config.config_key is '配置key'; +comment on column sys_oss_config.access_key is 'accessKey'; +comment on column sys_oss_config.secret_key is '秘钥'; +comment on column sys_oss_config.bucket_name is '桶名称'; +comment on column sys_oss_config.prefix is '前缀'; +comment on column sys_oss_config.endpoint is '访问站点'; +comment on column sys_oss_config.domain is '自定义域名'; +comment on column sys_oss_config.is_https is '是否https(Y=是,N=否)'; +comment on column sys_oss_config.region is '域'; +comment on column sys_oss_config.access_policy is '桶权限类型(0=private 1=public 2=custom)'; +comment on column sys_oss_config.status is '是否默认(0=是,1=否)'; +comment on column sys_oss_config.ext1 is '扩展字段'; +comment on column sys_oss_config.create_dept is '创建部门'; +comment on column sys_oss_config.create_by is '创建者'; +comment on column sys_oss_config.create_time is '创建时间'; +comment on column sys_oss_config.update_by is '更新者'; +comment on column sys_oss_config.update_time is '更新时间'; +comment on column sys_oss_config.remark is '备注'; + +insert into sys_oss_config values (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '','N', '', '1', '0', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1', '1', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1', '1', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1240000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1', '1', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '','N', '', '1', '1', '', 103, 1, now(), 1, now(), NULL); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id int8, + client_id varchar(64) default ''::varchar, + client_key varchar(32) default ''::varchar, + client_secret varchar(255) default ''::varchar, + grant_type varchar(255) default ''::varchar, + device_type varchar(32) default ''::varchar, + active_timeout int4 default 1800, + timeout int4 default 604800, + status char(1) default '0'::bpchar, + del_flag char(1) default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint sys_client_pk primary key (id) +); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); + +create table if not exists test_demo +( + id int8, + tenant_id varchar(20) default '000000', + dept_id int8, + user_id int8, + order_num int4 default 0, + test_key varchar(255), + value varchar(255), + version int4 default 0, + create_dept int8, + create_time timestamp, + create_by int8, + update_time timestamp, + update_by int8, + del_flag int4 default 0 +); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.tenant_id is '租户编号'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table if not exists test_tree +( + id int8, + tenant_id varchar(20) default '000000', + parent_id int8 default 0, + dept_id int8, + user_id int8, + tree_name varchar(255), + version int4 default 0, + create_dept int8, + create_time timestamp, + create_by int8, + update_time timestamp, + update_by int8, + del_flag integer default 0 +); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.tenant_id is '租户编号'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, now(), 1, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, now(), 1, NULL, NULL, 0); + +-- 字符串自动转时间 避免框架时间查询报错问题 +create or replace function cast_varchar_to_timestamp(varchar) returns timestamptz as $$ +select to_timestamp($1, 'yyyy-mm-dd hh24:mi:ss'); +$$ language sql strict ; + +create cast (varchar as timestamptz) with function cast_varchar_to_timestamp as IMPLICIT; diff --git a/script/sql/postgres/postgres_ry_workflow.sql b/script/sql/postgres/postgres_ry_workflow.sql new file mode 100644 index 0000000..80cd414 --- /dev/null +++ b/script/sql/postgres/postgres_ry_workflow.sql @@ -0,0 +1,405 @@ +-- ---------------------------- +-- 0、warm-flow-all.sql,地址:https://gitee.com/dromara/warm-flow/blob/master/sql/postgresql/postgresql-warm-flow-all.sql +-- ---------------------------- +CREATE TABLE flow_definition +( + id int8 NOT NULL, -- 主键id + flow_code varchar(40) NOT NULL, -- 流程编码 + flow_name varchar(100) NOT NULL, -- 流程名称 + category varchar(100) NULL, -- 流程类别 + "version" varchar(20) NOT NULL, -- 流程版本 + is_publish int2 NOT NULL DEFAULT 0, -- 是否发布(0未发布 1已发布 9失效) + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + activity_status int2 NOT NULL DEFAULT 1, -- 流程激活状态(0挂起 1激活) + listener_type varchar(100) NULL, -- 监听器类型 + listener_path varchar(400) NULL, -- 监听器路径 + ext varchar(500) NULL, -- 扩展字段,预留给业务系统使用 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_definition_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_definition IS '流程定义表'; + +COMMENT ON COLUMN flow_definition.id IS '主键id'; +COMMENT ON COLUMN flow_definition.flow_code IS '流程编码'; +COMMENT ON COLUMN flow_definition.flow_name IS '流程名称'; +COMMENT ON COLUMN flow_definition.category IS '流程类别'; +COMMENT ON COLUMN flow_definition."version" IS '流程版本'; +COMMENT ON COLUMN flow_definition.is_publish IS '是否发布(0未发布 1已发布 9失效)'; +COMMENT ON COLUMN flow_definition.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_definition.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_definition.activity_status IS '流程激活状态(0挂起 1激活)'; +COMMENT ON COLUMN flow_definition.listener_type IS '监听器类型'; +COMMENT ON COLUMN flow_definition.listener_path IS '监听器路径'; +COMMENT ON COLUMN flow_definition.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_definition.create_time IS '创建时间'; +COMMENT ON COLUMN flow_definition.update_time IS '更新时间'; +COMMENT ON COLUMN flow_definition.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_definition.tenant_id IS '租户id'; + +CREATE TABLE flow_node +( + id int8 NOT NULL, -- 主键id + node_type int2 NOT NULL, -- 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + definition_id int8 NOT NULL, -- 流程定义id + node_code varchar(100) NOT NULL, -- 流程节点编码 + node_name varchar(100) NULL, -- 流程节点名称 + permission_flag varchar(200) NULL, -- 权限标识(权限类型:权限标识,可以多个,用逗号隔开) + node_ratio numeric(6, 3) NULL, -- 流程签署比例值 + coordinate varchar(100) NULL, -- 坐标 + skip_any_node varchar(100) NULL DEFAULT 'N':: character varying, -- 是否可以退回任意节点(Y是 N否)即将删除 + any_node_skip varchar(100) NULL, -- 任意结点跳转 + listener_type varchar(100) NULL, -- 监听器类型 + listener_path varchar(400) NULL, -- 监听器路径 + handler_type varchar(100) NULL, -- 处理器类型 + handler_path varchar(400) NULL, -- 处理器路径 + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + "version" varchar(20) NOT NULL, -- 版本 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_node_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_node IS '流程节点表'; + +COMMENT ON COLUMN flow_node.id IS '主键id'; +COMMENT ON COLUMN flow_node.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_node.definition_id IS '流程定义id'; +COMMENT ON COLUMN flow_node.node_code IS '流程节点编码'; +COMMENT ON COLUMN flow_node.node_name IS '流程节点名称'; +COMMENT ON COLUMN flow_node.permission_flag IS '权限标识(权限类型:权限标识,可以多个,用逗号隔开)'; +COMMENT ON COLUMN flow_node.node_ratio IS '流程签署比例值'; +COMMENT ON COLUMN flow_node.coordinate IS '坐标'; +COMMENT ON COLUMN flow_node.skip_any_node IS '是否可以退回任意节点(Y是 N否)即将删除'; +COMMENT ON COLUMN flow_node.any_node_skip IS '任意结点跳转'; +COMMENT ON COLUMN flow_node.listener_type IS '监听器类型'; +COMMENT ON COLUMN flow_node.listener_path IS '监听器路径'; +COMMENT ON COLUMN flow_node.handler_type IS '处理器类型'; +COMMENT ON COLUMN flow_node.handler_path IS '处理器路径'; +COMMENT ON COLUMN flow_node.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_node.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_node."version" IS '版本'; +COMMENT ON COLUMN flow_node.create_time IS '创建时间'; +COMMENT ON COLUMN flow_node.update_time IS '更新时间'; +COMMENT ON COLUMN flow_node.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_node.tenant_id IS '租户id'; + + +CREATE TABLE flow_skip +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 流程定义id + now_node_code varchar(100) NOT NULL, -- 当前流程节点的编码 + now_node_type int2 NULL, -- 当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + next_node_code varchar(100) NOT NULL, -- 下一个流程节点的编码 + next_node_type int2 NULL, -- 下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + skip_name varchar(100) NULL, -- 跳转名称 + skip_type varchar(40) NULL, -- 跳转类型(PASS审批通过 REJECT退回) + skip_condition varchar(200) NULL, -- 跳转条件 + coordinate varchar(100) NULL, -- 坐标 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_skip_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_skip IS '节点跳转关联表'; + +COMMENT ON COLUMN flow_skip.id IS '主键id'; +COMMENT ON COLUMN flow_skip.definition_id IS '流程定义id'; +COMMENT ON COLUMN flow_skip.now_node_code IS '当前流程节点的编码'; +COMMENT ON COLUMN flow_skip.now_node_type IS '当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_skip.next_node_code IS '下一个流程节点的编码'; +COMMENT ON COLUMN flow_skip.next_node_type IS '下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_skip.skip_name IS '跳转名称'; +COMMENT ON COLUMN flow_skip.skip_type IS '跳转类型(PASS审批通过 REJECT退回)'; +COMMENT ON COLUMN flow_skip.skip_condition IS '跳转条件'; +COMMENT ON COLUMN flow_skip.coordinate IS '坐标'; +COMMENT ON COLUMN flow_skip.create_time IS '创建时间'; +COMMENT ON COLUMN flow_skip.update_time IS '更新时间'; +COMMENT ON COLUMN flow_skip.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_skip.tenant_id IS '租户id'; + +CREATE TABLE flow_instance +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 对应flow_definition表的id + business_id varchar(40) NOT NULL, -- 业务id + node_type int2 NOT NULL, -- 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + node_code varchar(40) NOT NULL, -- 流程节点编码 + node_name varchar(100) NULL, -- 流程节点名称 + variable text NULL, -- 任务变量 + flow_status varchar(20) NOT NULL, -- 流程状态(0待提交 1审批中 2 审批通过 8已完成 9已退回 10失效) + activity_status int2 NOT NULL DEFAULT 1, -- 流程激活状态(0挂起 1激活) + def_json text NULL, -- 流程定义json + create_by varchar(64) NULL DEFAULT '':: character varying, -- 创建者 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + ext varchar(500) NULL, -- 扩展字段,预留给业务系统使用 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_instance_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_instance IS '流程实例表'; + +COMMENT ON COLUMN flow_instance.id IS '主键id'; +COMMENT ON COLUMN flow_instance.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_instance.business_id IS '业务id'; +COMMENT ON COLUMN flow_instance.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_instance.node_code IS '流程节点编码'; +COMMENT ON COLUMN flow_instance.node_name IS '流程节点名称'; +COMMENT ON COLUMN flow_instance.variable IS '任务变量'; +COMMENT ON COLUMN flow_instance.flow_status IS '流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回 8已完成 9已退回 10失效)'; +COMMENT ON COLUMN flow_instance.activity_status IS '流程激活状态(0挂起 1激活)'; +COMMENT ON COLUMN flow_instance.def_json IS '流程定义json'; +COMMENT ON COLUMN flow_instance.create_by IS '创建者'; +COMMENT ON COLUMN flow_instance.create_time IS '创建时间'; +COMMENT ON COLUMN flow_instance.update_time IS '更新时间'; +COMMENT ON COLUMN flow_instance.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_instance.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_instance.tenant_id IS '租户id'; + +CREATE TABLE flow_task +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 对应flow_definition表的id + instance_id int8 NOT NULL, -- 对应flow_instance表的id + node_code varchar(100) NOT NULL, -- 节点编码 + node_name varchar(100) NULL, -- 节点名称 + node_type int2 NOT NULL, -- 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_task_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_task IS '待办任务表'; + +COMMENT ON COLUMN flow_task.id IS '主键id'; +COMMENT ON COLUMN flow_task.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_task.instance_id IS '对应flow_instance表的id'; +COMMENT ON COLUMN flow_task.node_code IS '节点编码'; +COMMENT ON COLUMN flow_task.node_name IS '节点名称'; +COMMENT ON COLUMN flow_task.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_task.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_task.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_task.create_time IS '创建时间'; +COMMENT ON COLUMN flow_task.update_time IS '更新时间'; +COMMENT ON COLUMN flow_task.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_task.tenant_id IS '租户id'; + +CREATE TABLE flow_his_task +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 对应flow_definition表的id + instance_id int8 NOT NULL, -- 对应flow_instance表的id + task_id int8 NOT NULL, -- 对应flow_task表的id + node_code varchar(200) NULL, -- 开始节点编码 + node_name varchar(200) NULL, -- 开始节点名称 + node_type int2 NULL, -- 开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + target_node_code varchar(200) NULL, -- 目标节点编码 + target_node_name varchar(200) NULL, -- 结束节点名称 + approver varchar(40) NULL, -- 审批者 + cooperate_type int2 NOT NULL DEFAULT 0, -- 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + collaborator varchar(40) NULL, -- 协作人(只有转办、会签、票签、委派) + skip_type varchar(10) NULL, -- 流转类型(PASS通过 REJECT退回 NONE无动作) + flow_status varchar(20) NOT NULL, -- 流程状态(0待提交 1审批中 2 审批通过 8已完成 9已退回 10失效) + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + ext varchar(500) NULL, -- 扩展字段,预留给业务系统使用 + message varchar(500) NULL, -- 审批意见 + variable text NULL, -- 任务变量 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_his_task_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_his_task IS '历史任务记录表'; + +COMMENT ON COLUMN flow_his_task.id IS '主键id'; +COMMENT ON COLUMN flow_his_task.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_his_task.instance_id IS '对应flow_instance表的id'; +COMMENT ON COLUMN flow_his_task.task_id IS '对应flow_task表的id'; +COMMENT ON COLUMN flow_his_task.node_code IS '开始节点编码'; +COMMENT ON COLUMN flow_his_task.node_name IS '开始节点名称'; +COMMENT ON COLUMN flow_his_task.node_type IS '开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_his_task.target_node_code IS '目标节点编码'; +COMMENT ON COLUMN flow_his_task.target_node_name IS '结束节点名称'; +COMMENT ON COLUMN flow_his_task.approver IS '审批者'; +COMMENT ON COLUMN flow_his_task.cooperate_type IS '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)'; +COMMENT ON COLUMN flow_his_task.collaborator IS '协作人'; +COMMENT ON COLUMN flow_his_task.skip_type IS '流转类型(PASS通过 REJECT退回 NONE无动作)'; +COMMENT ON COLUMN flow_his_task.flow_status IS '流程状态(1审批中 2 审批通过 9已退回 10失效)'; +COMMENT ON COLUMN flow_his_task.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_his_task.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_his_task.message IS '审批意见'; +COMMENT ON COLUMN flow_his_task.variable IS '任务变量'; +COMMENT ON COLUMN flow_his_task.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_his_task.create_time IS '任务开始时间'; +COMMENT ON COLUMN flow_his_task.update_time IS '审批完成时间'; +COMMENT ON COLUMN flow_his_task.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_his_task.tenant_id IS '租户id'; + +CREATE TABLE flow_user +( + id int8 NOT NULL, -- 主键id + "type" bpchar(1) NOT NULL, -- 人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3流程实例的抄送人权限 4待办任务的委托人权限) + processed_by varchar(80) NULL, -- 权限人 + associated int8 NOT NULL, -- 任务表id + create_time timestamp NULL, -- 创建时间 + create_by varchar(80) NULL, -- 创建人 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_user_pk PRIMARY KEY (id) +); +CREATE INDEX user_processed_type ON flow_user USING btree (processed_by, type); +COMMENT ON TABLE flow_user IS '流程用户表'; + +COMMENT ON COLUMN flow_user.id IS '主键id'; +COMMENT ON COLUMN flow_user."type" IS '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)'; +COMMENT ON COLUMN flow_user.processed_by IS '权限人'; +COMMENT ON COLUMN flow_user.associated IS '任务表id'; +COMMENT ON COLUMN flow_user.create_time IS '创建时间'; +COMMENT ON COLUMN flow_user.create_by IS '创建人'; +COMMENT ON COLUMN flow_user.update_time IS '更新时间'; +COMMENT ON COLUMN flow_user.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_user.tenant_id IS '租户id'; + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +CREATE TABLE flow_category +( + category_id int8 NOT NULL, + tenant_id VARCHAR(20) DEFAULT '000000'::varchar, + parent_id int8 DEFAULT 0, + ancestors VARCHAR(500) DEFAULT ''::varchar, + category_name VARCHAR(30) NOT NULL, + order_num INT DEFAULT 0, + del_flag CHAR DEFAULT '0'::bpchar, + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + PRIMARY KEY (category_id) +); + +COMMENT ON TABLE flow_category IS '流程分类'; +COMMENT ON COLUMN flow_category.category_id IS '流程分类ID'; +COMMENT ON COLUMN flow_category.tenant_id IS '租户编号'; +COMMENT ON COLUMN flow_category.parent_id IS '父流程分类id'; +COMMENT ON COLUMN flow_category.ancestors IS '祖级列表'; +COMMENT ON COLUMN flow_category.category_name IS '流程分类名称'; +COMMENT ON COLUMN flow_category.order_num IS '显示顺序'; +COMMENT ON COLUMN flow_category.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_category.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_category.create_by IS '创建者'; +COMMENT ON COLUMN flow_category.create_time IS '创建时间'; +COMMENT ON COLUMN flow_category.update_by IS '更新者'; +COMMENT ON COLUMN flow_category.update_time IS '更新时间'; + +INSERT INTO flow_category VALUES (100, '000000', 0, '0', 'OA审批', 0, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (101, '000000', 100, '0,100', '假勤管理', 0, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (102, '000000', 100, '0,100', '人事管理', 1, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (103, '000000', 101, '0,100,101', '请假', 0, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (104, '000000', 101, '0,100,101', '出差', 1, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (105, '000000', 101, '0,100,101', '加班', 2, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (106, '000000', 101, '0,100,101', '换班', 3, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (107, '000000', 101, '0,100,101', '外出', 4, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (108, '000000', 102, '0,100,102', '转正', 1, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (109, '000000', 102, '0,100,102', '离职', 2, '0', 103, 1, now(), NULL, NULL); + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +CREATE TABLE test_leave +( + id int8 NOT NULL, + tenant_id VARCHAR(20) DEFAULT '000000'::varchar, + leave_type VARCHAR(255) NOT NULL, + start_date TIMESTAMP NOT NULL, + end_date TIMESTAMP NOT NULL, + leave_days int2 NOT NULL, + remark VARCHAR(255), + status VARCHAR(255), + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + PRIMARY KEY (id) +); + +COMMENT ON TABLE test_leave IS '请假申请表'; +COMMENT ON COLUMN test_leave.id IS 'id'; +COMMENT ON COLUMN test_leave.tenant_id IS '租户编号'; +COMMENT ON COLUMN test_leave.leave_type IS '请假类型'; +COMMENT ON COLUMN test_leave.start_date IS '开始时间'; +COMMENT ON COLUMN test_leave.end_date IS '结束时间'; +COMMENT ON COLUMN test_leave.leave_days IS '请假天数'; +COMMENT ON COLUMN test_leave.remark IS '请假原因'; +COMMENT ON COLUMN test_leave.status IS '状态'; +COMMENT ON COLUMN test_leave.create_dept IS '创建部门'; +COMMENT ON COLUMN test_leave.create_by IS '创建者'; +COMMENT ON COLUMN test_leave.create_time IS '创建时间'; +COMMENT ON COLUMN test_leave.update_by IS '更新者'; +COMMENT ON COLUMN test_leave.update_time IS '更新时间'; + +INSERT INTO sys_menu VALUES ('11616', '工作流', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11623', '流程分类查询', '11622', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11624', '流程分类新增', '11622', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11625', '流程分类修改', '11622', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11627', '流程分类导出', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11638', '请假申请', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu VALUES ('11639', '请假申请查询', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11640', '请假申请新增', '11638', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11641', '请假申请修改', '11638', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11642', '请假申请删除', '11638', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11643', '请假申请导出', '11638', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, now(), NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, now(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, now(), NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (15, '000000', '任务状态', 'wf_task_status', 103, 1, now(), NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, now(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '已完成'); +INSERT INTO sys_dict_data VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已作废'); +INSERT INTO sys_dict_data VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已退回'); +INSERT INTO sys_dict_data VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, now(), NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '动态表单'); +INSERT INTO sys_dict_data VALUES (48, '000000', 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (49, '000000', 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (50, '000000', 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (51, '000000', 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (52, '000000', 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (53, '000000', 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (54, '000000', 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (55, '000000', 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (56, '000000', 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (57, '000000', 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (58, '000000', 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (59, '000000', 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '超时'); + diff --git a/script/sql/ry_job.sql b/script/sql/ry_job.sql new file mode 100644 index 0000000..be0f5e1 --- /dev/null +++ b/script/sql/ry_job.sql @@ -0,0 +1,519 @@ +SET NAMES utf8mb4; + +CREATE TABLE `sj_namespace` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(64) NOT NULL COMMENT '名称', + `unique_id` varchar(64) NOT NULL COMMENT '唯一id', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_name` (`name`), + UNIQUE KEY `uk_unique_id` (`unique_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='命名空间'; + +INSERT INTO `sj_namespace` VALUES (1, 'Development', 'dev', '', 0, now(), now()); +INSERT INTO `sj_namespace` VALUES (2, 'Production', 'prod', '', 0, now(), now()); + +CREATE TABLE `sj_group_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '组名称', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '组描述', + `token` varchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' COMMENT 'token', + `group_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用', + `version` int(11) NOT NULL COMMENT '版本号', + `group_partition` int(11) NOT NULL COMMENT '分区', + `id_generator_mode` tinyint(4) NOT NULL DEFAULT 1 COMMENT '唯一id生成模式 默认号段模式', + `init_scene` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否初始化场景 0:否 1:是', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='组配置'; + +INSERT INTO `sj_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); +INSERT INTO `sj_group_config` VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); + +CREATE TABLE `sj_notify_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `notify_name` varchar(64) NOT NULL DEFAULT '' COMMENT '通知名称', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务', + `notify_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知状态 0、未启用 1、启用', + `recipient_ids` varchar(128) NOT NULL COMMENT '接收人id列表', + `notify_threshold` int(11) NOT NULL DEFAULT 0 COMMENT '通知阈值', + `notify_scene` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知场景', + `rate_limiter_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '限流状态 0、未启用 1、启用', + `rate_limiter_threshold` int(11) NOT NULL DEFAULT 0 COMMENT '每秒限流阈值', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='通知配置'; + +CREATE TABLE `sj_notify_recipient` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `recipient_name` varchar(64) NOT NULL COMMENT '接收人名称', + `notify_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook', + `notify_attribute` varchar(512) NOT NULL COMMENT '配置属性', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id` (`namespace_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='告警通知接收人'; + +CREATE TABLE `sj_retry_dead_letter_0` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_namespace_id_group_name_unique_id` (`namespace_id`, `group_name`, `unique_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='死信队列表'; + +CREATE TABLE `sj_retry_task_0` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `next_trigger_at` datetime NOT NULL COMMENT '下次触发时间', + `retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数', + `retry_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '重试状态 0、重试中 1、成功 2、最大重试次数', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_namespace_id_group_name_task_type` (`namespace_id`, `group_name`, `task_type`), + KEY `idx_namespace_id_group_name_retry_status` (`namespace_id`, `group_name`, `retry_status`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_name_unique_id` (`namespace_id`, `group_name`, `unique_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务表'; + +CREATE TABLE `sj_retry_task_log` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `retry_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '重试状态 0、重试中 1、成功 2、最大次数', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_retry_status` (`retry_status`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_unique_id` (`unique_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务日志基础信息表'; + +CREATE TABLE `sj_retry_task_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `message` longtext NOT NULL COMMENT '异常信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `unique_id`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务调度日志信息记录表'; + +CREATE TABLE `sj_retry_scene_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用', + `max_retry_count` int(11) NOT NULL DEFAULT 5 COMMENT '最大重试次数', + `back_off` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式', + `trigger_interval` varchar(16) NOT NULL DEFAULT '' COMMENT '间隔时长', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `deadline_request` bigint(20) unsigned NOT NULL DEFAULT 60000 COMMENT 'Deadline Request 调用链超时 单位毫秒', + `executor_timeout` int(11) unsigned NOT NULL DEFAULT 5 COMMENT '任务执行超时时间,单位秒', + `route_key` tinyint(4) NOT NULL DEFAULT 4 COMMENT '路由策略', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='场景配置'; + +CREATE TABLE `sj_server_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `host_id` varchar(64) NOT NULL COMMENT '主机id', + `host_ip` varchar(64) NOT NULL COMMENT '机器ip', + `host_port` int(16) NOT NULL COMMENT '机器端口', + `expire_at` datetime NOT NULL COMMENT '过期时间', + `node_type` tinyint(4) NOT NULL COMMENT '节点类型 1、客户端 2、是服务端', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_expire_at_node_type` (`expire_at`, `node_type`), + UNIQUE KEY `uk_host_id_host_ip` (`host_id`, `host_ip`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='服务器节点'; + +CREATE TABLE `sj_distributed_lock` +( + `name` varchar(64) NOT NULL COMMENT '锁名称', + `lock_until` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '锁定时长', + `locked_at` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '锁定时间', + `locked_by` varchar(255) NOT NULL COMMENT '锁定者', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='锁定表'; + +CREATE TABLE `sj_system_user` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `username` varchar(64) NOT NULL COMMENT '账号', + `password` varchar(128) NOT NULL COMMENT '密码', + `role` tinyint(4) NOT NULL DEFAULT 0 COMMENT '角色:1-普通用户、2-管理员', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_username` (`username`) USING BTREE +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户表'; + +-- pwd: admin +INSERT INTO `sj_system_user` VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now()); + +CREATE TABLE `sj_system_user_permission` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `system_user_id` bigint(20) NOT NULL COMMENT '系统用户id', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_system_user_id` (`namespace_id`, `group_name`, `system_user_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户权限表'; + +CREATE TABLE `sj_sequence_alloc` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '组名称', + `max_id` bigint(20) NOT NULL DEFAULT 1 COMMENT '最大id', + `step` int(11) NOT NULL DEFAULT 100 COMMENT '步长', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='号段模式序号ID分配表'; + +-- 分布式调度DDL +CREATE TABLE `sj_job` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_name` varchar(64) NOT NULL COMMENT '名称', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '参数类型 ', + `next_trigger_at` bigint(13) NOT NULL COMMENT '下次触发时间', + `job_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务状态 0、关闭、1、开启', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、集群 2、广播 3、切片', + `route_key` tinyint(4) NOT NULL DEFAULT 4 COMMENT '路由策略', + `executor_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '执行器类型', + `executor_info` varchar(255) DEFAULT NULL COMMENT '执行器名称', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `block_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', + `max_retry_times` int(11) NOT NULL DEFAULT 0 COMMENT '最大重试次数', + `parallel_num` int(11) NOT NULL DEFAULT 1 COMMENT '并行数', + `retry_interval` int(11) NOT NULL DEFAULT 0 COMMENT '重试间隔(s)', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `resident` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否是常驻任务', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `owner_id` bigint(20) NULL COMMENT '负责人id', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_job_status_bucket_index` (`job_status`, `bucket_index`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务信息'; + +INSERT INTO `sj_job` VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '', '', 0 , now(), now()); + +CREATE TABLE `sj_job_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '任务批次id', + `task_id` bigint(20) NOT NULL COMMENT '调度任务id', + `message` longtext NOT NULL COMMENT '调度信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_id` (`task_batch_id`, `task_id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='调度日志'; + +CREATE TABLE `sj_job_task` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '调度任务id', + `parent_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '父执行器id', + `task_status` tinyint NOT NULL DEFAULT 0 COMMENT '执行的状态 0、失败 1、成功', + `retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数', + `mr_stage` tinyint DEFAULT NULL COMMENT '动态分片所处阶段 1:map 2:reduce 3:mergeReduce', + `leaf` tinyint NOT NULL DEFAULT '1' COMMENT '叶子节点', + `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '任务名称', + `client_info` varchar(128) DEFAULT NULL COMMENT '客户端地址 clientId#ip:port', + `wf_context` text DEFAULT NULL COMMENT '工作流全局上下文', + `result_message` text NOT NULL COMMENT '执行结果', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint NOT NULL DEFAULT 1 COMMENT '参数类型 ', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_status` (`task_batch_id`, `task_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务实例'; + +CREATE TABLE `sj_job_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务id', + `workflow_node_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流节点id', + `parent_workflow_node_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流任务父批次id', + `workflow_task_batch_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流任务批次id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', + `execution_at` bigint(13) NOT NULL DEFAULT 0 COMMENT '任务执行时间', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `parent_id` varchar(64) NOT NULL DEFAULT '' COMMENT '父节点', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`job_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_workflow_task_batch_id_workflow_node_id` (`workflow_task_batch_id`, `workflow_node_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务批次'; + +CREATE TABLE `sj_job_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `business_id` bigint NOT NULL COMMENT '业务id (job_id或workflow_id)', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `success_num` int NOT NULL DEFAULT 0 COMMENT '执行成功-日志数量', + `fail_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `fail_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `stop_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `stop_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `cancel_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `cancel_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_business_id` (`namespace_id`, `group_name`, business_id), + UNIQUE KEY `uk_trigger_at_system_task_type_business_id` (`trigger_at`, `system_task_type`, `business_id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Job'; + +CREATE TABLE `sj_retry_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `scene_name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '场景名称', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `running_num` int NOT NULL DEFAULT 0 COMMENT '重试中-日志数量', + `finish_num` int NOT NULL DEFAULT 0 COMMENT '重试完成-日志数量', + `max_count_num` int NOT NULL DEFAULT 0 COMMENT '重试到达最大次数-日志数量', + `suspend_num` int NOT NULL DEFAULT 0 COMMENT '暂停重试-日志数量', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_trigger_at` (`trigger_at`), + UNIQUE KEY `uk_scene_name_trigger_at` (`namespace_id`, `group_name`, `scene_name`, `trigger_at`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Retry'; + +CREATE TABLE `sj_workflow` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `workflow_name` varchar(64) NOT NULL COMMENT '工作流名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '工作流状态 0、关闭、1、开启', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `next_trigger_at` bigint NOT NULL COMMENT '下次触发时间', + `block_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '上下文', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `version` int(11) NOT NULL COMMENT '版本号', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流'; + +CREATE TABLE `sj_workflow_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `node_name` varchar(64) NOT NULL COMMENT '节点名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流ID', + `node_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、任务节点 2、条件节点', + `expression_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '1、SpEl、2、Aviator 3、QL', + `fail_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '失败策略 1、跳过 2、阻塞', + `workflow_node_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '工作流节点状态 0、关闭、1、开启', + `priority_level` int(11) NOT NULL DEFAULT 1 COMMENT '优先级', + `node_info` text DEFAULT NULL COMMENT '节点信息 ', + `version` int(11) NOT NULL COMMENT '版本号', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流节点'; + +CREATE TABLE `sj_workflow_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流任务id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '全局上下文', + `execution_at` bigint(13) NOT NULL DEFAULT 0 COMMENT '任务执行时间', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `version` int(11) NOT NULL DEFAULT 1 COMMENT '版本号', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`workflow_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流批次'; diff --git a/script/sql/ry_vue_5.X.sql b/script/sql/ry_vue_5.X.sql new file mode 100644 index 0000000..48e5f35 --- /dev/null +++ b/script/sql/ry_vue_5.X.sql @@ -0,0 +1,962 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id bigint not null comment '主键', + user_id bigint not null comment '用户ID', + tenant_id varchar(20) default '000000' comment '租户id', + auth_id varchar(255) not null comment '平台+平台唯一id', + source varchar(255) not null comment '用户来源', + open_id varchar(255) default null comment '平台编号唯一id', + user_name varchar(30) not null comment '登录账号', + nick_name varchar(30) default '' comment '用户昵称', + email varchar(255) default '' comment '用户邮箱', + avatar varchar(500) default '' comment '头像地址', + access_token varchar(255) not null comment '用户的授权令牌', + expire_in int default null comment '用户的授权令牌的有效期,部分平台可能没有', + refresh_token varchar(255) default null comment '刷新令牌,部分平台可能没有', + access_code varchar(255) default null comment '平台的授权信息,部分平台可能没有', + union_id varchar(255) default null comment '用户的 unionid', + scope varchar(255) default null comment '授予的权限,部分平台可能没有', + token_type varchar(255) default null comment '个别平台的授权信息,部分平台可能没有', + id_token varchar(2000) default null comment 'id token,部分平台可能没有', + mac_algorithm varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + mac_key varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + code varchar(255) default null comment '用户的授权code,部分平台可能没有', + oauth_token varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + oauth_token_secret varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + PRIMARY KEY (id) +) engine=innodb comment = '社会化关系表'; + + +-- ---------------------------- +-- 租户表 +-- ---------------------------- +create table sys_tenant +( + id bigint(20) not null comment 'id', + tenant_id varchar(20) not null comment '租户编号', + contact_user_name varchar(20) comment '联系人', + contact_phone varchar(20) comment '联系电话', + company_name varchar(50) comment '企业名称', + license_number varchar(30) comment '统一社会信用代码', + address varchar(200) comment '地址', + intro varchar(200) comment '企业简介', + domain varchar(200) comment '域名', + remark varchar(200) comment '备注', + package_id bigint(20) comment '租户套餐编号', + expire_time datetime comment '过期时间', + account_count int default -1 comment '用户数量(-1不限制)', + status char(1) default '0' comment '租户状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + primary key (id) +) engine=innodb comment = '租户表'; + + +-- ---------------------------- +-- 初始化-租户表数据 +-- ---------------------------- + +insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有限公司', null, null, '多租户通用后台管理管理系统', null, null, null, null, -1, '0', '0', 103, 1, sysdate(), null, null); + + +-- ---------------------------- +-- 租户套餐表 +-- ---------------------------- +create table sys_tenant_package ( + package_id bigint(20) not null comment '租户套餐id', + package_name varchar(20) comment '套餐名称', + menu_ids varchar(3000) comment '关联菜单id', + remark varchar(200) comment '备注', + menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示', + status char(1) default '0' comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + primary key (package_id) +) engine=innodb comment = '租户套餐表'; + + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table sys_dept ( + dept_id bigint(20) not null comment '部门id', + tenant_id varchar(20) default '000000' comment '租户编号', + parent_id bigint(20) default 0 comment '父部门id', + ancestors varchar(500) default '' comment '祖级列表', + dept_name varchar(30) default '' comment '部门名称', + dept_category varchar(100) default null comment '部门类别编码', + order_num int(4) default 0 comment '显示顺序', + leader bigint(20) default null comment '负责人', + phone varchar(11) default null comment '联系电话', + email varchar(50) default null comment '邮箱', + status char(1) default '0' comment '部门状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (dept_id) +) engine=innodb comment = '部门表'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- + + +insert into sys_dept values(100, '000000', 0, '0', 'XXX科技', null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(101, '000000', 100, '0,100', '深圳总公司', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(102, '000000', 100, '0,100', '长沙分公司', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(103, '000000', 101, '0,100,101', '研发部门', null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(104, '000000', 101, '0,100,101', '市场部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(105, '000000', 101, '0,100,101', '测试部门', null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(106, '000000', 101, '0,100,101', '财务部门', null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(107, '000000', 101, '0,100,101', '运维部门', null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(108, '000000', 102, '0,100,102', '市场部门', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table sys_user ( + user_id bigint(20) not null comment '用户ID', + tenant_id varchar(20) default '000000' comment '租户编号', + dept_id bigint(20) default null comment '部门ID', + user_name varchar(30) not null comment '用户账号', + nick_name varchar(30) not null comment '用户昵称', + user_type varchar(10) default 'sys_user' comment '用户类型(sys_user系统用户)', + email varchar(50) default '' comment '用户邮箱', + phonenumber varchar(11) default '' comment '手机号码', + sex char(1) default '0' comment '用户性别(0男 1女 2未知)', + avatar bigint(20) comment '头像地址', + password varchar(100) default '' comment '密码', + status char(1) default '0' comment '帐号状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + login_ip varchar(128) default '' comment '最后登录IP', + login_date datetime comment '最后登录时间', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (user_id) +) engine=innodb comment = '用户信息表'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '管理员'); +insert into sys_user values(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 3, sysdate(), null); +insert into sys_user values(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 4, sysdate(), null); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table sys_post +( + post_id bigint(20) not null comment '岗位ID', + tenant_id varchar(20) default '000000' comment '租户编号', + dept_id bigint(20) not null comment '部门id', + post_code varchar(64) not null comment '岗位编码', + post_category varchar(100) default null comment '岗位类别编码', + post_name varchar(50) not null comment '岗位名称', + post_sort int(4) not null comment '显示顺序', + status char(1) not null comment '状态(0正常 1停用)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (post_id) +) engine=innodb comment = '岗位信息表'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, '000000', 103, 'ceo', null, '董事长', 1, '0', 103, 1, sysdate(), null, null, ''); +insert into sys_post values(2, '000000', 100, 'se', null, '项目经理', 2, '0', 103, 1, sysdate(), null, null, ''); +insert into sys_post values(3, '000000', 100, 'hr', null, '人力资源', 3, '0', 103, 1, sysdate(), null, null, ''); +insert into sys_post values(4, '000000', 100, 'user', null, '普通员工', 4, '0', 103, 1, sysdate(), null, null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table sys_role ( + role_id bigint(20) not null comment '角色ID', + tenant_id varchar(20) default '000000' comment '租户编号', + role_name varchar(30) not null comment '角色名称', + role_key varchar(100) not null comment '角色权限字符串', + role_sort int(4) not null comment '显示顺序', + data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示', + dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示', + status char(1) not null comment '角色状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (role_id) +) engine=innodb comment = '角色信息表'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values(1, '000000', '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 103, 1, sysdate(), null, null, '超级管理员'); +insert into sys_role values(3, '000000', '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate(), null, null, ''); +insert into sys_role values(4, '000000', '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate(), null, null, ''); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table sys_menu ( + menu_id bigint(20) not null comment '菜单ID', + menu_name varchar(50) not null comment '菜单名称', + parent_id bigint(20) default 0 comment '父菜单ID', + order_num int(4) default 0 comment '显示顺序', + path varchar(200) default '' comment '路由地址', + component varchar(255) default null comment '组件路径', + query_param varchar(255) default null comment '路由参数', + is_frame int(1) default 1 comment '是否为外链(0是 1否)', + is_cache int(1) default 0 comment '是否缓存(0缓存 1不缓存)', + menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)', + visible char(1) default 0 comment '显示状态(0显示 1隐藏)', + status char(1) default 0 comment '菜单状态(0正常 1停用)', + perms varchar(100) default null comment '权限标识', + icon varchar(100) default '#' comment '菜单图标', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注', + primary key (menu_id) +) engine=innodb comment = '菜单权限表'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', 1, 0, 'M', '0', '0', '', 'system', 103, 1, sysdate(), null, null, '系统管理目录'); +insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', null, '', 1, 0, 'M', '0', '0', '', 'chart', 103, 1, sysdate(), null, null, '租户管理目录'); +insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), null, null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 103, 1, sysdate(), null, null, '系统工具目录'); +insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide', 103, 1, sysdate(), null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu values('5', '测试菜单', '0', '5', 'demo', null, '', 1, 0, 'M', '0', '0', '', 'star', 103, 1, sysdate(), null, null, '测试菜单'); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 103, 1, sysdate(), null, null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, sysdate(), null, null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 103, 1, sysdate(), null, null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, sysdate(), null, null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 103, 1, sysdate(), null, null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 103, 1, sysdate(), null, null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 103, 1, sysdate(), null, null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 103, 1, sysdate(), null, null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 103, 1, sysdate(), null, null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, sysdate(), null, null, '在线用户菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, sysdate(), null, null, '缓存监控菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, sysdate(), null, null, '代码生成菜单'); +insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', 1, 0, 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, sysdate(), null, null, '租户管理菜单'); +insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, sysdate(), null, null, '租户套餐管理菜单'); +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate(), null, null, '客户端管理菜单'); + +-- springboot-admin监控 +insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', 'monitor/admin/index', '', 1, 0, 'C', '0', '0', 'monitor:admin:list', 'dashboard', 103, 1, sysdate(), null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, sysdate(), null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values('120', '任务调度中心', '2', '6', 'snailjob', 'monitor/snailjob/index', '', 1, 0, 'C', '0', '0', 'monitor:snailjob:list', 'job', 103, 1, sysdate(), null, null, 'SnailJob控制台菜单'); + +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, sysdate(), null, null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 103, 1, sysdate(), null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1001', '用户查询', '100', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1002', '用户新增', '100', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1003', '用户修改', '100', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1004', '用户删除', '100', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1005', '用户导出', '100', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1006', '用户导入', '100', '6', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1007', '重置密码', '100', '7', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 103, 1, sysdate(), null, null, ''); +-- 角色管理按钮 +insert into sys_menu values('1008', '角色查询', '101', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1009', '角色新增', '101', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1010', '角色修改', '101', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1011', '角色删除', '101', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1012', '角色导出', '101', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 103, 1, sysdate(), null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 103, 1, sysdate(), null, null, ''); +-- 部门管理按钮 +insert into sys_menu values('1017', '部门查询', '103', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1018', '部门新增', '103', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1019', '部门修改', '103', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1020', '部门删除', '103', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 103, 1, sysdate(), null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 103, 1, sysdate(), null, null, ''); +-- 字典管理按钮 +insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 103, 1, sysdate(), null, null, ''); +-- 参数设置按钮 +insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 103, 1, sysdate(), null, null, ''); +-- 通知公告按钮 +insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 103, 1, sysdate(), null, null, ''); +-- 操作日志按钮 +insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 103, 1, sysdate(), null, null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate(), null, null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, sysdate(), null, null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 103, 1, sysdate(), null, null, ''); +-- oss相关按钮 +insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, sysdate(), null, null, ''); + +-- 租户管理相关按钮 +insert into sys_menu values ('1606', '租户查询', '121', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1607', '租户新增', '121', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1608', '租户修改', '121', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1609', '租户删除', '121', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1610', '租户导出', '121', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:export', '#', 103, 1, sysdate(), null, null, ''); +-- 租户套餐管理相关按钮 +insert into sys_menu values ('1611', '租户套餐查询', '122', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1612', '租户套餐新增', '122', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1613', '租户套餐修改', '122', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1614', '租户套餐删除', '122', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1615', '租户套餐导出', '122', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:export', '#', 103, 1, sysdate(), null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate(), null, null, ''); +-- 测试菜单 +insert into sys_menu values('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate(), null, null, '测试单表菜单'); +insert into sys_menu values('1501', '测试单表查询', '1500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1502', '测试单表新增', '1500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1503', '测试单表修改', '1500', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1504', '测试单表删除', '1500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1505', '测试单表导出', '1500', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate(), null, null, '测试树表菜单'); +insert into sys_menu values('1507', '测试树表查询', '1506', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1508', '测试树表新增', '1506', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1509', '测试树表修改', '1506', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1510', '测试树表删除', '1506', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1511', '测试树表导出', '1506', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate(), null, null, ''); + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table sys_user_role ( + user_id bigint(20) not null comment '用户ID', + role_id bigint(20) not null comment '角色ID', + primary key(user_id, role_id) +) engine=innodb comment = '用户和角色关联表'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table sys_role_menu ( + role_id bigint(20) not null comment '角色ID', + menu_id bigint(20) not null comment '菜单ID', + primary key(role_id, menu_id) +) engine=innodb comment = '角色和菜单关联表'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '118'); +insert into sys_role_menu values ('3', '123'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1050'); +insert into sys_role_menu values ('3', '1061'); +insert into sys_role_menu values ('3', '1062'); +insert into sys_role_menu values ('3', '1063'); +insert into sys_role_menu values ('3', '1064'); +insert into sys_role_menu values ('3', '1065'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('3', '1600'); +insert into sys_role_menu values ('3', '1601'); +insert into sys_role_menu values ('3', '1602'); +insert into sys_role_menu values ('3', '1603'); +insert into sys_role_menu values ('3', '1620'); +insert into sys_role_menu values ('3', '1621'); +insert into sys_role_menu values ('3', '1622'); +insert into sys_role_menu values ('3', '1623'); +insert into sys_role_menu values ('3', '11618'); +insert into sys_role_menu values ('3', '11619'); +insert into sys_role_menu values ('3', '11629'); +insert into sys_role_menu values ('3', '11632'); +insert into sys_role_menu values ('3', '11633'); +insert into sys_role_menu values ('3', '11638'); +insert into sys_role_menu values ('3', '11639'); +insert into sys_role_menu values ('3', '11640'); +insert into sys_role_menu values ('3', '11641'); +insert into sys_role_menu values ('3', '11642'); +insert into sys_role_menu values ('3', '11643'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table sys_role_dept ( + role_id bigint(20) not null comment '角色ID', + dept_id bigint(20) not null comment '部门ID', + primary key(role_id, dept_id) +) engine=innodb comment = '角色和部门关联表'; + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table sys_user_post +( + user_id bigint(20) not null comment '用户ID', + post_id bigint(20) not null comment '岗位ID', + primary key (user_id, post_id) +) engine=innodb comment = '用户与岗位关联表'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table sys_oper_log ( + oper_id bigint(20) not null comment '日志主键', + tenant_id varchar(20) default '000000' comment '租户编号', + title varchar(50) default '' comment '模块标题', + business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)', + method varchar(100) default '' comment '方法名称', + request_method varchar(10) default '' comment '请求方式', + operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)', + oper_name varchar(50) default '' comment '操作人员', + dept_name varchar(50) default '' comment '部门名称', + oper_url varchar(255) default '' comment '请求URL', + oper_ip varchar(128) default '' comment '主机地址', + oper_location varchar(255) default '' comment '操作地点', + oper_param varchar(4000) default '' comment '请求参数', + json_result varchar(4000) default '' comment '返回参数', + status int(1) default 0 comment '操作状态(0正常 1异常)', + error_msg varchar(4000) default '' comment '错误消息', + oper_time datetime comment '操作时间', + cost_time bigint(20) default 0 comment '消耗时间', + primary key (oper_id), + key idx_sys_oper_log_bt (business_type), + key idx_sys_oper_log_s (status), + key idx_sys_oper_log_ot (oper_time) +) engine=innodb comment = '操作日志记录'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table sys_dict_type +( + dict_id bigint(20) not null comment '字典主键', + tenant_id varchar(20) default '000000' comment '租户编号', + dict_name varchar(100) default '' comment '字典名称', + dict_type varchar(100) default '' comment '字典类型', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_id), + unique (tenant_id, dict_type) +) engine=innodb comment = '字典类型表'; + +insert into sys_dict_type values(1, '000000', '用户性别', 'sys_user_sex', 103, 1, sysdate(), null, null, '用户性别列表'); +insert into sys_dict_type values(2, '000000', '菜单状态', 'sys_show_hide', 103, 1, sysdate(), null, null, '菜单状态列表'); +insert into sys_dict_type values(3, '000000', '系统开关', 'sys_normal_disable', 103, 1, sysdate(), null, null, '系统开关列表'); +insert into sys_dict_type values(6, '000000', '系统是否', 'sys_yes_no', 103, 1, sysdate(), null, null, '系统是否列表'); +insert into sys_dict_type values(7, '000000', '通知类型', 'sys_notice_type', 103, 1, sysdate(), null, null, '通知类型列表'); +insert into sys_dict_type values(8, '000000', '通知状态', 'sys_notice_status', 103, 1, sysdate(), null, null, '通知状态列表'); +insert into sys_dict_type values(9, '000000', '操作类型', 'sys_oper_type', 103, 1, sysdate(), null, null, '操作类型列表'); +insert into sys_dict_type values(10, '000000', '系统状态', 'sys_common_status', 103, 1, sysdate(), null, null, '登录状态列表'); +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, sysdate(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, sysdate(), null, null, '客户端设备类型'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table sys_dict_data +( + dict_code bigint(20) not null comment '字典编码', + tenant_id varchar(20) default '000000' comment '租户编号', + dict_sort int(4) default 0 comment '字典排序', + dict_label varchar(100) default '' comment '字典标签', + dict_value varchar(100) default '' comment '字典键值', + dict_type varchar(100) default '' comment '字典类型', + css_class varchar(100) default null comment '样式属性(其他样式扩展)', + list_class varchar(100) default null comment '表格回显样式', + is_default char(1) default 'N' comment '是否默认(Y是 N否)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_code) +) engine=innodb comment = '字典数据表'; + +insert into sys_dict_data values(1, '000000', 1, '男', '0', 'sys_user_sex', '', '', 'Y', 103, 1, sysdate(), null, null, '性别男'); +insert into sys_dict_data values(2, '000000', 2, '女', '1', 'sys_user_sex', '', '', 'N', 103, 1, sysdate(), null, null, '性别女'); +insert into sys_dict_data values(3, '000000', 3, '未知', '2', 'sys_user_sex', '', '', 'N', 103, 1, sysdate(), null, null, '性别未知'); +insert into sys_dict_data values(4, '000000', 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '显示菜单'); +insert into sys_dict_data values(5, '000000', 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 103, 1, sysdate(), null, null, '隐藏菜单'); +insert into sys_dict_data values(6, '000000', 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(7, '000000', 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 103, 1, sysdate(), null, null, '停用状态'); +insert into sys_dict_data values(12, '000000', 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '系统默认是'); +insert into sys_dict_data values(13, '000000', 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 103, 1, sysdate(), null, null, '系统默认否'); +insert into sys_dict_data values(14, '000000', 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 103, 1, sysdate(), null, null, '通知'); +insert into sys_dict_data values(15, '000000', 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 103, 1, sysdate(), null, null, '公告'); +insert into sys_dict_data values(16, '000000', 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(17, '000000', 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 103, 1, sysdate(), null, null, '关闭状态'); +insert into sys_dict_data values(29, '000000', 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate(), null, null, '其他操作'); +insert into sys_dict_data values(18, '000000', 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate(), null, null, '新增操作'); +insert into sys_dict_data values(19, '000000', 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate(), null, null, '修改操作'); +insert into sys_dict_data values(20, '000000', 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate(), null, null, '删除操作'); +insert into sys_dict_data values(21, '000000', 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 103, 1, sysdate(), null, null, '授权操作'); +insert into sys_dict_data values(22, '000000', 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate(), null, null, '导出操作'); +insert into sys_dict_data values(23, '000000', 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate(), null, null, '导入操作'); +insert into sys_dict_data values(24, '000000', 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate(), null, null, '强退操作'); +insert into sys_dict_data values(25, '000000', 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate(), null, null, '生成操作'); +insert into sys_dict_data values(26, '000000', 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate(), null, null, '清空操作'); +insert into sys_dict_data values(27, '000000', 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 103, 1, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(28, '000000', 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 103, 1, sysdate(), null, null, '停用状态'); +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table sys_config ( + config_id bigint(20) not null comment '参数主键', + tenant_id varchar(20) default '000000' comment '租户编号', + config_name varchar(100) default '' comment '参数名称', + config_key varchar(100) default '' comment '参数键名', + config_value varchar(500) default '' comment '参数键值', + config_type char(1) default 'N' comment '系统内置(Y是 N否)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (config_id) +) engine=innodb comment = '参数配置表'; + +insert into sys_config values(1, '000000', '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 103, 1, sysdate(), null, null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '000000', '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 103, 1, sysdate(), null, null, '初始化密码 123456' ); +insert into sys_config values(3, '000000', '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 103, 1, sysdate(), null, null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(5, '000000', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 103, 1, sysdate(), null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(11, '000000', 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 103, 1, sysdate(), null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table sys_logininfor ( + info_id bigint(20) not null comment '访问ID', + tenant_id varchar(20) default '000000' comment '租户编号', + user_name varchar(50) default '' comment '用户账号', + client_key varchar(32) default '' comment '客户端', + device_type varchar(32) default '' comment '设备类型', + ipaddr varchar(128) default '' comment '登录IP地址', + login_location varchar(255) default '' comment '登录地点', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status char(1) default '0' comment '登录状态(0成功 1失败)', + msg varchar(255) default '' comment '提示消息', + login_time datetime comment '访问时间', + primary key (info_id), + key idx_sys_logininfor_s (status), + key idx_sys_logininfor_lt (login_time) +) engine=innodb comment = '系统访问记录'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table sys_notice ( + notice_id bigint(20) not null comment '公告ID', + tenant_id varchar(20) default '000000' comment '租户编号', + notice_title varchar(50) not null comment '公告标题', + notice_type char(1) not null comment '公告类型(1通知 2公告)', + notice_content longblob default null comment '公告内容', + status char(1) default '0' comment '公告状态(0正常 1关闭)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(255) default null comment '备注', + primary key (notice_id) +) engine=innodb comment = '通知公告表'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '000000', '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 103, 1, sysdate(), null, null, '管理员'); +insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 103, 1, sysdate(), null, null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +create table gen_table ( + table_id bigint(20) not null comment '编号', + data_name varchar(200) default '' comment '数据源名称', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + sub_table_name varchar(64) default null comment '关联子表的表名', + sub_table_fk_name varchar(64) default null comment '子表关联的外键名', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (table_id) +) engine=innodb comment = '代码生成业务表'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +create table gen_table_column ( + column_id bigint(20) not null comment '编号', + table_id bigint(20) comment '归属表编号', + column_name varchar(200) comment '列名称', + column_comment varchar(500) comment '列描述', + column_type varchar(100) comment '列类型', + java_type varchar(500) comment 'JAVA类型', + java_field varchar(200) comment 'JAVA字段名', + is_pk char(1) comment '是否主键(1是)', + is_increment char(1) comment '是否自增(1是)', + is_required char(1) comment '是否必填(1是)', + is_insert char(1) comment '是否为插入字段(1是)', + is_edit char(1) comment '是否编辑字段(1是)', + is_list char(1) comment '是否列表字段(1是)', + is_query char(1) comment '是否查询字段(1是)', + query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)', + html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + dict_type varchar(200) default '' comment '字典类型', + sort int comment '排序', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (column_id) +) engine=innodb comment = '代码生成业务表字段'; + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table sys_oss ( + oss_id bigint(20) not null comment '对象存储主键', + tenant_id varchar(20) default '000000' comment '租户编号', + file_name varchar(255) not null default '' comment '文件名', + original_name varchar(255) not null default '' comment '原名', + file_suffix varchar(10) not null default '' comment '文件后缀名', + url varchar(500) not null comment 'URL地址', + create_dept bigint(20) default null comment '创建部门', + create_time datetime default null comment '创建时间', + create_by bigint(20) default null comment '上传人', + update_time datetime default null comment '更新时间', + update_by bigint(20) default null comment '更新人', + service varchar(20) not null default 'minio' comment '服务商', + primary key (oss_id) +) engine=innodb comment ='OSS对象存储表'; + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table sys_oss_config ( + oss_config_id bigint(20) not null comment '主键', + tenant_id varchar(20) default '000000'comment '租户编号', + config_key varchar(20) not null default '' comment '配置key', + access_key varchar(255) default '' comment 'accessKey', + secret_key varchar(255) default '' comment '秘钥', + bucket_name varchar(255) default '' comment '桶名称', + prefix varchar(255) default '' comment '前缀', + endpoint varchar(255) default '' comment '访问站点', + domain varchar(255) default '' comment '自定义域名', + is_https char(1) default 'N' comment '是否https(Y=是,N=否)', + region varchar(255) default '' comment '域', + access_policy char(1) not null default '1' comment '桶权限类型(0=private 1=public 2=custom)', + status char(1) default '1' comment '是否默认(0=是,1=否)', + ext1 varchar(255) default '' comment '扩展字段', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (oss_config_id) +) engine=innodb comment='对象存储配置表'; + +insert into sys_oss_config values (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '','N', '', '1' ,'0', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1240000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '','N', '', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id bigint(20) not null comment 'id', + client_id varchar(64) default null comment '客户端id', + client_key varchar(32) default null comment '客户端key', + client_secret varchar(255) default null comment '客户端秘钥', + grant_type varchar(255) default null comment '授权类型', + device_type varchar(32) default null comment '设备类型', + active_timeout int(11) default 1800 comment 'token活跃超时时间', + timeout int(11) default 604800 comment 'token固定超时', + status char(1) default '0' comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + primary key (id) +) engine=innodb comment='系统授权表'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); + + +CREATE TABLE test_demo +( + id bigint(0) NOT NULL COMMENT '主键', + tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + order_num int(0) NULL DEFAULT 0 COMMENT '排序号', + test_key varchar(255) NULL DEFAULT NULL COMMENT 'key键', + value varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试单表'; + +CREATE TABLE test_tree +( + id bigint(0) NOT NULL COMMENT '主键', + tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', + parent_id bigint(0) NULL DEFAULT 0 COMMENT '父id', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + tree_name varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试树表'; + +INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate(), 1, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate(), 1, NULL, NULL, 0); diff --git a/script/sql/ry_workflow.sql b/script/sql/ry_workflow.sql new file mode 100644 index 0000000..bb3d76e --- /dev/null +++ b/script/sql/ry_workflow.sql @@ -0,0 +1,257 @@ +-- ---------------------------- +-- 0、warm-flow-all.sql,地址:https://gitee.com/dromara/warm-flow/blob/master/sql/mysql/warm-flow-all.sql +-- ---------------------------- +CREATE TABLE `flow_definition` +( + `id` bigint NOT NULL COMMENT '主键id', + `flow_code` varchar(40) NOT NULL COMMENT '流程编码', + `flow_name` varchar(100) NOT NULL COMMENT '流程名称', + `category` varchar(100) DEFAULT NULL COMMENT '流程类别', + `version` varchar(20) NOT NULL COMMENT '流程版本', + `is_publish` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否发布(0未发布 1已发布 9失效)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)', + `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型', + `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径', + `ext` varchar(500) DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程定义表'; + +CREATE TABLE `flow_node` +( + `id` bigint NOT NULL COMMENT '主键id', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `definition_id` bigint NOT NULL COMMENT '流程定义id', + `node_code` varchar(100) NOT NULL COMMENT '流程节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称', + `permission_flag` varchar(200) DEFAULT NULL COMMENT '权限标识(权限类型:权限标识,可以多个,用@@隔开)', + `node_ratio` decimal(6, 3) DEFAULT NULL COMMENT '流程签署比例值', + `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标', + `any_node_skip` varchar(100) DEFAULT NULL COMMENT '任意结点跳转', + `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型', + `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径', + `handler_type` varchar(100) DEFAULT NULL COMMENT '处理器类型', + `handler_path` varchar(400) DEFAULT NULL COMMENT '处理器路径', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `version` varchar(20) NOT NULL COMMENT '版本', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `ext` text COMMENT '节点扩展属性', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程节点表'; + +CREATE TABLE `flow_skip` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '流程定义id', + `now_node_code` varchar(100) NOT NULL COMMENT '当前流程节点的编码', + `now_node_type` tinyint(1) DEFAULT NULL COMMENT '当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `next_node_code` varchar(100) NOT NULL COMMENT '下一个流程节点的编码', + `next_node_type` tinyint(1) DEFAULT NULL COMMENT '下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `skip_name` varchar(100) DEFAULT NULL COMMENT '跳转名称', + `skip_type` varchar(40) DEFAULT NULL COMMENT '跳转类型(PASS审批通过 REJECT退回)', + `skip_condition` varchar(200) DEFAULT NULL COMMENT '跳转条件', + `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='节点跳转关联表'; + +CREATE TABLE `flow_instance` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id', + `business_id` varchar(40) NOT NULL COMMENT '业务id', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `node_code` varchar(40) NOT NULL COMMENT '流程节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称', + `variable` text COMMENT '任务变量', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', + `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)', + `def_json` text COMMENT '流程定义json', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `ext` varchar(500) DEFAULT NULL COMMENT '扩展字段,预留给业务系统使用', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程实例表'; + +CREATE TABLE `flow_task` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id', + `instance_id` bigint NOT NULL COMMENT '对应flow_instance表的id', + `node_code` varchar(100) NOT NULL COMMENT '节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '节点名称', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='待办任务表'; + +CREATE TABLE `flow_his_task` +( + `id` bigint(20) NOT NULL COMMENT '主键id', + `definition_id` bigint(20) NOT NULL COMMENT '对应flow_definition表的id', + `instance_id` bigint(20) NOT NULL COMMENT '对应flow_instance表的id', + `task_id` bigint(20) NOT NULL COMMENT '对应flow_task表的id', + `node_code` varchar(100) DEFAULT NULL COMMENT '开始节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '开始节点名称', + `node_type` tinyint(1) DEFAULT NULL COMMENT '开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `target_node_code` varchar(200) DEFAULT NULL COMMENT '目标节点编码', + `target_node_name` varchar(200) DEFAULT NULL COMMENT '结束节点名称', + `approver` varchar(40) DEFAULT NULL COMMENT '审批者', + `cooperate_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)', + `collaborator` varchar(40) DEFAULT NULL COMMENT '协作人', + `skip_type` varchar(10) NOT NULL COMMENT '流转类型(PASS通过 REJECT退回 NONE无动作)', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `message` varchar(500) DEFAULT NULL COMMENT '审批意见', + `variable` TEXT DEFAULT NULL COMMENT '任务变量', + `ext` TEXT DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串', + `create_time` datetime DEFAULT NULL COMMENT '任务开始时间', + `update_time` datetime DEFAULT NULL COMMENT '审批完成时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='历史任务记录表'; + + +CREATE TABLE `flow_user` +( + `id` bigint NOT NULL COMMENT '主键id', + `type` char(1) NOT NULL COMMENT '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)', + `processed_by` varchar(80) DEFAULT NULL COMMENT '权限人', + `associated` bigint NOT NULL COMMENT '任务表id', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(80) DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE, + KEY `user_processed_type` (`processed_by`, `type`), + KEY `user_associated` (`associated`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程用户表'; + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +create table flow_category +( + category_id bigint(20) not null comment '流程分类ID', + tenant_id varchar(20) default '000000' comment '租户编号', + parent_id bigint(20) default 0 comment '父流程分类id', + ancestors varchar(500) default '' comment '祖级列表', + category_name varchar(30) not null comment '流程分类名称', + order_num int(4) default 0 comment '显示顺序', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) null comment '创建部门', + create_by bigint(20) null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint(20) null comment '更新者', + update_time datetime null comment '更新时间', + primary key (category_id) +) engine = innodb comment = '流程分类'; + +INSERT INTO flow_category values (100, '000000', 0, '0', 'OA审批', 0, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (101, '000000', 100, '0,100', '假勤管理', 0, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (102, '000000', 100, '0,100', '人事管理', 1, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (103, '000000', 101, '0,100,101', '请假', 0, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (104, '000000', 101, '0,100,101', '出差', 1, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (105, '000000', 101, '0,100,101', '加班', 2, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (106, '000000', 101, '0,100,101', '换班', 3, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (107, '000000', 101, '0,100,101', '外出', 4, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (108, '000000', 102, '0,100,102', '转正', 1, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (109, '000000', 102, '0,100,102', '离职', 2, '0', 103, 1, sysdate(), null, null); + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +create table test_leave +( + id bigint(20) not null comment 'id', + tenant_id varchar(20) default '000000' comment '租户编号', + leave_type varchar(255) not null comment '请假类型', + start_date datetime not null comment '开始时间', + end_date datetime not null comment '结束时间', + leave_days int(10) not null comment '请假天数', + remark varchar(255) null comment '请假原因', + status varchar(255) null comment '状态', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '请假申请表'; + +insert into sys_menu values ('11616', '工作流', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, sysdate(),NULL, NULL, ''); +insert into sys_menu values ('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11700', '流程设计', '11616', '5', 'design/index', 'workflow/processDefinition/design', '', 1, 1, 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11701', '请假申请', '11616', '6', 'leaveEdit/index', 'workflow/leave/leaveEdit', '', 1, 1, 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), null, null, ''); +-- 流程分类管理相关按钮 +insert into sys_menu values ('11623', '流程分类查询', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1,sysdate(), null, null, ''); +insert into sys_menu values ('11624', '流程分类新增', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add', '#', 103, 1,sysdate(), null, null, ''); +insert into sys_menu values ('11625', '流程分类修改', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1,sysdate(), null, null, ''); +insert into sys_menu values ('11626', '流程分类删除', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove', '#', 103,1, sysdate(), null, null, ''); +insert into sys_menu values ('11627', '流程分类导出', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export', '#', 103,1, sysdate(), null, null, ''); +-- 请假测试相关按钮 +insert into sys_menu VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', '', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '请假申请菜单'); +insert into sys_menu VALUES (11639, '请假申请查询', 11638, 1, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11640, '请假申请新增', 11638, 2, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11641, '请假申请修改', 11638, 3, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11642, '请假申请删除', 11638, 4, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11643, '请假申请导出', 11638, 5, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate(), NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (15, '000000', '任务状态', 'wf_task_status', 103, 1, sysdate(), NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'已撤销'); +INSERT INTO sys_dict_data VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL,'待审核'); +INSERT INTO sys_dict_data VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL,'已完成'); +INSERT INTO sys_dict_data VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'已作废'); +INSERT INTO sys_dict_data VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'已退回'); +INSERT INTO sys_dict_data VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL,NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL,'自定义表单'); +INSERT INTO sys_dict_data VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL,'动态表单'); +INSERT INTO sys_dict_data VALUES (48, '000000', 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (49, '000000', 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (50, '000000', 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (51, '000000', 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (52, '000000', 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (53, '000000', 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (54, '000000', 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (55, '000000', 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (56, '000000', 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (57, '000000', 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (58, '000000', 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (59, '000000', 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '超时'); + diff --git a/script/sql/sqlserver/sqlserver_ry_job.sql b/script/sql/sqlserver/sqlserver_ry_job.sql new file mode 100644 index 0000000..97addc3 --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_job.sql @@ -0,0 +1,2778 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : Microsoft SQL Server + Date: 2024-12-27 22:24:37 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(64) NOT NULL, + unique_id nvarchar(64) NOT NULL, + description nvarchar(256) NOT NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace' +GO + +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Development', N'dev', N'', 0, getdate(), getdate()) +GO +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Production', N'prod', N'', 0, getdate(), getdate()) +GO + +-- sj_group_config +CREATE TABLE sj_group_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + description nvarchar(256) NOT NULL DEFAULT '', + token nvarchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status tinyint NOT NULL DEFAULT 0, + version int NOT NULL, + group_partition int NOT NULL, + id_generator_mode tinyint NOT NULL DEFAULT 1, + init_scene tinyint NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'token', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'分区', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_partition' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id生成模式 默认号段模式', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'id_generator_mode' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否初始化场景 0:否 1:是', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'init_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config' +GO + +INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate()) +GO +INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'prod', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate()) +GO + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + notify_name nvarchar(64) NOT NULL DEFAULT '', + system_task_type tinyint NOT NULL DEFAULT 3, + notify_status tinyint NOT NULL DEFAULT 0, + recipient_ids nvarchar(128) NOT NULL, + notify_threshold int NOT NULL DEFAULT 0, + notify_scene tinyint NOT NULL DEFAULT 0, + rate_limiter_status tinyint NOT NULL DEFAULT 0, + rate_limiter_threshold int NOT NULL DEFAULT 0, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收人id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'recipient_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知场景', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'限流状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'rate_limiter_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'每秒限流阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'rate_limiter_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config' +GO + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + recipient_name nvarchar(64) NOT NULL, + notify_type tinyint NOT NULL DEFAULT 0, + notify_attribute nvarchar(512) NOT NULL, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收人名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'recipient_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'notify_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置属性', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'notify_attribute' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'告警通知接收人', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient' +GO + +-- sj_retry_dead_letter_0 +CREATE TABLE sj_retry_dead_letter_0 +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + task_type tinyint NOT NULL DEFAULT 1, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id) +GO + +CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id) +GO +CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no) +GO +CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'死信队列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0' +GO + +-- sj_retry_task_0 +CREATE TABLE sj_retry_task_0 +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + next_trigger_at datetime2 NOT NULL, + retry_count int NOT NULL DEFAULT 0, + retry_status tinyint NOT NULL DEFAULT 0, + task_type tinyint NOT NULL DEFAULT 1, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id) +GO + +CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type) +GO +CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status) +GO +CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id) +GO +CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no) +GO +CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态 0、重试中 1、成功 2、最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'retry_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0' +GO + +-- sj_retry_task_log +CREATE TABLE sj_retry_task_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + retry_status tinyint NOT NULL DEFAULT 0, + task_type tinyint NOT NULL DEFAULT 1, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status) +GO +CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id) +GO +CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id) +GO +CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no) +GO +CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态 0、重试中 1、成功 2、最大次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'retry_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务日志基础信息表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log' +GO + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + unique_id nvarchar(64) NOT NULL, + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id) +GO +CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务调度日志信息记录表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message' +GO + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_status tinyint NOT NULL DEFAULT 0, + max_retry_count int NOT NULL DEFAULT 5, + back_off tinyint NOT NULL DEFAULT 1, + trigger_interval nvarchar(16) NOT NULL DEFAULT '', + notify_ids nvarchar(128) NOT NULL DEFAULT '', + deadline_request bigint NOT NULL DEFAULT 60000, + executor_timeout int NOT NULL DEFAULT 5, + route_key tinyint NOT NULL DEFAULT 4, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'scene_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'max_retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、默认等级 2、固定间隔时间 3、CRON 表达式', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'back_off' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'Deadline Request 调用链超时 单位毫秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'deadline_request' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config' +GO + +-- sj_server_node +CREATE TABLE sj_server_node +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + host_id nvarchar(64) NOT NULL, + host_ip nvarchar(64) NOT NULL, + host_port int NOT NULL, + expire_at datetime2 NOT NULL, + node_type tinyint NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip) +GO + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name) +GO +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主机id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器ip', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器端口', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_port' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'expire_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点类型 1、客户端 2、是服务端', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'服务器节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node' +GO + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name nvarchar(64) NOT NULL PRIMARY KEY, + lock_until datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_by nvarchar(255) NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'lock_until' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'locked_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定者', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'locked_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock' +GO + +-- sj_system_user +CREATE TABLE sj_system_user +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + username nvarchar(64) NOT NULL, + password nvarchar(128) NOT NULL, + role tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'账号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'密码', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'password' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色:1-普通用户、2-管理员', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'role' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user' +GO + +-- pwd: admin +INSERT INTO sj_system_user(username, password, role, create_dt, update_dt) VALUES (N'admin', N'465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', N'2', getdate(), getdate()) +GO + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + group_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + system_user_id bigint NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'system_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户权限表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission' +GO + +-- sj_sequence_alloc +CREATE TABLE sj_sequence_alloc +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + max_id bigint NOT NULL DEFAULT 1, + step int NOT NULL DEFAULT 100, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'max_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'步长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'step' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'号段模式序号ID分配表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc' +GO + +-- sj_job +CREATE TABLE sj_job +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_name nvarchar(64) NOT NULL, + args_str nvarchar(max) NULL DEFAULT NULL, + args_type tinyint NOT NULL DEFAULT 1, + next_trigger_at bigint NOT NULL, + job_status tinyint NOT NULL DEFAULT 1, + task_type tinyint NOT NULL DEFAULT 1, + route_key tinyint NOT NULL DEFAULT 4, + executor_type tinyint NOT NULL DEFAULT 1, + executor_info nvarchar(255) NULL DEFAULT NULL, + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + block_strategy tinyint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + max_retry_times int NOT NULL DEFAULT 0, + parallel_num int NOT NULL DEFAULT 1, + retry_interval int NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + resident tinyint NOT NULL DEFAULT 0, + notify_ids nvarchar(128) NOT NULL DEFAULT '', + owner_id bigint NULL, + description nvarchar(256) NOT NULL DEFAULT '', + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name) +GO +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index) +GO +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'job_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'job_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、集群 2、广播 3、切片', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'max_retry_times' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'并行数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'parallel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试间隔 ( s ) ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'retry_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否是常驻任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'resident' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'负责人id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'owner_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job' +GO + +INSERT INTO sj_job (namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, notify_ids, owner_id, description, ext_attrs, deleted, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, N'testJobExecutor', 2, N'60', 1, 60, 3, 1, 1, 116, 0, N'', 1, N'', N'', 0, getdate(), getdate()) +GO + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + task_id bigint NOT NULL, + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id) +GO +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt) +GO +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'task_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度日志', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message' +GO + +-- sj_job_task +CREATE TABLE sj_job_task +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + parent_id bigint NOT NULL DEFAULT 0, + task_status tinyint NOT NULL DEFAULT 0, + retry_count int NOT NULL DEFAULT 0, + mr_stage tinyint NULL DEFAULT NULL, + leaf tinyint NOT NULL DEFAULT '1', + task_name nvarchar(255) NOT NULL DEFAULT '', + client_info nvarchar(128) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + result_message nvarchar(max) NOT NULL, + args_str nvarchar(max) NULL DEFAULT NULL, + args_type tinyint NOT NULL DEFAULT 1, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status) +GO +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt) +GO +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父执行器id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行的状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'动态分片所处阶段 1:map 2:reduce 3:mergeReduce', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'mr_stage' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'叶子节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'leaf' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端地址 clientId#ip:port', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'client_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流全局上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行结果', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'result_message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务实例', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task' +GO + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_node_id bigint NOT NULL DEFAULT 0, + parent_workflow_node_id bigint NOT NULL DEFAULT 0, + workflow_task_batch_id bigint NOT NULL DEFAULT 0, + task_batch_status tinyint NOT NULL DEFAULT 0, + operation_reason tinyint NOT NULL DEFAULT 0, + execution_at bigint NOT NULL DEFAULT 0, + system_task_type tinyint NOT NULL DEFAULT 3, + parent_id nvarchar(64) NOT NULL DEFAULT '', + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status) +GO +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt) +GO +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name) +GO +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务父批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'parent_workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'workflow_task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch' +GO + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + business_id bigint NOT NULL, + system_task_type tinyint NOT NULL DEFAULT 3, + trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + success_num int NOT NULL DEFAULT 0, + fail_num int NOT NULL DEFAULT 0, + fail_reason nvarchar(512) NOT NULL DEFAULT '', + stop_num int NOT NULL DEFAULT 0, + stop_reason nvarchar(512) NOT NULL DEFAULT '', + cancel_num int NOT NULL DEFAULT 0, + cancel_reason nvarchar(512) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id) +GO + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务id ( job_id或workflow_id ) ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'business_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行成功-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'success_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'fail_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'fail_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'stop_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'stop_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'cancel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'cancel_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Job', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary' +GO + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + scene_name nvarchar(50) NOT NULL DEFAULT '', + trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + running_num int NOT NULL DEFAULT 0, + finish_num int NOT NULL DEFAULT 0, + max_count_num int NOT NULL DEFAULT 0, + suspend_num int NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at) +GO + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试中-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'running_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试完成-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'finish_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试到达最大次数-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'max_count_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'暂停重试-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'suspend_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Retry', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary' +GO + +-- sj_workflow +CREATE TABLE sj_workflow +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + workflow_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + workflow_status tinyint NOT NULL DEFAULT 1, + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + next_trigger_at bigint NOT NULL, + block_strategy tinyint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + description nvarchar(256) NOT NULL DEFAULT '', + flow_info nvarchar(max) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + notify_ids nvarchar(128) NOT NULL DEFAULT '', + bucket_index int NOT NULL DEFAULT 0, + version int NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt) +GO +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'workflow_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'workflow_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow' +GO + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_id bigint NOT NULL, + node_type tinyint NOT NULL DEFAULT 1, + expression_type tinyint NOT NULL DEFAULT 0, + fail_strategy tinyint NOT NULL DEFAULT 1, + workflow_node_status tinyint NOT NULL DEFAULT 1, + priority_level int NOT NULL DEFAULT 1, + node_info nvarchar(max) NULL DEFAULT NULL, + version int NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt) +GO +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流ID', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、任务节点 2、条件节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、SpEl、2、Aviator 3、QL', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'expression_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败策略 1、跳过 2、阻塞', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'fail_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'workflow_node_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'优先级', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'priority_level' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点信息 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node' +GO + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + workflow_id bigint NOT NULL, + task_batch_status tinyint NOT NULL DEFAULT 0, + operation_reason tinyint NOT NULL DEFAULT 0, + flow_info nvarchar(max) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + execution_at bigint NOT NULL DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '', + version int NOT NULL DEFAULT 1, + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status) +GO +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt) +GO +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'全局上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流批次', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch' +GO diff --git a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql new file mode 100644 index 0000000..9f8481a --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql @@ -0,0 +1,3607 @@ +create table sys_social +( + id bigint NOT NULL, + user_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + auth_id nvarchar(255) NOT NULL, + source nvarchar(255) NOT NULL, + open_id nvarchar(255) NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) DEFAULT ('') NULL, + email nvarchar(255) DEFAULT ('') NULL, + avatar nvarchar(500) DEFAULT ('') NULL, + access_token nvarchar(255) NOT NULL, + expire_in bigint NULL, + refresh_token nvarchar(255) NULL, + access_code nvarchar(255) NULL, + union_id nvarchar(255) NULL, + scope nvarchar(255) NULL, + token_type nvarchar(255) NULL, + id_token nvarchar(2000) NULL, + mac_algorithm nvarchar(255) NULL, + mac_key nvarchar(255) NULL, + code nvarchar(255) NULL, + oauth_token nvarchar(255) NULL, + oauth_token_secret nvarchar(255) NULL, + create_dept bigint, + create_by bigint, + create_time datetime2(7), + update_by bigint, + update_time datetime2(7), + del_flag nchar DEFAULT ('0') NULL, + CONSTRAINT PK__sys_social__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台+平台唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'auth_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户来源' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'source' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台编号唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'open_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌的有效期,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'expire_in' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'刷新令牌,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'refresh_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的 unionid' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'union_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'授予的权限,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'个别平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'token_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id token,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_algorithm' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权code,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token_secret' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'社会化关系表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social' +GO + +CREATE TABLE sys_tenant +( + id bigint NOT NULL, + tenant_id nvarchar(20) NOT NULL, + contact_user_name nvarchar(20) NULL, + contact_phone nvarchar(20) NULL, + company_name nvarchar(50) NULL, + license_number nvarchar(30) NULL, + address nvarchar(200) NULL, + intro nvarchar(200) NULL, + domain nvarchar(200) NULL, + remark nvarchar(200) NULL, + package_id bigint NULL, + expire_time datetime2(7) NULL, + account_count int DEFAULT ((-1)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_tenant__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'联系人' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'contact_user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'联系电话' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'contact_phone' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'企业名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'company_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'统一社会信用代码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'license_number' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'address' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'企业简介' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'intro' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'域名' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'domain' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户套餐编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'package_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'过期时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'expire_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户数量(-1不限制)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'account_count' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant' +GO + +INSERT sys_tenant VALUES (1, N'000000', N'管理组', N'15888888888', N'XXX有限公司', NULL, NULL, N'多租户通用后台管理管理系统', NULL, NULL, NULL, NULL, -1, N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO + + +CREATE TABLE sys_tenant_package +( + package_id bigint NOT NULL, + package_name nvarchar(20) NOT NULL, + menu_ids nvarchar(20) NULL, + remark nvarchar(200) NULL, + menu_check_strictly tinyint DEFAULT ((1)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_tenant_package__B21E8F2427725F8A PRIMARY KEY CLUSTERED (package_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户套餐id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'package_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'套餐名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'package_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'关联菜单id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'menu_ids' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户套餐表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package' +GO + + +CREATE TABLE gen_table +( + table_id bigint NOT NULL, + data_name nvarchar(200) DEFAULT '' NULL, + table_name nvarchar(200) DEFAULT '' NULL, + table_comment nvarchar(500) DEFAULT '' NULL, + sub_table_name nvarchar(64) NULL, + sub_table_fk_name nvarchar(64) NULL, + class_name nvarchar(100) DEFAULT '' NULL, + tpl_category nvarchar(200) DEFAULT ('crud') NULL, + package_name nvarchar(100) NULL, + module_name nvarchar(30) NULL, + business_name nvarchar(30) NULL, + function_name nvarchar(50) NULL, + function_author nvarchar(50) NULL, + gen_type nchar(1) DEFAULT ('0') NULL, + gen_path nvarchar(200) DEFAULT ('/') NULL, + options nvarchar(1000) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__gen_tabl__B21E8F2427725F8A PRIMARY KEY CLUSTERED (table_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'数据源名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'data_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表描述' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_comment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'关联子表的表名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'sub_table_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'子表关联的外键名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'sub_table_fk_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'实体类名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'class_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'使用的模板(crud单表操作 tree树表操作)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'tpl_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成包路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'package_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成模块名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'module_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成业务名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'business_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成功能名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'function_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成功能作者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'function_author' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成代码方式(0zip压缩包 1自定义路径)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'gen_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成路径(不填默认项目路径)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'gen_path' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'其它生成选项' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'options' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'代码生成业务表' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table' +GO + +CREATE TABLE gen_table_column +( + column_id bigint NOT NULL, + table_id bigint NULL, + column_name nvarchar(200) NULL, + column_comment nvarchar(500) NULL, + column_type nvarchar(100) NULL, + java_type nvarchar(500) NULL, + java_field nvarchar(200) NULL, + is_pk nchar(1) NULL, + is_increment nchar(1) NULL, + is_required nchar(1) NULL, + is_insert nchar(1) NULL, + is_edit nchar(1) NULL, + is_list nchar(1) NULL, + is_query nchar(1) NULL, + query_type nvarchar(200) DEFAULT ('EQ') NULL, + html_type nvarchar(200) NULL, + dict_type nvarchar(200) DEFAULT '' NULL, + sort int NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__gen_tabl__E301851F2E68B4E8 PRIMARY KEY CLUSTERED (column_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'归属表编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'table_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列描述' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_comment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'JAVA类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'java_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'JAVA字段名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'java_field' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否主键(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_pk' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否自增(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_increment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否必填(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_required' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否为插入字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_insert' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否编辑字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_edit' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否列表字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_list' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否查询字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_query' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'查询方式(等于、不等于、大于、小于、范围)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'query_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'html_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'排序' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'代码生成业务表字段' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column' +GO + +CREATE TABLE sys_config +( + config_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT '000000' NULL, + config_name nvarchar(100) DEFAULT '' NULL, + config_key nvarchar(100) DEFAULT '' NULL, + config_value nvarchar(500) DEFAULT '' NULL, + config_type nchar(1) DEFAULT ('N') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_conf__4AD1BFF182643682 PRIMARY KEY CLUSTERED (config_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数键名' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数键值' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_value' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'系统内置(Y是 N否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数配置表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config' +GO + +INSERT sys_config VALUES (1, N'000000', N'主框架页-默认皮肤样式名称', N'sys.index.skinName', N'skin-blue', N'Y', 103, 1, getdate(), NULL, NULL, N'蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow') +GO +INSERT sys_config VALUES (2, N'000000', N'用户管理-账号初始密码', N'sys.user.initPassword', N'123456', N'Y', 103, 1, getdate(), NULL, NULL, N'初始化密码 123456') +GO +INSERT sys_config VALUES (3, N'000000', N'主框架页-侧边栏主题', N'sys.index.sideTheme', N'theme-dark', N'Y', 103, 1, getdate(), NULL, NULL, N'深色主题theme-dark,浅色主题theme-light') +GO +INSERT sys_config VALUES (5, N'000000', N'账号自助-是否开启用户注册功能', N'sys.account.registerUser', N'false', N'Y', 103, 1, getdate(), NULL, NULL, N'是否开启注册用户功能(true开启,false关闭)') +GO +INSERT sys_config VALUES (11, N'000000', N'OSS预览列表资源开关', N'sys.oss.previewListResource', N'true', N'Y', 103, 1, getdate(), NULL, NULL, N'true:开启, false:关闭'); +GO + +CREATE TABLE sys_dept +( + dept_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + parent_id bigint DEFAULT ((0)) NULL, + ancestors nvarchar(500)DEFAULT '' NULL, + dept_name nvarchar(30) NULL, + dept_category nvarchar(100) DEFAULT '' NULL, + order_num int DEFAULT ((0)) NULL, + leader bigint NULL, + phone nvarchar(11) NULL, + email nvarchar(50) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_dept__DCA659747DE13804 PRIMARY KEY CLUSTERED (dept_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'父部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'parent_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'祖级列表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'ancestors' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门类别编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'order_num' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'负责人' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'leader' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'联系电话' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'phone' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept' +GO + +INSERT sys_dept VALUES (100, N'000000', 0, N'0', N'XXX科技', NULL, 0, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (101, N'000000', 100, N'0,100', N'深圳总公司', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (102, N'000000', 100, N'0,100', N'长沙分公司', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (103, N'000000', 101, N'0,100,101', N'研发部门', NULL, 1, 1, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (104, N'000000', 101, N'0,100,101', N'市场部门', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (105, N'000000', 101, N'0,100,101', N'测试部门', NULL, 3, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (106, N'000000', 101, N'0,100,101', N'财务部门', NULL, 4, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (107, N'000000', 101, N'0,100,101', N'运维部门', NULL, 5, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (108, N'000000', 102, N'0,100,102', N'市场部门', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (109, N'000000', 102, N'0,100,102', N'财务部门', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO + +CREATE TABLE sys_dict_data +( + dict_code bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dict_sort int DEFAULT ((0)) NULL, + dict_label nvarchar(100) DEFAULT '' NULL, + dict_value nvarchar(100) DEFAULT '' NULL, + dict_type nvarchar(100) DEFAULT '' NULL, + css_class nvarchar(100) NULL, + list_class nvarchar(100) NULL, + is_default nchar(1) DEFAULT ('N') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_dict__19CBC34B661AF3B3 PRIMARY KEY CLUSTERED (dict_code) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典排序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典标签' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_label' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典键值' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_value' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'样式属性(其他样式扩展)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'css_class' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表格回显样式' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'list_class' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否默认(Y是 N否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'is_default' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典数据表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data' +GO + +INSERT sys_dict_data VALUES (1, N'000000', 1, N'男', N'0', N'sys_user_sex', N'', N'', N'Y', 103, 1, getdate(), NULL, NULL, N'性别男') +GO +INSERT sys_dict_data VALUES (2, N'000000', 2, N'女', N'1', N'sys_user_sex', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'性别女') +GO +INSERT sys_dict_data VALUES (3, N'000000', 3, N'未知', N'2', N'sys_user_sex', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'性别未知') +GO +INSERT sys_dict_data VALUES (4, N'000000', 1, N'显示', N'0', N'sys_show_hide', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'显示菜单') +GO +INSERT sys_dict_data VALUES (5, N'000000', 2, N'隐藏', N'1', N'sys_show_hide', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'隐藏菜单') +GO +INSERT sys_dict_data VALUES (6, N'000000', 1, N'正常', N'0', N'sys_normal_disable', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (7, N'000000', 2, N'停用', N'1', N'sys_normal_disable', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (8, N'000000', 1, N'正常', N'0', N'sys_job_status', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (9, N'000000', 2, N'暂停', N'1', N'sys_job_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (10, N'000000', 1, N'默认', N'DEFAULT', N'sys_job_group', N'', N'', N'Y', 103, 1, getdate(), NULL, NULL, N'默认分组') +GO +INSERT sys_dict_data VALUES (11, N'000000', 2, N'系统', N'SYSTEM', N'sys_job_group', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'系统分组') +GO +INSERT sys_dict_data VALUES (12, N'000000', 1, N'是', N'Y', N'sys_yes_no', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'系统默认是') +GO +INSERT sys_dict_data VALUES (13, N'000000', 2, N'否', N'N', N'sys_yes_no', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'系统默认否') +GO +INSERT sys_dict_data VALUES (14, N'000000', 1, N'通知', N'1', N'sys_notice_type', N'', N'warning', N'Y', 103, 1, getdate(), NULL, NULL, N'通知') +GO +INSERT sys_dict_data VALUES (15, N'000000', 2, N'公告', N'2', N'sys_notice_type', N'', N'success', N'N', 103, 1, getdate(), NULL, NULL, N'公告') +GO +INSERT sys_dict_data VALUES (16, N'000000', 1, N'正常', N'0', N'sys_notice_status', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (17, N'000000', 2, N'关闭', N'1', N'sys_notice_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'关闭状态') +GO +INSERT sys_dict_data VALUES (29, N'000000', 99, N'其他', N'0', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'其他操作'); +GO +INSERT sys_dict_data VALUES (18, N'000000', 1, N'新增', N'1', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'新增操作') +GO +INSERT sys_dict_data VALUES (19, N'000000', 2, N'修改', N'2', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'修改操作') +GO +INSERT sys_dict_data VALUES (20, N'000000', 3, N'删除', N3, N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'删除操作') +GO +INSERT sys_dict_data VALUES (21, N'000000', 4, N'授权', N'4', N'sys_oper_type', N'', N'primary', N'N', 103, 1, getdate(), NULL, NULL, N'授权操作') +GO +INSERT sys_dict_data VALUES (22, N'000000', 5, N'导出', N'5', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'导出操作') +GO +INSERT sys_dict_data VALUES (23, N'000000', 6, N'导入', N'6', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'导入操作') +GO +INSERT sys_dict_data VALUES (24, N'000000', 7, N'强退', N'7', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'强退操作') +GO +INSERT sys_dict_data VALUES (25, N'000000', 8, N'生成代码', N'8', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'生成操作') +GO +INSERT sys_dict_data VALUES (26, N'000000', 9, N'清空数据', N'9', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'清空操作') +GO +INSERT sys_dict_data VALUES (27, N'000000', 1, N'成功', N'0', N'sys_common_status', N'', N'primary', N'N', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (28, N'000000', 2, N'失败', N'1', N'sys_common_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (30, N'000000', 0, N'密码认证', N'password', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'密码认证') +GO +INSERT sys_dict_data VALUES (31, N'000000', 0, N'短信认证', N'sms', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'短信认证') +GO +INSERT sys_dict_data VALUES (32, N'000000', 0, N'邮件认证', N'email', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'邮件认证') +GO +INSERT sys_dict_data VALUES (33, N'000000', 0, N'小程序认证', N'xcx', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'小程序认证') +GO +INSERT sys_dict_data VALUES (34, N'000000', 0, N'三方登录认证', N'`social`', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'三方登录认证') +GO +INSERT sys_dict_data VALUES (35, N'000000', 0, N'PC', N'`pc`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'PC') +GO +INSERT sys_dict_data VALUES (36, N'000000', 0, N'安卓', N'`android`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'安卓') +GO +INSERT sys_dict_data VALUES (37, N'000000', 0, N'iOS', N'`ios`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'iOS') +GO +INSERT sys_dict_data VALUES (38, N'000000', 0, N'小程序', N'`xcx`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'小程序') +GO + +CREATE TABLE sys_dict_type +( + dict_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dict_name nvarchar(100) DEFAULT '' NULL, + dict_type nvarchar(100) DEFAULT '' NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_dict__3BD4186C409C5391 PRIMARY KEY CLUSTERED (dict_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX sys_dict_type_index1 ON sys_dict_type (tenant_id, dict_type) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type' +GO + +INSERT sys_dict_type VALUES (1, N'000000', N'用户性别', N'sys_user_sex', 103, 1, getdate(), NULL, NULL, N'用户性别列表') +GO +INSERT sys_dict_type VALUES (2, N'000000', N'菜单状态', N'sys_show_hide', 103, 1, getdate(), NULL, NULL, N'菜单状态列表') +GO +INSERT sys_dict_type VALUES (3, N'000000', N'系统开关', N'sys_normal_disable', 103, 1, getdate(), NULL, NULL, N'系统开关列表') +GO +INSERT sys_dict_type VALUES (4, N'000000', N'任务状态', N'sys_job_status', 103, 1, getdate(), NULL, NULL, N'任务状态列表') +GO +INSERT sys_dict_type VALUES (5, N'000000', N'任务分组', N'sys_job_group', 103, 1, getdate(), NULL, NULL, N'任务分组列表') +GO +INSERT sys_dict_type VALUES (6, N'000000', N'系统是否', N'sys_yes_no', 103, 1, getdate(), NULL, NULL, N'系统是否列表') +GO +INSERT sys_dict_type VALUES (7, N'000000', N'通知类型', N'sys_notice_type', 103, 1, getdate(), NULL, NULL, N'通知类型列表') +GO +INSERT sys_dict_type VALUES (8, N'000000', N'通知状态', N'sys_notice_status', 103, 1, getdate(), NULL, NULL, N'通知状态列表') +GO +INSERT sys_dict_type VALUES (9, N'000000', N'操作类型', N'sys_oper_type', 103, 1, getdate(), NULL, NULL, N'操作类型列表') +GO +INSERT sys_dict_type VALUES (10, N'000000', N'系统状态', N'sys_common_status', 103, 1, getdate(), NULL, NULL, N'登录状态列表') +GO +INSERT sys_dict_type VALUES (11, N'000000', N'授权类型', N'sys_grant_type', 103, 1, getdate(), NULL, NULL, N'认证授权类型') +GO +INSERT sys_dict_type VALUES (12, N'000000', N'设备类型', N'sys_device_type', 103, 1, getdate(), NULL, NULL, N'客户端设备类型') +GO + +CREATE TABLE sys_logininfor +( + info_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + user_name nvarchar(50) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + ipaddr nvarchar(128) DEFAULT '' NULL, + login_location nvarchar(255) DEFAULT '' NULL, + browser nvarchar(50) DEFAULT '' NULL, + os nvarchar(50) DEFAULT '' NULL, + status nchar(1) DEFAULT ('0') NULL, + msg nvarchar(255) DEFAULT '' NULL, + login_time datetime2(7) NULL, + CONSTRAINT PK__sys_logi__3D8A9C1A1854AE10 PRIMARY KEY CLUSTERED (info_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_logininfor_s ON sys_logininfor (status) +GO +CREATE NONCLUSTERED INDEX idx_sys_logininfor_lt ON sys_logininfor (login_time) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'访问ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'info_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'客户端' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'client_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'设备类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'device_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录IP地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'ipaddr' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录地点' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'login_location' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'浏览器类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'browser' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作系统' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'os' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录状态(0成功 1失败)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'提示消息' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'msg' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'访问时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'login_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'系统访问记录' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor' +GO + +CREATE TABLE sys_menu +( + menu_id bigint NOT NULL, + menu_name nvarchar(50) NOT NULL, + parent_id bigint DEFAULT ((0)) NULL, + order_num int DEFAULT ((0)) NULL, + path nvarchar(200) DEFAULT '' NULL, + component nvarchar(255) NULL, + query_param nvarchar(255) NULL, + is_frame int DEFAULT ((1)) NULL, + is_cache int DEFAULT ((0)) NULL, + menu_type nchar(1) DEFAULT '' NULL, + visible nchar(1) DEFAULT ((0)) NULL, + status nchar(1) DEFAULT ((0)) NULL, + perms nvarchar(100) NULL, + icon nvarchar(100) DEFAULT ('#') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) DEFAULT '' NULL, + CONSTRAINT PK__sys_menu__4CA0FADCF8545C58 PRIMARY KEY CLUSTERED (menu_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'父菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'parent_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'order_num' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'路由地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'path' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'组件路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'component' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'路由参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'query_param' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否为外链(0是 1否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'is_frame' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否缓存(0缓存 1不缓存)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'is_cache' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单类型(M目录 C菜单 F按钮)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示状态(0显示 1隐藏)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'visible' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'权限标识' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'perms' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单图标' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'icon' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单权限表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu' +GO + +INSERT sys_menu VALUES (1, N'系统管理', 0, 1, N'system', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'system', 103, 1, getdate(), NULL, NULL, N'系统管理目录') +GO +INSERT sys_menu VALUES (6, N'租户管理', 0, 2, N'tenant', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'chart', 103, 1, getdate(), NULL, NULL, N'租户管理目录') +GO +INSERT sys_menu VALUES (2, N'系统监控', 0, 3, N'monitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, getdate(), NULL, NULL, N'系统监控目录') +GO +INSERT sys_menu VALUES (3, N'系统工具', 0, 4, N'tool', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'tool', 103, 1, getdate(), NULL, NULL, N'系统工具目录') +GO +INSERT sys_menu VALUES (4, N'PLUS官网', 0, 5, N'https://gitee.com/dromara/RuoYi-Vue-Plus', null, N'', 0, 0, N'M', N'0', N'0', N'', N'guide', 103, 1, getdate(), null, null, N'RuoYi-Vue-Plus官网地址'); +GO +INSERT sys_menu VALUES (5, N'测试菜单', 0, 5, N'demo', NULL, N'', 1, 0, N'M', N'0', N'0', NULL, N'star', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (100, N'用户管理', 1, 1, N'user', N'system/user/index', N'', 1, 0, N'C', N'0', N'0', N'system:user:list', N'user', 103, 1, getdate(), NULL, NULL, N'用户管理菜单') +GO +INSERT sys_menu VALUES (101, N'角色管理', 1, 2, N'role', N'system/role/index', N'', 1, 0, N'C', N'0', N'0', N'system:role:list', N'peoples', 103, 1, getdate(), NULL, NULL, N'角色管理菜单') +GO +INSERT sys_menu VALUES (102, N'菜单管理', 1, 3, N'menu', N'system/menu/index', N'', 1, 0, N'C', N'0', N'0', N'system:menu:list', N'tree-table', 103, 1, getdate(), NULL, NULL, N'菜单管理菜单') +GO +INSERT sys_menu VALUES (103, N'部门管理', 1, 4, N'dept', N'system/dept/index', N'', 1, 0, N'C', N'0', N'0', N'system:dept:list', N'tree', 103, 1, getdate(), NULL, NULL, N'部门管理菜单') +GO +INSERT sys_menu VALUES (104, N'岗位管理', 1, 5, N'post', N'system/post/index', N'', 1, 0, N'C', N'0', N'0', N'system:post:list', N'post', 103, 1, getdate(), NULL, NULL, N'岗位管理菜单') +GO +INSERT sys_menu VALUES (105, N'字典管理', 1, 6, N'dict', N'system/dict/index', N'', 1, 0, N'C', N'0', N'0', N'system:dict:list', N'dict', 103, 1, getdate(), NULL, NULL, N'字典管理菜单') +GO +INSERT sys_menu VALUES (106, N'参数设置', 1, 7, N'config', N'system/config/index', N'', 1, 0, N'C', N'0', N'0', N'system:config:list', N'edit', 103, 1, getdate(), NULL, NULL, N'参数设置菜单') +GO +INSERT sys_menu VALUES (107, N'通知公告', 1, 8, N'notice', N'system/notice/index', N'', 1, 0, N'C', N'0', N'0', N'system:notice:list', N'message', 103, 1, getdate(), NULL, NULL, N'通知公告菜单') +GO +INSERT sys_menu VALUES (108, N'日志管理', 1, 9, N'log', N'', N'', 1, 0, N'M', N'0', N'0', N'', N'log', 103, 1, getdate(), NULL, NULL, N'日志管理菜单') +GO +INSERT sys_menu VALUES (109, N'在线用户', 2, 1, N'online', N'monitor/online/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:online:list', N'online', 103, 1, getdate(), NULL, NULL, N'在线用户菜单') +GO +INSERT sys_menu VALUES (113, N'缓存监控', 2, 5, N'cache', N'monitor/cache/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:cache:list', N'redis', 103, 1, getdate(), NULL, NULL, N'缓存监控菜单') +GO +INSERT sys_menu VALUES (115, N'代码生成', 3, 2, N'gen', N'tool/gen/index', N'', 1, 0, N'C', N'0', N'0', N'tool:gen:list', N'code', 103, 1, getdate(), NULL, NULL, N'代码生成菜单') +GO +INSERT sys_menu VALUES (121, N'租户管理', 6, 1, N'tenant', N'system/tenant/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenant:list', N'code', 103, 1, getdate(), NULL, NULL, N'租户管理菜单') +GO +INSERT sys_menu VALUES (122, N'租户套餐管理', 6, 2, N'tenantPackage', N'system/tenantPackage/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenantPackage:list', N'code', 103, 1, getdate(), NULL, NULL, N'租户套餐管理菜单') +GO +INSERT sys_menu VALUES (123, N'客户端管理', 1, 11, N'client', N'system/client/index', N'', 1, 0, N'C', N'0', N'0', N'system:client:list', N'international', 103, 1, getdate(), NULL, NULL, N'客户端管理菜单') +GO +INSERT sys_menu VALUES (117, N'Admin监控', 2, 5, N'Admin', N'monitor/admin/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:admin:list', N'dashboard', 103, 1, getdate(), NULL, NULL, N'Admin监控菜单'); +GO +INSERT sys_menu VALUES (118, N'文件管理', 1, 10, N'oss', N'system/oss/index', N'', 1, 0, N'C', '0', N'0', N'system:oss:list', N'upload', 103, 1, getdate(), NULL, NULL, N'文件管理菜单'); +GO +INSERT sys_menu VALUES (120, N'任务调度中心', 2, 5, N'snailjob', N'monitor/snailjob/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:snailjob:list', N'job', 103, 1, getdate(), NULL, NULL, N'SnailJob控制台菜单'); +GO +INSERT sys_menu VALUES (500, N'操作日志', 108, 1, N'operlog', N'monitor/operlog/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:operlog:list', N'form', 103, 1, getdate(), NULL, NULL, N'操作日志菜单') +GO +INSERT sys_menu VALUES (501, N'登录日志', 108, 2, N'logininfor', N'monitor/logininfor/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:logininfor:list', N'logininfor', 103, 1, getdate(), NULL, NULL, N'登录日志菜单') +GO +INSERT sys_menu VALUES (1001, N'用户查询', 100, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1002, N'用户新增', 100, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1003, N'用户修改', 100, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1004, N'用户删除', 100, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1005, N'用户导出', 100, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1006, N'用户导入', 100, 6, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:import', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1007, N'重置密码', 100, 7, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:resetPwd', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1008, N'角色查询', 101, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1009, N'角色新增', 101, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1010, N'角色修改', 101, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1011, N'角色删除', 101, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1012, N'角色导出', 101, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1013, N'菜单查询', 102, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1014, N'菜单新增', 102, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1015, N'菜单修改', 102, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1016, N'菜单删除', 102, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1017, N'部门查询', 103, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1018, N'部门新增', 103, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1019, N'部门修改', 103, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1020, N'部门删除', 103, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1021, N'岗位查询', 104, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1022, N'岗位新增', 104, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1023, N'岗位修改', 104, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1024, N'岗位删除', 104, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1025, N'岗位导出', 104, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1026, N'字典查询', 105, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1027, N'字典新增', 105, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1028, N'字典修改', 105, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1029, N'字典删除', 105, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1030, N'字典导出', 105, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1031, N'参数查询', 106, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1032, N'参数新增', 106, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1033, N'参数修改', 106, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1034, N'参数删除', 106, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1035, N'参数导出', 106, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1036, N'公告查询', 107, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1037, N'公告新增', 107, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1038, N'公告修改', 107, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1039, N'公告删除', 107, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1040, N'操作查询', 500, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1041, N'操作删除', 500, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1042, N'日志导出', 500, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1043, N'登录查询', 501, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1044, N'登录删除', 501, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1045, N'日志导出', 501, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1050, N'账户解锁', 501, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:unlock', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1046, N'在线查询', 109, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1047, N'批量强退', 109, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:batchLogout', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1048, N'单条强退', 109, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:forceLogout', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1055, N'生成查询', 115, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1056, N'生成修改', 115, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1057, N'生成删除', 115, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1058, N'导入代码', 115, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:import', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1059, N'预览代码', 115, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:preview', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1060, N'生成代码', 115, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:code', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +-- oss相关按钮 +INSERT sys_menu VALUES (1600, N'文件查询', 118, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1601, N'文件上传', 118, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:upload', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1602, N'文件下载', 118, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:download', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1603, N'文件删除', 118, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1620, N'配置列表', 118, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:list', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1621, N'配置添加', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1622, N'配置编辑', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1623, N'配置删除', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 租户管理相关按钮 +INSERT sys_menu VALUES (1606, N'租户查询', 121, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1607, N'租户新增', 121, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1608, N'租户修改', 121, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1609, N'租户删除', 121, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1610, N'租户导出', 121, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 租户套餐管理相关按钮 +INSERT sys_menu VALUES (1611, N'租户套餐查询', 122, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1612, N'租户套餐新增', 122, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1613, N'租户套餐修改', 122, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1614, N'租户套餐删除', 122, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1615, N'租户套餐导出', 122, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 客户端管理按钮 +INSERT sys_menu VALUES (1061, N'客户端管理查询', 123, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1062, N'客户端管理新增', 123, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1063, N'客户端管理修改', 123, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1064, N'客户端管理删除', 123, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1065, N'客户端管理导出', 123, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 测试菜单 +INSERT sys_menu VALUES (1500, N'测试单表', 5, 1, N'demo', N'demo/demo/index', N'', 1, 0, N'C', N'0', N'0', N'demo:demo:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试单表菜单'); +GO +INSERT sys_menu VALUES (1501, N'测试单表查询', 1500, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1502, N'测试单表新增', 1500, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1503, N'测试单表修改', 1500, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1504, N'测试单表删除', 1500, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1505, N'测试单表导出', 1500, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO + +INSERT sys_menu VALUES (1506, N'测试树表', 5, 1, N'tree', N'demo/tree/index', N'', 1, 0, N'C', N'0', N'0', N'demo:tree:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试树表菜单'); +GO +INSERT sys_menu VALUES (1507, N'测试树表查询', 1506, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1508, N'测试树表新增', 1506, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1509, N'测试树表修改', 1506, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1510, N'测试树表删除', 1506, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1511, N'测试树表导出', 1506, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO + +CREATE TABLE sys_notice +( + notice_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + notice_title nvarchar(50) NOT NULL, + notice_type nchar(1) NOT NULL, + notice_content nvarchar(max) NULL, + status nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(255) NULL, + CONSTRAINT PK__sys_noti__3E82A5DB0EC94801 PRIMARY KEY CLUSTERED (notice_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +TEXTIMAGE_ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告标题' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_title' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告类型(1通知 2公告)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告内容' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_content' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告状态(0正常 1关闭)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'通知公告表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice' +GO + +INSERT sys_notice VALUES (1, N'000000', N'温馨提醒:2018-07-01 若依新版本发布啦', N'2', N'新版本内容', N'0', 103, 1, getdate(), NULL, NULL, N'管理员') +GO +INSERT sys_notice VALUES (2, N'000000', N'维护通知:2018-07-01 若依系统凌晨维护', N'1', N'维护内容', N'0', 103, 1, getdate(), NULL, NULL, N'管理员') +GO + +CREATE TABLE sys_oper_log +( + oper_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + title nvarchar(50) DEFAULT '' NULL, + business_type int DEFAULT ((0)) NULL, + method nvarchar(100) DEFAULT '' NULL, + request_method nvarchar(10) DEFAULT '' NULL, + operator_type int DEFAULT ((0)) NULL, + oper_name nvarchar(50) DEFAULT '' NULL, + dept_name nvarchar(50) DEFAULT '' NULL, + oper_url nvarchar(255) DEFAULT '' NULL, + oper_ip nvarchar(128) DEFAULT '' NULL, + oper_location nvarchar(255) DEFAULT '' NULL, + oper_param nvarchar(4000) DEFAULT '' NULL, + json_result nvarchar(4000) DEFAULT '' NULL, + status int DEFAULT ((0)) NULL, + error_msg nvarchar(4000) DEFAULT '' NULL, + oper_time datetime2(7) NULL, + cost_time bigint DEFAULT ((0)) NULL, + CONSTRAINT PK__sys_oper__34723BF9BD954573 PRIMARY KEY CLUSTERED (oper_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_oper_log_bt ON sys_oper_log (business_type) +GO +CREATE NONCLUSTERED INDEX idx_sys_oper_log_s ON sys_oper_log (status) +GO +CREATE NONCLUSTERED INDEX idx_sys_oper_log_ot ON sys_oper_log (oper_time) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'日志主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'模块标题' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'title' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'业务类型(0其它 1新增 2修改 3删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'business_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'方法名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'method' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求方式' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'request_method' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作类别(0其它 1后台用户 2手机端用户)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'operator_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作人员' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'dept_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求URL' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_url' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'主机地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_ip' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作地点' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_location' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_param' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'返回参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'json_result' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作状态(0正常 1异常)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'错误消息' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'error_msg' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消耗时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'cost_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作日志记录' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log' +GO + +CREATE TABLE sys_post +( + post_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dept_id bigint NOT NULL, + post_code nvarchar(64) NOT NULL, + post_category nvarchar(100) NULL, + post_name nvarchar(50) NOT NULL, + post_sort int NOT NULL, + status nchar(1) NOT NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_post__3ED7876668E2D081 PRIMARY KEY CLUSTERED (post_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位类别编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post' +GO + +INSERT sys_post VALUES (1, N'000000', 103, N'ceo', NULL, N'董事长', 1, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (2, N'000000', 100, N'se', NULL, N'项目经理', 2, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (3, N'000000', 100, N'hr', NULL, N'人力资源', 3, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (4, N'000000', 100, N'user', NULL, N'普通员工', 4, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO + +CREATE TABLE sys_role +( + role_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + role_name nvarchar(30) NOT NULL, + role_key nvarchar(100) NOT NULL, + role_sort int NOT NULL, + data_scope nchar(1) DEFAULT ('1') NULL, + menu_check_strictly tinyint DEFAULT ((1)) NULL, + dept_check_strictly tinyint DEFAULT ((1)) NULL, + status nchar(1) NOT NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_role__760965CCF9383145 PRIMARY KEY CLUSTERED (role_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色权限字符串' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'data_scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单树选择项是否关联显示' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'menu_check_strictly' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门树选择项是否关联显示' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'dept_check_strictly' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role' +GO + +INSERT sys_role VALUES (1, N'000000', N'超级管理员', N'superadmin', 1, N'1', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N'超级管理员') +GO +INSERT sys_role VALUES (3, N'000000', N'本部门及以下', N'test1', 3, N'4', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_role VALUES (4, N'000000', N'仅本人', N'test2', 4, N'5', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N''); +GO + +CREATE TABLE sys_role_dept +( + role_id bigint NOT NULL, + dept_id bigint NOT NULL, + CONSTRAINT PK__sys_role__2BC3005BABBCA08A PRIMARY KEY CLUSTERED (role_id, dept_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色和部门关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept' +GO + +CREATE TABLE sys_role_menu +( + role_id bigint NOT NULL, + menu_id bigint NOT NULL, + CONSTRAINT PK__sys_role__A2C36A6187BA4B17 PRIMARY KEY CLUSTERED (role_id, menu_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu', + 'COLUMN', N'menu_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色和菜单关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu' +GO + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +INSERT sys_role_menu VALUES (3, 1); +GO +INSERT sys_role_menu VALUES (3, 5); +GO +INSERT sys_role_menu VALUES (3, 100); +GO +INSERT sys_role_menu VALUES (3, 101); +GO +INSERT sys_role_menu VALUES (3, 102); +GO +INSERT sys_role_menu VALUES (3, 103); +GO +INSERT sys_role_menu VALUES (3, 104); +GO +INSERT sys_role_menu VALUES (3, 105); +GO +INSERT sys_role_menu VALUES (3, 106); +GO +INSERT sys_role_menu VALUES (3, 107); +GO +INSERT sys_role_menu VALUES (3, 108); +GO +INSERT sys_role_menu VALUES (3, 118); +GO +INSERT sys_role_menu VALUES (3, 123); +GO +INSERT sys_role_menu VALUES (3, 500); +GO +INSERT sys_role_menu VALUES (3, 501); +GO +INSERT sys_role_menu VALUES (3, 1001); +GO +INSERT sys_role_menu VALUES (3, 1002); +GO +INSERT sys_role_menu VALUES (3, 1003); +GO +INSERT sys_role_menu VALUES (3, 1004); +GO +INSERT sys_role_menu VALUES (3, 1005); +GO +INSERT sys_role_menu VALUES (3, 1006); +GO +INSERT sys_role_menu VALUES (3, 1007); +GO +INSERT sys_role_menu VALUES (3, 1008); +GO +INSERT sys_role_menu VALUES (3, 1009); +GO +INSERT sys_role_menu VALUES (3, 1010); +GO +INSERT sys_role_menu VALUES (3, 1011); +GO +INSERT sys_role_menu VALUES (3, 1012); +GO +INSERT sys_role_menu VALUES (3, 1013); +GO +INSERT sys_role_menu VALUES (3, 1014); +GO +INSERT sys_role_menu VALUES (3, 1015); +GO +INSERT sys_role_menu VALUES (3, 1016); +GO +INSERT sys_role_menu VALUES (3, 1017); +GO +INSERT sys_role_menu VALUES (3, 1018); +GO +INSERT sys_role_menu VALUES (3, 1019); +GO +INSERT sys_role_menu VALUES (3, 1020); +GO +INSERT sys_role_menu VALUES (3, 1021); +GO +INSERT sys_role_menu VALUES (3, 1022); +GO +INSERT sys_role_menu VALUES (3, 1023); +GO +INSERT sys_role_menu VALUES (3, 1024); +GO +INSERT sys_role_menu VALUES (3, 1025); +GO +INSERT sys_role_menu VALUES (3, 1026); +GO +INSERT sys_role_menu VALUES (3, 1027); +GO +INSERT sys_role_menu VALUES (3, 1028); +GO +INSERT sys_role_menu VALUES (3, 1029); +GO +INSERT sys_role_menu VALUES (3, 1030); +GO +INSERT sys_role_menu VALUES (3, 1031); +GO +INSERT sys_role_menu VALUES (3, 1032); +GO +INSERT sys_role_menu VALUES (3, 1033); +GO +INSERT sys_role_menu VALUES (3, 1034); +GO +INSERT sys_role_menu VALUES (3, 1035); +GO +INSERT sys_role_menu VALUES (3, 1036); +GO +INSERT sys_role_menu VALUES (3, 1037); +GO +INSERT sys_role_menu VALUES (3, 1038); +GO +INSERT sys_role_menu VALUES (3, 1039); +GO +INSERT sys_role_menu VALUES (3, 1040); +GO +INSERT sys_role_menu VALUES (3, 1041); +GO +INSERT sys_role_menu VALUES (3, 1042); +GO +INSERT sys_role_menu VALUES (3, 1043); +GO +INSERT sys_role_menu VALUES (3, 1044); +GO +INSERT sys_role_menu VALUES (3, 1045); +GO +INSERT sys_role_menu VALUES (3, 1050); +GO +INSERT sys_role_menu VALUES (3, 1061); +GO +INSERT sys_role_menu VALUES (3, 1062); +GO +INSERT sys_role_menu VALUES (3, 1063); +GO +INSERT sys_role_menu VALUES (3, 1064); +GO +INSERT sys_role_menu VALUES (3, 1065); +GO +INSERT sys_role_menu VALUES (3, 1500); +GO +INSERT sys_role_menu VALUES (3, 1501); +GO +INSERT sys_role_menu VALUES (3, 1502); +GO +INSERT sys_role_menu VALUES (3, 1503); +GO +INSERT sys_role_menu VALUES (3, 1504); +GO +INSERT sys_role_menu VALUES (3, 1505); +GO +INSERT sys_role_menu VALUES (3, 1506); +GO +INSERT sys_role_menu VALUES (3, 1507); +GO +INSERT sys_role_menu VALUES (3, 1508); +GO +INSERT sys_role_menu VALUES (3, 1509); +GO +INSERT sys_role_menu VALUES (3, 1510); +GO +INSERT sys_role_menu VALUES (3, 1511); +GO +INSERT sys_role_menu VALUES (3, 1600); +GO +INSERT sys_role_menu VALUES (3, 1601); +GO +INSERT sys_role_menu VALUES (3, 1602); +GO +INSERT sys_role_menu VALUES (3, 1603); +GO +INSERT sys_role_menu VALUES (3, 1620); +GO +INSERT sys_role_menu VALUES (3, 1621); +GO +INSERT sys_role_menu VALUES (3, 1622); +GO +INSERT sys_role_menu VALUES (3, 1623); +GO +INSERT sys_role_menu VALUES (3, 11618); +GO +INSERT sys_role_menu VALUES (3, 11619); +GO +INSERT sys_role_menu VALUES (3, 11629); +GO +INSERT sys_role_menu VALUES (3, 11632); +GO +INSERT sys_role_menu VALUES (3, 11633); +GO +INSERT sys_role_menu VALUES (3, 11638); +GO +INSERT sys_role_menu VALUES (3, 11639); +GO +INSERT sys_role_menu VALUES (3, 11640); +GO +INSERT sys_role_menu VALUES (3, 11641); +GO +INSERT sys_role_menu VALUES (3, 11642); +GO +INSERT sys_role_menu VALUES (3, 11643); +GO +INSERT sys_role_menu VALUES (4, 5); +GO +INSERT sys_role_menu VALUES (4, 1500); +GO +INSERT sys_role_menu VALUES (4, 1501); +GO +INSERT sys_role_menu VALUES (4, 1502); +GO +INSERT sys_role_menu VALUES (4, 1503); +GO +INSERT sys_role_menu VALUES (4, 1504); +GO +INSERT sys_role_menu VALUES (4, 1505); +GO +INSERT sys_role_menu VALUES (4, 1506); +GO +INSERT sys_role_menu VALUES (4, 1507); +GO +INSERT sys_role_menu VALUES (4, 1508); +GO +INSERT sys_role_menu VALUES (4, 1509); +GO +INSERT sys_role_menu VALUES (4, 1510); +GO +INSERT sys_role_menu VALUES (4, 1511); +GO + +CREATE TABLE sys_user +( + user_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dept_id bigint NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) NOT NULL, + user_type nvarchar(10) DEFAULT ('sys_user') NULL, + email nvarchar(50) DEFAULT '' NULL, + phonenumber nvarchar(11) DEFAULT '' NULL, + sex nchar(1) DEFAULT ('0') NULL, + avatar bigint NULL, + password nvarchar(100) DEFAULT '' NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + login_ip nvarchar(128) DEFAULT '' NULL, + login_date datetime2(7) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_user__B9BE370F79170B6A PRIMARY KEY CLUSTERED (user_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户类型(sys_user系统用户)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'手机号码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'phonenumber' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户性别(0男 1女 2未知)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'sex' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'密码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'password' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'帐号状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'最后登录IP' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'login_ip' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'最后登录时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'login_date' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user' +GO + +INSERT sys_user VALUES (1, N'000000', 103, N'admin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'管理员') +GO +INSERT sys_user VALUES (3, N'000000', 108, N'test', N'本部门及以下 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 3, getdate(), NULL); +GO +INSERT sys_user VALUES (4, N'000000', 102, N'test1', N'仅本人 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 4, getdate(), NULL); +GO + +CREATE TABLE sys_user_post +( + user_id bigint NOT NULL, + post_id bigint NOT NULL, + CONSTRAINT PK__sys_user__CA534F799C04589B PRIMARY KEY CLUSTERED (user_id, post_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post', + 'COLUMN', N'post_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户与岗位关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post' +GO + +INSERT sys_user_post VALUES (1, 1) +GO + +CREATE TABLE sys_user_role +( + user_id bigint NOT NULL, + role_id bigint NOT NULL, + CONSTRAINT PK__sys_user__6EDEA153FB34D8F0 PRIMARY KEY CLUSTERED (user_id, role_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户和角色关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role' +GO + +INSERT sys_user_role VALUES (1, 1) +GO +INSERT sys_user_role VALUES (3, 3); +GO +INSERT sys_user_role VALUES (4, 4); +GO + +CREATE TABLE sys_oss +( + oss_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + file_name nvarchar(255) DEFAULT '' NOT NULL, + original_name nvarchar(255) DEFAULT '' NOT NULL, + file_suffix nvarchar(10) DEFAULT '' NOT NULL, + url nvarchar(500) NOT NULL, + create_dept bigint NULL, + create_time datetime2(7) NULL, + create_by bigint NULL, + update_time datetime2(7) NULL, + update_by bigint NULL, + service nvarchar(20) DEFAULT ('minio') NOT NULL, + CONSTRAINT PK__sys_oss__91241EA442389F0D PRIMARY KEY CLUSTERED (oss_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'对象存储主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'oss_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'tenant_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'文件名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'file_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'原名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'original_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'文件后缀名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'file_suffix' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'URL地址', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'url' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'上传人', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'服务商', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'service' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'OSS对象存储表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss' +GO + +CREATE TABLE sys_oss_config +( + oss_config_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + config_key nvarchar(20) DEFAULT '' NOT NULL, + access_key nvarchar(255) DEFAULT '' NULL, + secret_key nvarchar(255) DEFAULT '' NULL, + bucket_name nvarchar(255) DEFAULT '' NULL, + prefix nvarchar(255) DEFAULT '' NULL, + endpoint nvarchar(255) DEFAULT '' NULL, + domain nvarchar(255) DEFAULT '' NULL, + is_https nchar(1) DEFAULT ('N') NULL, + region nvarchar(255) DEFAULT '' NULL, + access_policy nchar(1) DEFAULT ('1') NOT NULL, + status nchar(1) DEFAULT ('1') NULL, + ext1 nvarchar(255) DEFAULT '' NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_oss___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (oss_config_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'oss_config_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'tenant_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'配置key', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'config_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'accessKey', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'access_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'secret_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'桶名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'bucket_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'前缀', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'prefix' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'访问站点', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'endpoint' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'自定义域名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'domain' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'是否https(Y=是,N=否)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'is_https' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'域', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'region' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'桶权限类型(0=private 1=public 2=custom)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'access_policy' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'是否默认(0=是,1=否)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'status' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'ext1' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'remark' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'对象存储配置表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config' +GO + +INSERT INTO sys_oss_config VALUES (N'1', N'000000', N'minio', N'ruoyi', N'ruoyi123', N'ruoyi', N'', N'127.0.0.1:9000', N'',N'N', N'', N'1', N'0', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N'2', N'000000', N'qiniu', N'XXXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi', N'', N's3-cn-north-1.qiniucs.com', N'',N'N', N'', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N3, N'000000', N'aliyun', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi', N'', N'oss-cn-beijing.aliyuncs.com', N'',N'N', N'', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N'4', N'000000', N'qcloud', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi-1250000000', N'', N'cos.ap-beijing.myqcloud.com', N'',N'N', N'ap-beijing', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N'5', N'000000', N'image', N'ruoyi', N'ruoyi123', N'ruoyi', N'image', N'127.0.0.1:9000', N'',N'N', N'', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO + + +CREATE TABLE sys_client +( + id bigint NOT NULL, + client_id nvarchar(64) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + client_secret nvarchar(255) DEFAULT '' NULL, + grant_type nvarchar(255) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + active_timeout int DEFAULT ((1800)) NULL, + timeout int DEFAULT ((604800)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL + CONSTRAINT PK__sys_client___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'客户端id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'客户端key', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'客户端秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_secret' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'授权类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'grant_type' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'设备类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'device_type' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'token活跃超时时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'active_timeout' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'token固定超时', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'timeout' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'status' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'系统授权表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client' +GO + +INSERT INTO sys_client VALUES (N'1', N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO +INSERT INTO sys_client VALUES (N'2', N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO + +CREATE TABLE test_demo +( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dept_id bigint NULL, + user_id bigint NULL, + order_num int DEFAULT ((0)) NULL, + test_key nvarchar(255) NULL, + value nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_dem__3213E83F176051C8 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'排序号', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'order_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'key键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'test_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'value' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试单表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo' +GO + +CREATE TABLE test_tree +( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + parent_id bigint DEFAULT ((0)) NULL, + dept_id bigint NULL, + user_id bigint NULL, + tree_name nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_tre__3213E83FC75A1B63 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'tree_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试树表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree' +GO + +INSERT test_demo VALUES (1, N'000000', 102, 4, 1, N'测试数据权限', N'测试', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (2, N'000000', 102, 3, 2, N'子节点1', N'111', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (3, N'000000', 102, 3, 3, N'子节点2', N'222', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (4, N'000000', 108, 4, 4, N'测试数据', N'demo', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (5, N'000000', 108, 3, 13, N'子节点11', N'1111', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (6, N'000000', 108, 3, 12, N'子节点22', N'2222', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (7, N'000000', 108, 3, 11, N'子节点33', N'3333', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (8, N'000000', 108, 3, 10, N'子节点44', N'4444', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (9, N'000000', 108, 3, 9, N'子节点55', N'5555', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (10, N'000000', 108, 3, 8, N'子节点66', N'6666', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (11, N'000000', 108, 3, 7, N'子节点77', N'7777', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (12, N'000000', 108, 3, 6, N'子节点88', N'8888', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (13, N'000000', 108, 3, 5, N'子节点99', N'9999', 0, 103, getdate(), 1, NULL, NULL, 0); +GO + +INSERT test_tree VALUES (1, N'000000', 0, 102, 4, N'测试数据权限', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (2, N'000000', 1, 102, 3, N'子节点1', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (3, N'000000', 2, 102, 3, N'子节点2', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (4, N'000000', 0, 108, 4, N'测试树1', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (5, N'000000', 4, 108, 3, N'子节点11', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (6, N'000000', 4, 108, 3, N'子节点22', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (7, N'000000', 4, 108, 3, N'子节点33', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (8, N'000000', 5, 108, 3, N'子节点44', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (9, N'000000', 6, 108, 3, N'子节点55', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (10, N'000000', 7, 108, 3, N'子节点66', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (11, N'000000', 7, 108, 3, N'子节点77', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (12, N'000000', 10, 108, 3, N'子节点88', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (13, N'000000', 10, 108, 3, N'子节点99', 0, 103, getdate(), 1, NULL, NULL, 0); +GO diff --git a/script/sql/sqlserver/sqlserver_ry_workflow.sql b/script/sql/sqlserver/sqlserver_ry_workflow.sql new file mode 100644 index 0000000..ea4b720 --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_workflow.sql @@ -0,0 +1,1336 @@ +CREATE TABLE flow_definition ( + id bigint NOT NULL, + flow_code nvarchar(40) NOT NULL, + flow_name nvarchar(100) NOT NULL, + category nvarchar(100) NULL, + version nvarchar(20) NOT NULL, + is_publish tinyint DEFAULT('0') NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + activity_status tinyint DEFAULT('1') NULL, + listener_type nvarchar(100) NULL, + listener_path nvarchar(400) NULL, + ext nvarchar(500) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_def__3213E83FEE39AE33 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'flow_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'flow_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程类别', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'category' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程版本', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'是否发布(0未发布 1已发布 9失效)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'is_publish' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程激活状态(0挂起 1激活)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'activity_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'listener_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'listener_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务详情 存业务表对象json字符串', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义表', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition' +GO + +CREATE TABLE flow_node ( + id bigint NOT NULL, + node_type tinyint NOT NULL, + definition_id bigint NOT NULL, + node_code nvarchar(100) NOT NULL, + node_name nvarchar(100) NULL, + permission_flag nvarchar(200) NULL, + node_ratio decimal(6,3) NULL, + coordinate nvarchar(100) NULL, + skip_any_node nvarchar(100) DEFAULT('N') NULL, + any_node_skip nvarchar(100) NULL, + listener_type nvarchar(100) NULL, + listener_path nvarchar(400) NULL, + handler_type nvarchar(100) NULL, + handler_path nvarchar(400) NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + version nvarchar(20) NOT NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_nod__3213E83F372470DE PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'权限标识(权限类型:权限标识,可以多个,用逗号隔开)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'permission_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程签署比例值', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_ratio' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'坐标', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'coordinate' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'是否可以退回任意节点(Y是 N否)即将删除', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'skip_any_node' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任意结点跳转', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'any_node_skip' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'listener_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'listener_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'处理器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'handler_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'处理器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'handler_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'版本', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点表', +'SCHEMA', N'dbo', +'TABLE', N'flow_node' +GO + +CREATE TABLE flow_skip ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + now_node_code nvarchar(100) NOT NULL, + now_node_type tinyint NULL, + next_node_code nvarchar(100) NOT NULL, + next_node_type tinyint NULL, + skip_name nvarchar(100) NULL, + skip_type nvarchar(40) NULL, + skip_condition nvarchar(200) NULL, + coordinate nvarchar(100) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_ski__3213E83F073FEE6E PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'当前流程节点的编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'now_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'now_node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'下一个流程节点的编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'next_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'next_node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转类型(PASS审批通过 REJECT退回)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转条件', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_condition' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'坐标', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'coordinate' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点跳转关联表', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip' +GO + +CREATE TABLE flow_instance ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + business_id nvarchar(40) NOT NULL, + node_type tinyint NOT NULL, + node_code nvarchar(40) NOT NULL, + node_name nvarchar(100) NULL, + variable nvarchar(max) NULL, + flow_status nvarchar(20) NOT NULL, + activity_status tinyint DEFAULT('1') NULL, + def_json nvarchar(max) NULL, + create_by nvarchar(64) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + ext nvarchar(500) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_ins__3213E83F5190FEE1 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +TEXTIMAGE_ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'business_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务变量', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'variable' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回 8已完成 9已退回 10失效)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'flow_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程激活状态(0挂起 1激活)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'activity_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义json', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'def_json' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'扩展字段,预留给业务系统使用', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程实例表', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance' +GO + +CREATE TABLE flow_task ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + instance_id bigint NOT NULL, + node_code nvarchar(100) NOT NULL, + node_name nvarchar(100) NULL, + node_type tinyint NOT NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_tas__3213E83F5AE1F1BA PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_instance表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'instance_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'待办任务表', +'SCHEMA', N'dbo', +'TABLE', N'flow_task' +GO + +CREATE TABLE flow_his_task ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + instance_id bigint NOT NULL, + task_id bigint NOT NULL, + node_code nvarchar(200) NULL, + node_name nvarchar(200) NULL, + node_type tinyint NULL, + target_node_code nvarchar(100) NULL, + target_node_name nvarchar(100) NULL, + approver nvarchar(40) NULL, + cooperate_type tinyint DEFAULT('0') NULL, + collaborator nvarchar(40) NULL, + skip_type nvarchar(10) NOT NULL, + flow_status nvarchar(20) NOT NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + message nvarchar(500) NULL, + variable nvarchar(max) NULL, + ext nvarchar(500) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_his__3213E83F67951564 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_instance表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'instance_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_task表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'task_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'目标节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'target_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'结束节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'target_node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批者', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'approver' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'cooperate_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'协作人', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'collaborator' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流转类型(PASS通过 REJECT退回 NONE无动作)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'skip_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程状态(1审批中 2 审批通过 9已退回 10失效)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'flow_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批意见', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务变量', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'variable' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务详情 存业务表对象json字符串', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务开始时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批完成时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'历史任务记录表', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task' +GO + +CREATE TABLE flow_user ( + id bigint NOT NULL, + type nchar(1) NOT NULL, + processed_by nvarchar(80) NULL, + associated bigint NOT NULL, + create_time datetime2(7) NULL, + create_by nvarchar(80) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_use__3213E83FFA38CA8B PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX user_processed_type ON flow_user (processed_by ASC, type ASC) +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'权限人', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'processed_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务表id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'associated' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程用户表', +'SCHEMA', N'dbo', +'TABLE', N'flow_user' +GO + +CREATE TABLE flow_category ( + category_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT('000000') NULL, + parent_id bigint DEFAULT(0) NULL, + ancestors nvarchar(500) DEFAULT('') NULL, + category_name nvarchar(30) NOT NULL, + order_num int DEFAULT(0) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__flow_cat__D54EE9B4AE98B9C1 PRIMARY KEY CLUSTERED (category_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类ID', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'category_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户编号', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'父流程分类id', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'祖级列表', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'ancestors' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'category_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'显示顺序', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'order_num' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志(0代表存在 1代表删除)', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建部门', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类', +'SCHEMA', N'dbo', +'TABLE', N'flow_category' +GO + +INSERT flow_category VALUES (100, N'000000', 0, N'0', N'OA审批', 0, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (101, N'000000', 100, N'0,100', N'假勤管理', 0, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (102, N'000000', 100, N'0,100', N'人事管理', 1, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (103, N'000000', 101, N'0,100,101', N'请假', 0, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (104, N'000000', 101, N'0,100,101', N'出差', 1, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (105, N'000000', 101, N'0,100,101', N'加班', 2, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (106, N'000000', 101, N'0,100,101', N'换班', 3, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (107, N'000000', 101, N'0,100,101', N'外出', 4, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (108, N'000000', 102, N'0,100,102', N'转正', 1, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (109, N'000000', 102, N'0,100,102', N'离职', 2, N'0', 103, 1, getdate(), NULL, NULL); +GO + +CREATE TABLE test_leave ( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT('000000') NULL, + leave_type nvarchar(255) NOT NULL, + start_date datetime2(7) NOT NULL, + end_date datetime2(7) NOT NULL, + leave_days int NOT NULL, + remark nvarchar(255) NULL, + status nvarchar(255) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__test_lea__3213E83F348788FA PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'id', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户编号', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假类型', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'leave_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'start_date' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'结束时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'end_date' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假天数', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'leave_days' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假原因', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'状态', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建部门', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假申请表', +'SCHEMA', N'dbo', +'TABLE', N'test_leave' +GO + +INSERT sys_menu VALUES (11616, N'工作流', 0, 6, N'workflow', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'workflow', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11618, N'我的任务', 0, 7, N'task', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'my-task', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11619, N'我的待办', 11618, 2, N'taskWaiting', N'workflow/task/taskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11632, N'我的已办', 11618, 3, N'taskFinish', N'workflow/task/taskFinish', N'', 1, 1, N'C', N'0', N'0', N'', N'finish', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11633, N'我的抄送', 11618, 4, N'taskCopyList', N'workflow/task/taskCopyList', N'', 1, 1, N'C', N'0', N'0', N'', N'my-copy', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11620, N'流程定义', 11616, 3, N'processDefinition', N'workflow/processDefinition/index', N'', 1, 1, N'C', N'0', N'0', N'', N'process-definition', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11621, N'流程实例', 11630, 1, N'processInstance', N'workflow/processInstance/index', N'', 1, 1, N'C', N'0', N'0', N'', N'tree-table', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11622, N'流程分类', 11616, 1, N'category', N'workflow/category/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:category:list', N'category', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11629, N'我发起的', 11618, 1, N'myDocument', N'workflow/task/myDocument', N'', 1, 1, N'C', N'0', N'0', N'', N'guide', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11630, N'流程监控', 11616, 4, N'monitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11631, N'待办任务', 11630, 2, N'allTaskWaiting', N'workflow/task/allTaskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N''); +GO + +-- 流程分类管理相关按钮 +INSERT sys_menu VALUES (11623, N'流程分类查询', 11622, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11624, N'流程分类新增', 11622, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11625, N'流程分类修改', 11622, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11626, N'流程分类删除', 11622, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11627, N'流程分类导出', 11622, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO + +-- 请假测试相关按钮 +INSERT sys_menu VALUES (11638, N'请假申请', 5, 1, N'leave', N'workflow/leave/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:leave:list', N'#', 103, 1, GETDATE(), NULL, NULL, N'请假申请菜单'); +GO +INSERT sys_menu VALUES (11639, N'请假申请查询', 11638, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11640, N'请假申请新增', 11638, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11641, N'请假申请修改', 11638, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11642, N'请假申请删除', 11638, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11643, N'请假申请导出', 11638, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); + +INSERT sys_dict_type VALUES (13, N'000000', N'业务状态', N'wf_business_status', 103, 1, GETDATE(), NULL, NULL, N'业务状态列表'); +GO +INSERT sys_dict_type VALUES (14, N'000000', N'表单类型', N'wf_form_type', 103, 1, GETDATE(), NULL, NULL, N'表单类型列表'); +GO +INSERT sys_dict_type VALUES (15, N'000000', N'任务状态', N'wf_task_status', 103, 1, GETDATE(), NULL, NULL, N'任务状态'); +GO + +INSERT sys_dict_data VALUES (39, N'000000', 1, N'已撤销', N'cancel', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已撤销'); +GO +INSERT sys_dict_data VALUES (40, N'000000', 2, N'草稿', N'draft', N'wf_business_status', N'', N'info', N'N', 103, 1, GETDATE(), NULL, NULL, N'草稿'); +GO +INSERT sys_dict_data VALUES (41, N'000000', 3, N'待审核', N'waiting', N'wf_business_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'待审核'); +GO +INSERT sys_dict_data VALUES (42, N'000000', 4, N'已完成', N'finish', N'wf_business_status', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'已完成'); +GO +INSERT sys_dict_data VALUES (43, N'000000', 5, N'已作废', N'invalid', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已作废'); +GO +INSERT sys_dict_data VALUES (44, N'000000', 6, N'已退回', N'back', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已退回'); +GO +INSERT sys_dict_data VALUES (45, N'000000', 7, N'已终止', N'termination', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已终止'); +GO +INSERT sys_dict_data VALUES (46, N'000000', 1, N'自定义表单', N'static', N'wf_form_type', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'自定义表单'); +GO +INSERT sys_dict_data VALUES (47, N'000000', 2, N'动态表单', N'dynamic', N'wf_form_type', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'动态表单'); +GO +INSERT sys_dict_data VALUES (48, N'000000', 1, N'撤销', N'cancel', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'撤销'); +GO +INSERT sys_dict_data VALUES (49, N'000000', 2, N'通过', N'pass', N'wf_task_status', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'通过'); +GO +INSERT sys_dict_data VALUES (50, N'000000', 3, N'待审核', N'waiting', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'待审核'); +GO +INSERT sys_dict_data VALUES (51, N'000000', 4, N'作废', N'invalid', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'作废'); +GO +INSERT sys_dict_data VALUES (52, N'000000', 5, N'退回', N'back', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'退回'); +GO +INSERT sys_dict_data VALUES (53, N'000000', 6, N'终止', N'termination', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'终止'); +GO +INSERT sys_dict_data VALUES (54, N'000000', 7, N'转办', N'transfer', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'转办'); +GO +INSERT sys_dict_data VALUES (55, N'000000', 8, N'委托', N'depute', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'委托'); +GO +INSERT sys_dict_data VALUES (56, N'000000', 9, N'抄送', N'copy', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'抄送'); +GO +INSERT sys_dict_data VALUES (57, N'000000', 10, N'加签', N'sign', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'加签'); +GO +INSERT sys_dict_data VALUES (58, N'000000', 11, N'减签', N'sign_off', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'减签'); +GO +INSERT sys_dict_data VALUES (59, N'000000', 11, N'超时', N'timeout', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'超时'); +GO diff --git a/script/sql/update/oracle/update_5.0-5.1.sql b/script/sql/update/oracle/update_5.0-5.1.sql new file mode 100644 index 0000000..09cfae8 --- /dev/null +++ b/script/sql/update/oracle/update_5.0-5.1.sql @@ -0,0 +1,151 @@ +ALTER TABLE gen_table ADD (data_name VARCHAR2(200) DEFAULT ''); + +COMMENT ON COLUMN gen_table.data_name IS '数据源名称'; + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120; + +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id number(20) not null, + user_id number(20) not null, + tenant_id varchar2(20) default null, + auth_id varchar2(255) not null, + source varchar2(255) not null, + open_id varchar2(255) default null, + user_name varchar2(30) not null, + nick_name varchar2(30) default '', + email varchar2(255) default '', + avatar varchar2(500) default '', + access_token varchar2(255) not null, + expire_in number(20) default null, + refresh_token varchar2(255) default null, + access_code varchar2(255) default null, + union_id varchar2(255) default null, + scope varchar2(255) default null, + token_type varchar2(255) default null, + id_token varchar2(255) default null, + mac_algorithm varchar2(255) default null, + mac_key varchar2(255) default null, + code varchar2(255) default null, + oauth_token varchar2(255) default null, + oauth_token_secret varchar2(255) default null, + create_dept number(20), + create_by number(20), + create_time date, + update_by number(20), + update_time date, + del_flag char(1) default '0' +); + +alter table sys_social add constraint pk_sys_social primary key (id); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 2代表删除)'; + + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id number(20) not null, + client_id varchar2(64) default null, + client_key varchar2(32) default null, + client_secret varchar2(255) default null, + grant_type varchar2(255) default null, + device_type varchar2(32) default null, + active_timeout number(11) default 1800, + timeout number(11) default 604800, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_client add constraint pk_sys_client primary key (id); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 2代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); + +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', '0', 103, 1, sysdate, null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', '0', 103, 1, sysdate, null, null, '客户端设备类型'); + +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '小程序'); + +-- 二级菜单 +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate, null, null, '客户端管理菜单'); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate, null, null, ''); + +-- 角色菜单权限 +insert into sys_role_menu values ('2', '1061'); +insert into sys_role_menu values ('2', '1062'); +insert into sys_role_menu values ('2', '1063'); +insert into sys_role_menu values ('2', '1064'); +insert into sys_role_menu values ('2', '1065'); + + +update sys_dept set leader = null; +ALTER TABLE sys_dept MODIFY (leader NUMBER(20)) diff --git a/script/sql/update/oracle/update_5.1.0-5.1.1.sql b/script/sql/update/oracle/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..979a4bd --- /dev/null +++ b/script/sql/update/oracle/update_5.1.0-5.1.1.sql @@ -0,0 +1,5 @@ +ALTER TABLE sys_logininfor ADD (client_key varchar2(32) DEFAULT ''); +COMMENT ON COLUMN sys_logininfor.client_key IS '客户端'; + +ALTER TABLE sys_logininfor ADD (device_type varchar2(32) DEFAULT ''); +COMMENT ON COLUMN sys_logininfor.device_type IS '设备类型'; diff --git a/script/sql/update/oracle/update_5.1.1-5.1.2.sql b/script/sql/update/oracle/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..d7c030c --- /dev/null +++ b/script/sql/update/oracle/update_5.1.1-5.1.2.sql @@ -0,0 +1,6 @@ +delete from sys_menu where menu_id in (1604, 1605); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, sysdate, null, null, ''); + diff --git a/script/sql/update/oracle/update_5.1.2-5.2.0.sql b/script/sql/update/oracle/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..1aa585a --- /dev/null +++ b/script/sql/update/oracle/update_5.1.2-5.2.0.sql @@ -0,0 +1,9 @@ +ALTER TABLE sys_dept ADD (dept_category varchar2(100) DEFAULT NULL) COMMENT '部门类别编码'; +COMMENT ON COLUMN sys_dept.dept_category IS '部门类别编码'; +ALTER TABLE sys_post ADD (dept_id number(20) NOT NULL) COMMENT '部门id'; +COMMENT ON COLUMN sys_post.dept_id IS '部门id'; +ALTER TABLE sys_post ADD (post_category VARCHAR2(100) DEFAULT NULL) COMMENT '岗位类别编码'; +COMMENT ON COLUMN sys_post.post_category IS '岗位类别编码'; +UPDATE sys_post SET dept_id = 100; +UPDATE sys_post SET dept_id = 103 where post_id = 1; +UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120; diff --git a/script/sql/update/postgres/update_5.0-5.1.sql b/script/sql/update/postgres/update_5.0-5.1.sql new file mode 100644 index 0000000..f5f0a5c --- /dev/null +++ b/script/sql/update/postgres/update_5.0-5.1.sql @@ -0,0 +1,150 @@ +ALTER TABLE gen_table ADD data_name varchar(200) default ''::varchar; + +COMMENT ON COLUMN gen_table.data_name IS '数据源名称'; + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120; + +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id int8 not null, + user_id int8 not null, + tenant_id varchar(20) default null::varchar, + auth_id varchar(255) not null, + source varchar(255) not null, + open_id varchar(255) default null::varchar, + user_name varchar(30) not null, + nick_name varchar(30) default ''::varchar, + email varchar(255) default ''::varchar, + avatar varchar(500) default ''::varchar, + access_token varchar(255) not null, + expire_in int8 default null, + refresh_token varchar(255) default null::varchar, + access_code varchar(255) default null::varchar, + union_id varchar(255) default null::varchar, + scope varchar(255) default null::varchar, + token_type varchar(255) default null::varchar, + id_token varchar(255) default null::varchar, + mac_algorithm varchar(255) default null::varchar, + mac_key varchar(255) default null::varchar, + code varchar(255) default null::varchar, + oauth_token varchar(255) default null::varchar, + oauth_token_secret varchar(255) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + del_flag char default '0'::bpchar, + constraint "pk_sys_social" primary key (id) +); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 2代表删除)'; + + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +drop table if exists sys_client; +create table sys_client ( + id int8, + client_id varchar(64) default ''::varchar, + client_key varchar(32) default ''::varchar, + client_secret varchar(255) default ''::varchar, + grant_type varchar(255) default ''::varchar, + device_type varchar(32) default ''::varchar, + active_timeout int4 default 1800, + timeout int4 default 604800, + status char(1) default '0'::bpchar, + del_flag char(1) default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint sys_client_pk primary key (id) +); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 2代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); + +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', '0', 103, 1, now(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', '0', 103, 1, now(), null, null, '客户端设备类型'); + +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '小程序'); + +-- 二级菜单 +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', '1', '0', 'C', '0', '0', 'system:client:list', 'international', 103, 1, now(), null, null, '客户端管理菜单'); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:export', '#', 103, 1, now(), null, null, ''); + +-- 角色菜单权限 +insert into sys_role_menu values ('2', '1061'); +insert into sys_role_menu values ('2', '1062'); +insert into sys_role_menu values ('2', '1063'); +insert into sys_role_menu values ('2', '1064'); +insert into sys_role_menu values ('2', '1065'); + + +update sys_dept set leader = null; +ALTER TABLE sys_dept ALTER COLUMN leader TYPE int8; diff --git a/script/sql/update/postgres/update_5.1.0-5.1.1.sql b/script/sql/update/postgres/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..29f5507 --- /dev/null +++ b/script/sql/update/postgres/update_5.1.0-5.1.1.sql @@ -0,0 +1,5 @@ +ALTER TABLE sys_logininfor ADD client_key varchar(32) default ''::varchar; +COMMENT ON COLUMN sys_logininfor.client_key IS '客户端'; + +ALTER TABLE sys_logininfor ADD device_type varchar(32) default ''::varchar; +COMMENT ON COLUMN sys_logininfor.device_type IS '设备类型'; diff --git a/script/sql/update/postgres/update_5.1.1-5.1.2.sql b/script/sql/update/postgres/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..62eb836 --- /dev/null +++ b/script/sql/update/postgres/update_5.1.1-5.1.2.sql @@ -0,0 +1,5 @@ +delete from sys_menu where menu_id in (1604, 1605); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, now(), null, null, ''); diff --git a/script/sql/update/postgres/update_5.1.2-5.2.0.sql b/script/sql/update/postgres/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..5089a09 --- /dev/null +++ b/script/sql/update/postgres/update_5.1.2-5.2.0.sql @@ -0,0 +1,9 @@ +ALTER TABLE sys_dept ADD COLUMN dept_category varchar(100) default null::varchar; +COMMENT ON COLUMN sys_dept.dept_category IS '客户端'; +ALTER TABLE sys_post ADD COLUMN dept_id int8 NOT NULL; +COMMENT ON COLUMN sys_post.dept_id IS '部门id'; +ALTER TABLE sys_post ADD COLUMN post_category varchar(100) default null::varchar; +COMMENT ON COLUMN sys_post.post_category IS '岗位类别编码'; +UPDATE sys_post SET dept_id = 100; +UPDATE sys_post SET dept_id = 103 where post_id = 1; +UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120; diff --git a/script/sql/update/sqlserver/update_5.0-5.1.sql b/script/sql/update/sqlserver/update_5.0-5.1.sql new file mode 100644 index 0000000..bde3813 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.0-5.1.sql @@ -0,0 +1,409 @@ +ALTER TABLE gen_table ADD data_name nvarchar(200) DEFAULT '' NULL +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据源名称', + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'data_name' +GO + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120 +GO + +create table sys_social +( + id bigint NOT NULL, + user_id bigint NOT NULL, + tenant_id nvarchar(20) NULL, + auth_id nvarchar(255) NOT NULL, + source nvarchar(255) NOT NULL, + open_id nvarchar(255) NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) DEFAULT ('') NULL, + email nvarchar(255) DEFAULT ('') NULL, + avatar nvarchar(500) DEFAULT ('') NULL, + access_token nvarchar(255) NOT NULL, + expire_in bigint NULL, + refresh_token nvarchar(255) NULL, + access_code nvarchar(255) NULL, + union_id nvarchar(255) NULL, + scope nvarchar(255) NULL, + token_type nvarchar(255) NULL, + id_token nvarchar(255) NULL, + mac_algorithm nvarchar(255) NULL, + mac_key nvarchar(255) NULL, + code nvarchar(255) NULL, + oauth_token nvarchar(255) NULL, + oauth_token_secret nvarchar(255) NULL, + create_dept bigint, + create_by bigint, + create_time datetime2(7), + update_by bigint, + update_time datetime2(7), + del_flag nchar DEFAULT ('0') NULL, + CONSTRAINT PK__sys_social__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台+平台唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'auth_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户来源' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'source' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台编号唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'open_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌的有效期,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'expire_in' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'刷新令牌,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'refresh_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的 unionid' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'union_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'授予的权限,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'个别平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'token_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id token,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_algorithm' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权code,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token_secret' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 2代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_time' +GO + + +CREATE TABLE sys_client +( + id bigint NOT NULL, + client_id nvarchar(64) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + client_secret nvarchar(255) DEFAULT '' NULL, + grant_type nvarchar(255) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + active_timeout int DEFAULT ((1800)) NULL, + timeout int DEFAULT ((604800)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL + CONSTRAINT PK__sys_client___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty +'MS_Description', N'客户端id' , +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'client_id' +GO +EXEC sp_addextendedproperty +'MS_Description', N'客户端key', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'client_key' +GO +EXEC sp_addextendedproperty +'MS_Description', N'客户端秘钥', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'client_secret' +GO +EXEC sp_addextendedproperty +'MS_Description', N'授权类型', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'grant_type' +GO +EXEC sp_addextendedproperty +'MS_Description', N'设备类型', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'device_type' +GO +EXEC sp_addextendedproperty +'MS_Description', N'token活跃超时时间', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'active_timeout' +GO +EXEC sp_addextendedproperty +'MS_Description', N'token固定超时', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'timeout' +GO +EXEC sp_addextendedproperty +'MS_Description', N'状态(0正常 1停用)', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'status' +GO +EXEC sp_addextendedproperty +'MS_Description', N'删除标志(0代表存在 2代表删除)', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty +'MS_Description', N'创建部门' , +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty +'MS_Description', N'系统授权表', +'SCHEMA', N'dbo', +'TABLE', N'sys_client' +GO + +INSERT INTO sys_client VALUES (N'1', N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO +INSERT INTO sys_client VALUES (N'2', N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO + +INSERT sys_dict_type VALUES (11, N'000000', N'授权类型', N'sys_grant_type', N'0', 103, 1, getdate(), NULL, NULL, N'认证授权类型') +GO +INSERT sys_dict_type VALUES (12, N'000000', N'设备类型', N'sys_device_type', N'0', 103, 1, getdate(), NULL, NULL, N'客户端设备类型') +GO + +INSERT sys_dict_data VALUES (30, N'000000', 0, N'密码认证', N'password', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'密码认证'); +GO +INSERT sys_dict_data VALUES (31, N'000000', 0, N'短信认证', N'sms', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'短信认证') +GO +INSERT sys_dict_data VALUES (32, N'000000', 0, N'邮件认证', N'email', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'邮件认证') +GO +INSERT sys_dict_data VALUES (33, N'000000', 0, N'小程序认证', N'xcx', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'小程序认证') +GO +INSERT sys_dict_data VALUES (34, N'000000', 0, N'三方登录认证', N'`social`', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'三方登录认证') +GO +INSERT sys_dict_data VALUES (35, N'000000', 0, N'PC', N'`pc`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'PC') +GO +INSERT sys_dict_data VALUES (36, N'000000', 0, N'安卓', N'`android`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'安卓') +GO +INSERT sys_dict_data VALUES (37, N'000000', 0, N'iOS', N'`ios`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'iOS') +GO +INSERT sys_dict_data VALUES (38, N'000000', 0, N'小程序', N'`xcx`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'小程序') +GO + +-- 二级菜单 +INSERT sys_menu VALUES (123, N'客户端管理', 1, 11, N'client', N'system/client/index', N'', 1, 0, N'C', N'0', N'0', N'system:client:list', N'international', 103, 1, getdate(), NULL, NULL, N'客户端管理菜单') +GO +-- 客户端管理按钮 +INSERT sys_menu VALUES (1061, N'客户端管理查询', 123, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1062, N'客户端管理新增', 123, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1063, N'客户端管理修改', 123, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1064, N'客户端管理删除', 123, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1065, N'客户端管理导出', 123, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO + + +-- 角色菜单权限 +INSERT sys_role_menu VALUES (2, 1061) +GO +INSERT sys_role_menu VALUES (2, 1062) +GO +INSERT sys_role_menu VALUES (2, 1063) +GO +INSERT sys_role_menu VALUES (2, 1064) +GO +INSERT sys_role_menu VALUES (2, 1065) +GO + + +UPDATE sys_dept SET leader = null +GO +ALTER TABLE sys_dept ALTER COLUMN leader bigint NULL +GO diff --git a/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql b/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..2238536 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql @@ -0,0 +1,19 @@ +ALTER TABLE sys_logininfor ADD client_key nvarchar(32) DEFAULT '' NULL +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'client_key' +GO + +ALTER TABLE sys_logininfor ADD device_type nvarchar(32) DEFAULT '' NULL +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'设备类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'device_type' +GO diff --git a/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql b/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..9133772 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql @@ -0,0 +1,10 @@ +DELETE FROM sys_menu WHERE menu_id IN (1604, 1605); +GO +INSERT sys_menu VALUES (1620, N'配置列表', 118, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:list', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1621, N'配置添加', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1622, N'配置编辑', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1623, N'配置删除', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO diff --git a/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql b/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..18daca4 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql @@ -0,0 +1,29 @@ +ALTER TABLE sys_dept ADD dept_category nvarchar(100) DEFAULT NULL +EXEC sp_addextendedproperty + 'MS_Description', N'部门类别编码', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_category' +GO +ALTER TABLE sys_post ADD dept_id bigint NOT NULL +GO +ALTER TABLE sys_post ADD post_category nvarchar(100) DEFAULT NULL +GO +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'dept_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'岗位类别编码', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_category' +GO +UPDATE sys_post SET dept_id = 100 +GO +UPDATE sys_post SET dept_id = 103 where post_id = 1 +GO +UPDATE sys_menu SET menu_name = N'SnailJob控制台', path = N'snailjob', component = N'monitor/snailjob/index', perms = N'monitor:snailjob:list', remark = N'SnailJob控制台菜单' WHERE menu_id = 120 +GO diff --git a/script/sql/update/update_5.0-5.1.sql b/script/sql/update/update_5.0-5.1.sql new file mode 100644 index 0000000..871bda3 --- /dev/null +++ b/script/sql/update/update_5.0-5.1.sql @@ -0,0 +1,101 @@ +ALTER TABLE gen_table ADD COLUMN data_name varchar(200) NULL DEFAULT '' COMMENT '数据源名称' AFTER table_id; + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120; + +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +drop table if exists sys_social; +create table sys_social +( + id bigint not null comment '主键', + user_id bigint not null comment '用户ID', + tenant_id varchar(20) default null comment '租户id', + auth_id varchar(255) not null comment '平台+平台唯一id', + source varchar(255) not null comment '用户来源', + open_id varchar(255) default null comment '平台编号唯一id', + user_name varchar(30) not null comment '登录账号', + nick_name varchar(30) default '' comment '用户昵称', + email varchar(255) default '' comment '用户邮箱', + avatar varchar(500) default '' comment '头像地址', + access_token varchar(255) not null comment '用户的授权令牌', + expire_in int default null comment '用户的授权令牌的有效期,部分平台可能没有', + refresh_token varchar(255) default null comment '刷新令牌,部分平台可能没有', + access_code varchar(255) default null comment '平台的授权信息,部分平台可能没有', + union_id varchar(255) default null comment '用户的 unionid', + scope varchar(255) default null comment '授予的权限,部分平台可能没有', + token_type varchar(255) default null comment '个别平台的授权信息,部分平台可能没有', + id_token varchar(255) default null comment 'id token,部分平台可能没有', + mac_algorithm varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + mac_key varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + code varchar(255) default null comment '用户的授权code,部分平台可能没有', + oauth_token varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + oauth_token_secret varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (id) +) engine=innodb comment = '社会化关系表'; + + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +drop table if exists sys_client; +create table sys_client ( + id bigint(20) not null comment 'id', + client_id varchar(64) default null comment '客户端id', + client_key varchar(32) default null comment '客户端key', + client_secret varchar(255) default null comment '客户端秘钥', + grant_type varchar(255) default null comment '授权类型', + device_type varchar(32) default null comment '设备类型', + active_timeout int(11) default 1800 comment 'token活跃超时时间', + timeout int(11) default 604800 comment 'token固定超时', + status char(1) default '0' comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + primary key (id) +) engine=innodb comment='系统授权表'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); + +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, sysdate(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, sysdate(), null, null, '客户端设备类型'); + +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '小程序'); + +-- 二级菜单 +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate(), null, null, '客户端管理菜单'); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 角色菜单权限 +insert into sys_role_menu values ('2', '1061'); +insert into sys_role_menu values ('2', '1062'); +insert into sys_role_menu values ('2', '1063'); +insert into sys_role_menu values ('2', '1064'); +insert into sys_role_menu values ('2', '1065'); + + +update sys_dept set leader = null; +alter table sys_dept modify column leader bigint null default null comment '负责人' after order_num; diff --git a/script/sql/update/update_5.1.0-5.1.1.sql b/script/sql/update/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..1dea49b --- /dev/null +++ b/script/sql/update/update_5.1.0-5.1.1.sql @@ -0,0 +1,3 @@ +ALTER TABLE sys_logininfor + ADD COLUMN client_key VARCHAR(32) NULL DEFAULT NULL COMMENT '客户端' AFTER `user_name`, + ADD COLUMN device_type VARCHAR(32) NULL DEFAULT NULL COMMENT '设备类型' AFTER `client_key`; diff --git a/script/sql/update/update_5.1.1-5.1.2.sql b/script/sql/update/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..314743f --- /dev/null +++ b/script/sql/update/update_5.1.1-5.1.2.sql @@ -0,0 +1,5 @@ +delete from sys_menu where menu_id in (1604, 1605); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, sysdate(), null, null, ''); diff --git a/script/sql/update/update_5.1.2-5.2.0.sql b/script/sql/update/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..33384e7 --- /dev/null +++ b/script/sql/update/update_5.1.2-5.2.0.sql @@ -0,0 +1,5 @@ +ALTER TABLE sys_dept ADD dept_category VARCHAR(100) DEFAULT NULL COMMENT '部门类别编码'; +ALTER TABLE sys_post ADD dept_id BIGINT(20) NOT NULL COMMENT '部门id', ADD post_category VARCHAR(100) DEFAULT NULL COMMENT '岗位类别编码'; +UPDATE sys_post SET dept_id = 100; +UPDATE sys_post SET dept_id = 103 where post_id = 1; +UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120; diff --git a/script/sql/xinnengyuan.sql b/script/sql/xinnengyuan.sql new file mode 100644 index 0000000..081e499 --- /dev/null +++ b/script/sql/xinnengyuan.sql @@ -0,0 +1,1592 @@ +use xinnengyuandev; + +drop table if exists bus_project; +create table `bus_project` +( + `id` bigint not null auto_increment, + `project_name` varchar(64) null comment '项目名称', + `short_name` varchar(64) null comment '项目简称', + `p_id` bigint null comment '父项目id', + `status` char(1) default '0' null comment '状态(0正常 1停用)', + `pic_url` varchar(255) null comment '项目图片', + `lng` varchar(20) null comment '经度', + `lat` varchar(20) null comment '纬度', + `remark` varchar(500) null comment '备注', + `type` varchar(20) null comment '项目类型', + `is_type` char(1) null comment '项目类型(1光伏 2风电)', + `project_site` varchar(255) null comment '项目地址', + `principal` varchar(50) null comment '负责人', + `principal_phone` varchar(50) null comment '负责人电话', + `actual` varchar(64) null comment '实际容量', + `plan` varchar(64) null comment '计划容量', + `on_stream_time` varchar(64) null comment '开工时间', + `punch_range` varchar(30) default '09:00,18:00' not null comment '打卡范围(09:00,18:00)', + `design_total` int default 0 not null comment '设计总量', + `security_agreement` varchar(255) null comment '安全协议书', + `sort` bigint default 0 not null comment '排序字段', + `show_hidden` char(1) default '0' not null comment '显示隐藏(0显示 1隐藏)', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '项目表' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS bus_user_project_relevancy; +CREATE TABLE `bus_user_project_relevancy` +( + `id` bigint not null AUTO_INCREMENT comment '主键ID', + `user_id` bigint not null comment '用户ID', + `project_id` bigint not null comment '项目ID', + `create_by` varchar(50) null comment '创建人', + `update_by` varchar(50) null comment '更新人', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '系统用户与项目关联表' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS mat_company; +CREATE TABLE `mat_company` +( + `id` bigint not null auto_increment, + `company_name` varchar(64) null comment '公司名称', + `project_id` bigint null comment '项目id', + `status` char(1) default '0' null comment '帐号状态(0正常 1停用)', + `remark` varchar(255) null comment '备注', + `qualification` varchar(255) null comment '资质情况', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '公司表' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS mat_materials; +CREATE TABLE `mat_materials` +( + `id` bigint not null auto_increment, + `materials_name` varchar(64) null comment '材料名称', + `company_id` bigint null comment '公司id', + `project_id` bigint null comment '项目id', + `type_specification_name` varchar(64) null comment '规格型号名称', + `file_url` varchar(1024) null comment '文件地址列表(字典materials_file_type)', + `use_part` varchar(64) null comment '使用部位', + `weight_id` varchar(64) null comment '计量单位', + `remark` varchar(255) null comment '备注', + `quantity_count` varchar(64) null comment '预计材料数量', + `status` char(1) default '0' null comment '状态(0正常 1停用)', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '材料名称表' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS mat_materials_inventory; +CREATE TABLE `mat_materials_inventory` +( + `id` bigint not null auto_increment comment '主键id', + `materials_id` bigint not null comment '材料id', + `project_id` bigint null comment '项目id', + `out_put` char(1) null comment '出入库状态', + `number` int default 0 null comment '出/入库的数量', + `out_put_time` datetime null comment '出/入库操作时间', + `residue` int default 0 null comment '剩余库存数量(记录最后一次操作留下的库存数)', + `operator` varchar(255) null comment '操作人(入库人、领料人)', + `path` varchar(512) null comment '材料出入证明', + `disposition` varchar(255) null comment '处理方式', + `recipient` varchar(255) null comment '交接单位(班组)', + `shipper` varchar(255) null comment '领用人', + `remark` varchar(255) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目ID' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '材料出/入库表' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS `bus_contractor`; +CREATE TABLE `bus_contractor` +( + `id` bigint not null auto_increment comment '主键id', + `name` varchar(50) null comment '公司名称', + `principal` varchar(20) null comment '负责人', + `principal_phone` varchar(20) null comment '负责人联系电话', + `custodian` varchar(20) null comment '管理人', + `custodian_phone` varchar(20) null comment '管理人联系电话', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建人', + `update_by` varchar(64) null comment '更新人', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '分包单位' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS sub_construction_user; +CREATE TABLE `bus_construction_user` +( + `id` bigint not null auto_increment, + `pace_photo` longtext null comment '人脸照', + `user_name` varchar(32) null comment '人员姓名', + `project_id` bigint null comment '项目id', + `contractor_id` bigint null comment '分包公司id', + `team_id` bigint null comment '班组id', + `status` tinyint null comment '状态(0在职 1离职)', + `is_pinch` tinyint null comment '是否代打', + `phone` varchar(24) null comment '联系电话', + `sex` tinyint default 0 not null comment '性别(0:保密 1:男 2女)', + `nation` varchar(20) null comment '民族', + `sfz_number` varchar(50) null comment '身份证号码', + `sfz_start` varchar(20) null comment '身份证有效开始期', + `sfz_end` varchar(20) null comment '身份证有效结束期', + `sfz_site` varchar(100) null comment '身份证地址', + `sfz_birth` varchar(255) null comment '身份证出生日期', + `native_place` varchar(20) null comment '籍贯', + `yhk_number` varchar(50) null comment '银行卡号', + `yhk_opening_bank` varchar(50) null comment '开户行', + `yhk_cardholder` varchar(255) null comment '持卡人', + `type_of_work` char(1) null comment '工种(字典type_of_work)', + `clock` char(1) default '1' not null comment '打卡(0启用打卡 1禁止打卡)', + `entry_date` varchar(255) null comment '入场时间', + `leave_date` varchar(255) null comment '离场时间', + `salary` decimal(10, 2) default 0.00 null comment '薪水', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_subcontractor_id` (`contractor_id` ASC) USING BTREE comment '劳务公司id', + INDEX `idx_phone` (`phone` ASC) USING BTREE comment '电话' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '施工人员表' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS `bus_project_team`; +CREATE TABLE `bus_project_team` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint null comment '项目id', + `team_name` varchar(50) null comment '班组名称', + `is_clock_in` char(1) default '1' not null comment '范围内打卡(0范围内打卡 1任何地点打卡)默认为1', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + collate = utf8mb4_general_ci comment = '项目班组' + ROW_FORMAT = DYNAMIC; + +DROP TABLE IF EXISTS `bus_project_team_member`; +CREATE TABLE `bus_project_team_member` +( + `id` bigint not null auto_increment comment '主键id', + `team_id` bigint null comment '班组id', + `project_id` bigint null comment '项目id', + `member_id` bigint null comment '施工人员id', + `post_id` char(1) default '0' null comment '岗位(默认为0普通员工,1组长)', + `remark` varchar(512) null comment '备注', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_member_id` (`member_id` ASC) USING BTREE comment '施工人员id' +) comment = '项目班组下的成员' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS eqp_machinery; +CREATE TABLE `bus_machinery` +( + `id` bigint not null auto_increment comment '主键id', + `machinery_name` varchar(16) null comment '机械名称', + `machinery_number` varchar(64) null comment '机械型号', + `project_id` bigint null comment '项目id', + `number` int null comment '数量', + `principal` varchar(20) null comment '负责人', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE +) comment = '机械表' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS eqp_machinery_detail; +CREATE TABLE `bus_machinery_detail` +( + `id` bigint not null auto_increment comment '主键id', + `checkout_number` varchar(64) null comment '检验证编号', + `checkout_unit` varchar(64) null comment '检验单位', + `checkout_date` varchar(64) null comment '检定日期/有效期', + `status` char(1) default '0' null comment '施工类型状态(0正常 1停用)', + `type` char(1) default '0' null null comment '0入场 1出场', + `entry_time` datetime null comment '入场时间', + `remark` varchar(512) null comment '备注', + `picture` varchar(512) null comment '图片(英文逗号分隔)', + `machinery_id` bigint null comment '机械主键id', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_machinery_id` (`machinery_id` ASC) USING BTREE comment '机械主键id' +) comment = '机械详情' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_team_meeting; +CREATE TABLE `bus_team_meeting` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `team_id` bigint not null comment '班组id', + `contractor_id` bigint null comment '分包公司id', + `meeting_date` datetime null comment '开会时间', + `compere_id` bigint null comment '宣讲人', + `participant_id` text null comment '参与人id(多个用,号隔开)', + `content` text null comment '班会内容', + `picture` text null comment '班会图片(多个用,号隔开)', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组ID' +) comment = '站班会' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_safety_inspection; +CREATE TABLE `bus_safety_inspection` +( + `id` bigint not null auto_increment comment '主键ID', + `pid` bigint null comment '父id(默认为0)', + `project_id` bigint not null comment '项目ID', + `check_type` char(1) null comment '检查类型', + `violation_type` char(1) null comment '违章类型', + `inspection_result` varchar(300) null comment '巡检结果', + `team_id` bigint null comment '整改班组id', + `corrector_id` bigint null comment '整改人(班组长)id', + `is_reply` char(1) null comment '是否回复(1回复 2不回复)', + `reply_date` varchar(20) null comment '回复日期', + `status` char(1) null comment '工单状态(1通知 2整改 3复查)', + `hidden_danger` varchar(1024) null comment '问题隐患', + `measure` varchar(1024) null comment '整改措施', + `review` varchar(1024) null comment '复查情况', + `review_type` char(1) null comment '复查状态(1通过 2未通过)', + `check_time` datetime null comment '检查时间', + `rectification_time` datetime null comment '整改时间', + `review_time` datetime null comment '复查时间', + `check_file` bigint null comment '检查附件', + `rectification_file` bigint null comment '整改附件', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE +) comment = '安全巡检工单' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_safety_log; +CREATE TABLE `bus_safety_log` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `date_of_occurrence` varchar(16) null comment '发生日期', + `air_temperature_max` double null comment '最高气温', + `air_temperature_min` double null comment '最低气温', + `weather` char(1) null comment '气候', + `progress` varchar(1024) null comment '进展', + `job_content` varchar(1024) null comment '作业内容', + `disclose_condition` varchar(1024) null comment '交底情况', + `activity_condition` varchar(1024) null comment '活动情况', + `examine_condition` varchar(1024) null comment '检查情况', + `implement_condition` varchar(1024) null comment '实施情况', + `safety_inspection_condition` varchar(1024) null comment '安全检查情况', + `stoppage_or_overtime` varchar(1024) null comment '停工或加班情况', + `other_condition` varchar(1024) null comment '其他情况', + `file_id` varchar(1024) null comment '文件id列表', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) comment = '安全日志' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_safety_weekly_report; +CREATE TABLE `bus_safety_weekly_report` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `week` varchar(50) null comment '周期', + `scope` varchar(20) null comment '周期范围', + `scope_end` varchar(20) null comment '周期范围结束', + `path` varchar(256) null comment '文件位置', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) comment = '安全周报' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_questions_config; +CREATE TABLE `hse_questions_config` +( + `id` bigint not null auto_increment comment '主键id', + `single_choice` int default 0 not null comment '单选题(单位/道)', + `single_score` float not null comment '单选分数', + `multiple_choice` int default 0 not null comment '多选题(单位/道)', + `multiple_score` float not null comment '多选分数', + `estimate` int default 0 not null comment '判断题(单位/道)', + `estimate_score` float not null comment '判断分数', + `full_mark` float not null comment '满分', + `pass_score` float not null comment '及格线', + `answer_time` int not null comment '答题最大时间(单位/分钟)', + PRIMARY KEY (`id`) USING BTREE +) comment = '题库配置' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_question_bank; +CREATE TABLE `hse_question_bank` +( + `id` bigint not null auto_increment comment '主键id', + `category_type` char(1) null comment '题目类别', + `question_type` char(1) null comment '题目类型', + `question_content` varchar(255) null comment '题目内容', + `options` text null comment '选项(以JSON数组形式存储)', + `correct_answer` varchar(255) null comment '正确答案', + `wx_or_pc` varchar(20) null comment '创建人设备类型', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE +) comment = '题库' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_question_user_answer; +CREATE TABLE `hse_question_user_answer` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint null comment '项目id', + `user_id` bigint null comment '用户id', + `bank_id` bigint null comment '题库id列表', + `answer` varchar(10) null comment '答案列表', + `score` float null comment '得分', + `take_time` bigint null comment '用时时间(时间戳/秒)', + `pass` varchar(10) null comment '及格线/总分(格式:60,100)', + `file` varchar(255) null comment '文件地址', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE +) comment = '用户试卷存储' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_attendance`; +CREATE TABLE `bus_attendance` +( + `id` bigint not null auto_increment comment '主键id', + `user_id` bigint null comment '人员id', + `user_name` varchar(32) null comment '人员姓名', + `face_pic` varchar(512) null comment '人脸照', + `project_id` bigint null comment '项目id', + `clock_time` datetime null comment '打卡时间', + `clock_date` date null comment '打卡日期', + `clock_status` varchar(20) null comment '打卡状态(1正常,2迟到,3早退,4缺勤,5补卡)', + `pinch_user_id` bigint null comment '代打人员id', + `clock_record` varchar(500) null comment '多次打卡时间记录', + `commuter` char(1) null comment '上下班(1上班,2下班)', + `punch_range` varchar(64) null comment '打卡范围', + `daily_wage` decimal(10, 2) null comment '日薪', + `lng` varchar(255) null comment '经度', + `lat` varchar(255) null comment '纬度', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '人员id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_clock_date` (`clock_date` ASC) USING BTREE comment '打卡日期' +) comment = '考勤表' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_work_wage`; +CREATE TABLE `bus_work_wage` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint null comment '项目id', + `work_type` varchar(50) null comment '工种', + `is_special_type` char(1) null comment '是否是特种兵(1是 2否)', + `wage_calculation_type` char(1) null comment '工资计算方式(1计时 2计件)', + `wage` decimal(10, 2) null comment '工资标准', + `wage_measure_unit` varchar(64) null comment '工资计量单位', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_work_type` (`work_type` ASC) USING BTREE comment '工种' +) comment = '工种薪水' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_construction_blacklist`; +CREATE TABLE `bus_construction_blacklist` +( + `id` bigint not null auto_increment comment '主键id', + `user_id` bigint not null comment '用户id', + `user_name` varchar(50) not null comment '名字', + `sfz_number` varchar(50) not null comment '身份证号码', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id' +) comment = '黑名单' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS sub_construction_user_file; +CREATE TABLE `bus_construction_user_file` +( + `id` bigint not null auto_increment comment '主键id', + `user_id` bigint not null comment '用户id', + `file_type` char(2) null comment '图片类型', + `file_name` varchar(255) null comment '文件名称', + `path` varchar(1024) null comment '图片路径', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `remark` varchar(512) null comment '备注', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id' +) comment = '施工人员文件存储' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_construction_user_exit`; +CREATE TABLE `bus_construction_user_exit` +( + `id` bigint not null auto_increment comment '主键id', + `sfz_number` varchar(32) null comment '身份证号码', + `user_id` bigint not null comment '用户id', + `project_id` bigint not null comment '项目id', + `team_id` bigint not null comment '班组id', + `entry_date` varchar(64) null comment '入场时间', + `leave_date` varchar(64) null comment '退场时间', + `path` varchar(1024) null comment '退场文件', + `remark` varchar(512) null comment '备注', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id' +) comment = '施工人员入场退场记录信息' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_reissue_card`; +CREATE TABLE `bus_reissue_card` +( + `id` bigint not null auto_increment comment '主键id', + `user_id` bigint not null comment '申请人id', + `user_name` varchar(50) not null comment '申请人名字', + `user_explain` varchar(512) null comment '申请补卡说明', + `user_time` datetime default CURRENT_TIMESTAMP null comment '补卡申请时间', + `ganger_id` bigint null comment '班组长', + `ganger_name` varchar(50) null comment '班组长名字', + `ganger_opinion` char(1) default '1' not null comment '班组长意见(1未读 2同意 3拒绝)', + `ganger_explain` varchar(512) null comment '班组长说明', + `ganger_time` datetime null comment '班组长操作时间', + `manager_opinion` char(1) default '1' not null comment '管理员意见(1未读 2同意 3拒绝)', + `manager_explain` varchar(512) null comment '管理员说明', + `manager_time` datetime null comment '管理员操作时间', + `project_id` bigint not null comment '项目id', + `team_id` bigint null comment '班组id', + `reissue_card_type` char(1) not null comment '补卡类型(1上班 2下班)', + `attendance_id` bigint not null comment '考勤表主键id', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id' +) comment = '施工人员补卡申请' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_leave`; +CREATE TABLE `bus_leave` +( + `id` bigint not null auto_increment comment '主键id', + `user_id` bigint not null comment '申请人id', + `user_name` varchar(50) not null comment '申请人名字', + `user_explain` varchar(512) null comment '申请请假说明', + `user_time` datetime default CURRENT_TIMESTAMP null comment '请假申请时间', + `leave_type` char(1) not null comment '请假类型(1事假 2病假)', + `start_time` datetime not null comment '请假开始时间', + `end_time` datetime not null comment '请假结束时间', + `ganger_id` bigint null comment '班组长', + `ganger_name` varchar(50) null comment '班组长名字', + `ganger_opinion` char(1) default '1' not null comment '班组长意见(1未读 2同意 3拒绝)', + `ganger_explain` varchar(512) null comment '班组长说明', + `ganger_time` datetime null comment '班组长操作时间', + `manager_opinion` char(1) default '1' not null comment '管理员意见(1未读 2同意 3拒绝)', + `manager_explain` varchar(512) null comment '管理员说明', + `manager_time` datetime null comment '管理员操作时间', + `project_id` bigint not null comment '项目id', + `team_id` bigint null comment '班组id', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id' +) comment = '施工人员请假申请' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_worker_daily_report`; +CREATE TABLE `bus_worker_daily_report` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `team_id` bigint null comment '班组id', + `user_id` bigint not null comment '申请人id', + `user_name` varchar(50) not null comment '申请人名字', + `today_completed_work` text null comment '今日完成工作', + `unfinished_work` text null comment '未完成工作', + `tomorrow_work` text null comment '明日工作', + `coordination_help` text null comment '需协调与帮助', + `file` varchar(1024) null comment '附件', + `is_review` tinyint(4) default 1 not null comment '是否审核(1审核 2不审核)', + `reviewer_id` bigint null comment '审核人id', + `reviewer_name` varchar(50) null comment '审核人名字', + `review_opinion` char(1) default '1' not null comment '审核人意见(1未读 2同意 3拒绝)', + `review_explain` varchar(512) null comment '审核人说明', + `review_time` datetime null comment '审核人操作时间', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id' +) comment = '施工人员日报' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_daily_piece_item`; +CREATE TABLE `bus_daily_piece_item` +( + `id` bigint not null auto_increment comment '主键id', + `report_id` bigint not null comment '日报id', + `piece_type` varchar(50) not null comment '计件类型', + `piece_count` int not null comment '计件数量', + `piece_unit` varchar(20) null comment '计件单位', + `remark` varchar(512) null comment '备注', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_report_id` (`report_id` ASC) USING BTREE comment '日报id' +) comment = '施工人员日报计件信息' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_document_safety_meeting; +CREATE TABLE `hse_document_safety_meeting` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint null comment '项目id', + `pid` bigint default 0 null comment '父级(0代表顶级)', + `file_name` varchar(255) null comment '文件名称', + `file_path` varchar(512) null comment '文件路径', + `file_type` char(1) not null comment '文件类型(1文件-2文件夹-3图片)', + `file_suffix` varchar(20) null comment '文件后缀', + `file_status` char(1) default '0' null comment '状态(0正常 1删除)', + `original_name` varchar(255) null comment '原文件名', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_pid` (`pid` ASC) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE +) comment = '安全会议纪要' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS hse_questions_category; +CREATE TABLE `hse_questions_category` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `category_name` varchar(255) not null comment '题库类别', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE +) comment = '题库类别' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS qlt_quality_inspection; +CREATE TABLE `qlt_quality_inspection` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint null comment '项目id', + `inspection_type` char(1) null comment '巡检类型', + `inspection_headline` varchar(64) null comment '巡检标题', + `inspection_result` varchar(300) null comment '巡检结果', + `inspection_status` char(1) null comment '工单状态(1通知 2整改 3验证)', + `inspection_file` varchar(1024) null comment '巡检附件', + `team_id` bigint null comment '班组id', + `corrector` varchar(128) null comment '整改人(班组长)', + `is_reply` char(1) null comment '是否回复(1回复 2不回复)', + `reply_period_date` date null comment '回复期限日期', + `rectification_result` varchar(300) null comment '整改反馈', + `rectification_time` datetime null comment '整改时间', + `rectification_file` varchar(1024) null comment '整改附件', + `verification_result` varchar(300) null comment '验证结果', + `verification_type` char(1) null comment '验证状态(1通过 2未通过)', + `verification_time` datetime null comment '验证时间', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `project_id` (`project_id` ASC) USING BTREE, + INDEX `team_id` (`team_id` ASC) USING BTREE +) comment = '质量-检查工单' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS qlt_quality_construction_log; +CREATE TABLE `qlt_quality_construction_log` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint null comment '项目id', + `happen_date` date null comment '发生日期', + `production_status` varchar(300) null comment '生产情况', + `technology_quality` varchar(300) null comment '技术质量安全工作', + `file` varchar(1024) null comment '附件', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE +) comment = '质量-施工日志' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `app_user`; +CREATE TABLE `app_user` +( + `id` bigint not null auto_increment comment 'app用户id', + `user_account` varchar(30) not null comment '用户账号', + `user_type` varchar(10) null comment '用户类型', + `phone` varchar(11) null comment '手机号码', + `password` varchar(100) null comment '密码', + `status` char(1) null default '0' comment '帐号状态(0正常 1停用)', + `login_ip` varchar(128) null comment '最后登录IP', + `login_date` datetime null comment '最后登录时间', + `remark` varchar(512) null comment '备注', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `idx_user_account` (`user_account` ASC) USING BTREE, + UNIQUE INDEX `idx_phone` (`phone` ASC) USING BTREE +) comment = 'app用户表' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `user_relevancy`; +CREATE TABLE `user_relevancy` +( + `id` bigint not null auto_increment comment '主键', + `app_id` bigint null comment 'app用户id', + `web_id` bigint null comment 'web用户id', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_app_id` (`app_id` ASC) USING BTREE, + INDEX `idx_web_id` (`web_id` ASC) USING BTREE +) comment = '用户关联表' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_matrix`; +CREATE TABLE `fac_matrix` +( + `id` bigint not null auto_increment comment '主键', + `project_id` bigint not null comment '项目id', + `matrix_name` varchar(100) not null comment '方阵名称', + `positions` text null comment '方阵位置', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) comment = '设施-方阵' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_photovoltaic_panel`; +CREATE TABLE `fac_photovoltaic_panel` +( + `id` bigint not null auto_increment comment '主键', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `name` varchar(100) not null comment '光伏板名称', + `positions` text null comment '光伏板位置', + `status` char(1) default 0 not null comment '完成状态(0未开始 1进行中 2完成)', + `finish_type` char(1) null comment '完成类型(1手动填报 2AI填报)', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE, + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE +) comment = '设施-光伏板' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_photovoltaic_panel_point`; +CREATE TABLE `fac_photovoltaic_panel_point` +( + `id` bigint not null auto_increment comment '主键', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `name` varchar(100) not null comment '光伏板桩点名称', + `positions` text null comment '光伏板桩点位置', + `status` char(1) default 0 not null comment '完成状态(0未开始 1进行中 2完成)', + `finish_type` char(1) null comment '完成类型(1手动填报 2AI填报)', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE, + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE +) comment = '设施-光伏板桩点' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_photovoltaic_panel_column`; +CREATE TABLE `fac_photovoltaic_panel_column` +( + `id` bigint not null auto_increment comment '主键', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `name` varchar(100) not null comment '光伏板立柱名称', + `positions` text null comment '光伏板立柱位置', + `status` char(1) default 0 not null comment '完成状态(0未开始 1进行中 2完成)', + `finish_type` char(1) null comment '完成类型(1手动填报 2AI填报)', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE, + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE +) comment = '设施-光伏板立柱' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_photovoltaic_panel_support`; +CREATE TABLE `fac_photovoltaic_panel_support` +( + `id` bigint not null auto_increment comment '主键', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `name` varchar(100) not null comment '光伏板支架名称', + `positions` text null comment '光伏板支架位置', + `status` char(1) default 0 not null comment '完成状态(0未开始 1进行中 2完成)', + `finish_type` char(1) null comment '完成类型(1手动填报 2AI填报)', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE, + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE +) comment = '设施-光伏板支架' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_inverter`; +CREATE TABLE `fac_inverter` +( + `id` bigint not null auto_increment comment '主键', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `name` varchar(100) not null comment '逆变器名称', + `positions` text null comment '逆变器位置', + `status` char(1) default 0 not null comment '完成状态(0未开始 1进行中 2完成)', + `finish_type` char(1) null comment '完成类型(1手动填报 2AI填报)', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE, + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE +) comment = '设施-逆变器' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_box_transformer`; +CREATE TABLE `fac_box_transformer` +( + `id` bigint not null auto_increment comment '主键', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `name` varchar(100) not null comment '箱变名称', + `positions` text null comment '箱变位置', + `status` char(1) default 0 not null comment '完成状态(0未开始 1进行中 2完成)', + `finish_type` char(1) null comment '完成类型(1手动填报 2AI填报)', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE, + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE +) comment = '设施-箱变' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_project_file`; +CREATE TABLE `bus_project_file` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `file_type` char(2) null comment '文件类型', + `file_name` varchar(255) null comment '文件名称', + `file_path` varchar(1024) null comment '文件路径', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `remark` varchar(512) null comment '备注', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) comment = '项目文件存储' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `bus_project_news`; +CREATE TABLE `bus_project_news` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `title` varchar(64) null comment '标题', + `content` longtext null comment '内容', + `file` varchar(512) null comment '附件', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) comment = '项目新闻' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `pgs_progress_category_template`; +CREATE TABLE `pgs_progress_category_template` +( + `id` bigint not null auto_increment comment '主键id', + `pid` bigint default '0' not null comment '父类别id', + `name` varchar(64) not null comment '类别名称', + `unit_type` char(1) not null comment '计量方式(0无 1数量 2百分比)', + `project_id` bigint default '0' not null comment '项目id(0表示共用)', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_pid` (`pid` ASC) USING BTREE comment '父类别id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) comment ='进度类别模版' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `pgs_progress_category`; +CREATE TABLE `pgs_progress_category` +( + `id` bigint not null auto_increment comment '主键id', + `pid` bigint default '0' not null comment '父类别id', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `name` varchar(64) not null comment '类别名称', + `unit_type` char(1) not null comment '计量方式(0无 1数量 2百分比)', + `total` decimal(10, 2) null comment '总数量/百分比', + `completed` decimal(10, 2) null comment '已完成数量/百分比', + `plan_total` decimal(10, 2) null comment '计划总数量/百分比', + `is_delay` char(1) default '0' not null comment '是否超期(0否 1是)', + `status` char(1) default '0' not null comment '完成状态(0未开始 1进行中 2已完成)', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_pid` (`pid` ASC) USING BTREE comment '父类别id', + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE comment '方阵id', + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id' +) comment ='进度类别' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `fac_percentage_facility`; +CREATE TABLE `fac_percentage_facility` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `progress_category_id` bigint null comment '进度类型id', + `progress_category_name` varchar(64) null comment '进度类别名称', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE comment '方阵id', + INDEX `idx_progress_category_id` (`progress_category_id` ASC) USING BTREE comment '进度类别id' +) comment ='设施-百分比设施' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `pgs_progress_plan`; +CREATE TABLE `pgs_progress_plan` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `matrix_id` bigint not null comment '方阵id', + `matrix_name` varchar(64) null comment '方阵名称', + `progress_category_id` bigint null comment '进度类型id', + `progress_category_name` varchar(64) null comment '进度类别名称', + `start_date` date null comment '计划开始时间', + `end_date` date null comment '计划结束时间', + `plan_number` decimal(10) null comment '计划数量/百分比', + `finished_number` decimal(10) null comment '完成数量/百分比', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE comment '方阵id', + INDEX `idx_progress_category_id` (`progress_category_id` ASC) USING BTREE comment '进度类别id' +) comment ='进度计划' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `pgs_progress_plan_detail`; +CREATE TABLE `pgs_progress_plan_detail` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `progress_plan_id` bigint not null comment '进度计划id', + `progress_category_id` bigint null comment '进度类型id', + `date` date null comment '计划时间', + `plan_number` decimal(10) null comment '计划数量/百分比', + `finished_number` decimal(10) null comment '完成数量/百分比', + `ai_fill` decimal(10) null comment 'AI填入数量', + `finished_detail` text null comment '完成设施详情', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id', + INDEX `idx_progress_plan_id` (`progress_plan_id` ASC) USING BTREE comment '进度计划id', + INDEX `idx_date` (`date` ASC) USING BTREE comment '计划时间' +) comment ='进度计划详情' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `oth_ys7_device`; +CREATE TABLE `oth_ys7_device` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint default 0 not null comment '项目id', + `device_serial` varchar(255) null comment '设备序列号', + `device_name` varchar(255) null comment '设备名称', + `device_type` varchar(255) null comment '设备型号', + `status` tinyint(4) null comment '设备在线状态(0离线 1在线)', + `defence` bigint null comment '布撤防状态', + `device_version` varchar(255) null comment '固件版本号', + `position` varchar(255) null comment '摄像头坐标信息', + `device_create_time` datetime null comment '设备添加时间', + `device_update_time` datetime null comment '设备最后更新时间', + `risk_level` int null comment '设备风险安全等级(0安全 大于0,值越大,风险越高)', + `video_encrypted` tinyint(4) default 0 not null comment '视频加密(0关闭 1开启)', + `remark` varchar(512) null comment '备注', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + unique index `idx_device_serial` (`device_serial` asc) using btree comment '设备序列号' +) comment = '萤石摄像头' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `oth_device_preset`; +CREATE TABLE `oth_device_preset` +( + `id` bigint not null auto_increment comment '主键id', + `device_serial` varchar(255) null comment '设备序列号', + `channel_no` int null comment '通道号', + `preset_index` int null comment '预置点序号', + `preset_name` varchar(255) null comment '预置点', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_device_serial` (`device_serial` asc) using btree comment '设备序列号' +) comment = '摄像头预置位' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `oth_ys7_device_img`; +CREATE TABLE `oth_ys7_device_img` +( + `id` bigint not null auto_increment comment '主键id', + `device_serial` varchar(255) not null comment '设备序列号', + `device_name` varchar(255) null comment '设备名称', + `url` varchar(512) not null comment '图片地址', + `remark` varchar(512) null comment '备注', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_device_serial` (`device_serial` asc) using btree comment '设备序列号' +) comment = '萤石摄像头图片' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `hse_violation_level`; +CREATE TABLE `hse_violation_level` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `violation_level` varchar(64) null comment '违章等级', + `color` varchar(32) null comment '颜色', + `risk_type` char(2) null comment '风险等级', + `violation_type` varchar(255) null comment '违章类型(多个逗号分隔)', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment = '违章等级' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `hse_violation_level_post`; +CREATE TABLE `hse_violation_level_post` +( + `level` bigint not null comment '等级', + `post` bigint not null comment '岗位', + primary key (`level`, `post`) using btree +) comment = '等级与岗位关联' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `hse_recognize_record`; +CREATE TABLE `hse_recognize_record` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint null comment '项目id', + `device_serial` varchar(255) null comment '设备序列号', + `device_name` varchar(255) null comment '设备名称', + `record_category` char(1) null comment '识别类别(1无人机识别 2监控拍摄)', + `violation_type` varchar(255) null comment '违章类型(多个逗号分隔)', + `picture` varchar(512) null comment '图片路径', + `num` int default 0 null comment '违规数量', + `description` varchar(512) null comment '故障描述', + `remark` varchar(512) null comment '备注', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment = '识别记录' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `sys_user_file`; +CREATE TABLE `sys_user_file` +( + `id` bigint not null auto_increment comment '主键id', + `user_id` bigint not null comment '用户id', + `file_id` bigint not null comment '文件id', + primary key (`id`) using btree, + unique index `idx_user_file` (`user_id`, `file_id`) using btree comment '用户id_文件id' +) comment = '用户文件关联' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS sub_subcontract; +CREATE TABLE `bus_subcontract` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `contractor_id` bigint not null comment '分包方id', + `contract_file_id` bigint not null comment '合同文件id', + `contract_number` varchar(255) null comment '合同编号', + `contract_name` varchar(255) null comment '合同名称', + `contract_type` char(1) not null comment '合同类型', + `contract_amount` decimal(12, 2) null comment '合同金额', + `contract_time` datetime null comment '合同时间', + `remark` varchar(512) null comment '备注', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id' +) comment = '分包合同' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `hse_knowledge_document`; +CREATE TABLE `hse_knowledge_document` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `pid` bigint default 0 not null comment '父级(0代表顶级)', + `file_name` varchar(255) not null comment '文件名称', + `file_path` varchar(512) null comment '文件路径', + `file_url` varchar(512) null comment '文件访问路径', + `file_type` char(1) not null comment '文件类型(1文件夹 2文件 3图片)', + `file_suffix` varchar(20) null comment '文件后缀', + `file_status` char(1) default '0' not null comment '状态(0正常 1删除)', + `original_name` varchar(255) null comment '原文件名', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment '安全知识库' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `qlt_knowledge_document`; +CREATE TABLE `qlt_knowledge_document` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `pid` bigint default 0 not null comment '父级(0代表顶级)', + `file_name` varchar(255) not null comment '文件名称', + `file_path` varchar(512) null comment '文件路径', + `file_url` varchar(512) null comment '文件访问路径', + `file_type` char(1) not null comment '文件类型(1文件夹 2文件 3图片)', + `file_suffix` varchar(20) null comment '文件后缀', + `file_status` char(1) default '0' not null comment '状态(0正常 1删除)', + `original_name` varchar(255) null comment '原文件名', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment '质量知识库' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS sub_contractor_tool; +CREATE TABLE `bus_contractor_tool` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `contractor_id` bigint not null comment '分包方id', + `tool_name` varchar(255) null comment '工具名称', + `tool_type` char(2) null comment '工具类型', + `tool_model` varchar(255) null comment '工具型号', + `tool_number` decimal(10) default 0 not null comment '工具数量', + `file` varchar(512) null comment '文件', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id' +) comment = '分包方工器具' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `sub_contractor_tool_record`; +CREATE TABLE `sub_contractor_tool_record` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `contractor_id` bigint not null comment '分包方id', + `contractor_tool_id` bigint not null comment '分包方工器具id', + `record_type` char(1) not null comment '记录类型(1进场 2出场)', + `record_number` decimal default 0 not null comment '进场工器具数量', + `remaining_number` decimal default 0 not null comment '剩余数量', + `check_num` varchar(255) null comment '检测编号', + `check_dept` varchar(255) null comment '检测部门', + `check_time` datetime null comment '检测时间', + `certificate` varchar(512) null comment '合格证', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `record_time` datetime null comment '记录时间', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id', + index `idx_contractor_tool_id` (`contractor_tool_id` asc) using btree comment '分包方工器具id' +) comment = '分包方工器具记录' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `sub_contractor_material`; +CREATE TABLE `sub_contractor_material` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `contractor_id` bigint not null comment '分包方id', + `material_name` varchar(255) not null comment '物料名称', + `material_type` char(2) null comment '物料类型', + `material_model` varchar(255) null comment '物料型号', + `material_number` decimal(10) default 0 not null comment '物料数量', + `material_unit` varchar(50) not null comment '物料单位', + `file` varchar(512) null comment '文件', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + `is_delete` tinyint(4) default 0 not null comment '是否删除(0正常 1删除)', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id' +) comment = '分包方物料' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `sub_contractor_material_record`; +CREATE TABLE `sub_contractor_material_record` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `contractor_id` bigint not null comment '分包方id', + `contractor_material_id` bigint not null comment '物料id', + `record_type` char(1) not null comment '记录类型(1到货计划 2使用情况)', + `record_time` datetime not null comment '记录时间', + `record_number` decimal(10) default 0 not null comment '数量', + `remaining_number` decimal(10) default 0 not null comment '剩余数量(到货 使用)', + `used_position` varchar(255) null comment '使用位置或构件部位(使用情况)', + `file` varchar(512) null comment '相关附件', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id', + index `idx_contractor_material_id` (`contractor_material_id` asc) using btree comment '物料id' +) comment = '分包方物料记录' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `des_technical_standard`; +CREATE TABLE `des_technical_standard` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `pid` bigint default 0 not null comment '父级(0代表顶级)', + `file_name` varchar(255) not null comment '文件名称', + `file_path` varchar(512) null comment '文件路径', + `file_url` varchar(512) null comment '文件访问路径', + `file_type` char(1) not null comment '文件类型(1文件夹 2文件 3图片)', + `file_suffix` varchar(20) null comment '文件后缀', + `file_status` char(1) default '0' not null comment '状态(0正常 1删除)', + `original_name` varchar(255) null comment '原文件名', + `remark` varchar(512) null comment '备注', + `create_by` varchar(64) null comment '创建者', + `update_by` varchar(64) null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment '技术标准管理文档' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `des_drawing`; +CREATE TABLE `des_drawing` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `version_number` varchar(50) not null comment '版本号', + `file_name` varchar(255) not null comment '文件名称', + `file_url` varchar(512) null comment '文件访问路径', + `file_type` char(1) not null comment '文件类型(1过程图纸 2蓝图 3变更图纸)', + `file_suffix` varchar(20) null comment '文件后缀', + `file_status` char(1) default '0' not null comment '状态(0正常 1删除)', + `original_name` varchar(255) null comment '原文件名', + `newest` char(1) default '1' not null comment '是否最新(0否 1是)', + `status` varchar(255) null comment '审核状态', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_file_type` (`file_type` asc) using btree comment '文件类型' +) comment '图纸管理' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `des_special_scheme`; +CREATE TABLE `des_special_scheme` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `version_number` varchar(50) not null comment '版本号', + `file_name` varchar(255) not null comment '文件名称', + `file_url` bigint null comment '文件访问路径', + `file_suffix` varchar(20) null comment '文件后缀', + `file_status` char(1) default '0' not null comment '状态(0正常 1删除)', + `original_name` varchar(255) null comment '原文件名', + `status` varchar(255) default 'draft' not null comment '审核状态', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + `deleted_at` datetime null comment '删除时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment '专项方案管理' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `des_design_change`; +CREATE TABLE `des_design_change` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `form_no` varchar(50) null comment '申请单编号', + `project_name` varchar(255) null comment '工程名称', + `submit_unit` varchar(255) null comment '提出单位', + `specialty` varchar(100) null comment '专业', + `submit_date` date null comment '提出日期', + `volume_name` varchar(255) null comment '卷册名称', + `volume_no` varchar(100) null comment '卷册号', + `attachment_pic` varchar(1024) null comment '附图', + `change_reason` varchar(255) null comment '变更原因', + `change_content` text null comment '变更内容', + `cost_estimation` text null comment '变更费用估算', + `cost_estimation_file` varchar(1024) null comment '变更费用估算计算表', + `file_id` varchar(255) null comment '变更文件', + `status` varchar(255) null comment '审核状态', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment '设计变更管理' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `mat_material_receive`; +CREATE TABLE `mat_material_receive` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `material_source` char(1) not null comment '材料来源(1甲供 2乙供)', + `form_code` varchar(50) null comment '表单编号', + `project_name` varchar(255) null comment '工程名称', + `material_name` varchar(255) null comment '设备材料名称', + `contract_name` varchar(255) null comment '合同名称', + `ordering_unit` varchar(255) null comment '订货单位', + `supplier_unit` varchar(255) null comment '供货单位', + `defect_description` text null comment '缺陷情况(承包单位填写)', + `cert_count` int default 0 null comment '合格证份数', + `cert_count_file_id` varchar(1024) null comment '合格证文件', + `report_count` int default 0 null comment '出厂报告份数', + `report_count_file_id` varchar(1024) null comment '出厂报告文件', + `tech_doc_count` int default 0 null comment '技术资料份数', + `tech_doc_count_file_id` varchar(1024) null comment '技术资料文件', + `license_count` int default 0 null comment '厂家资质文件份数', + `license_count_file_id` varchar(1024) null comment '厂家资质文件', + `storage_type` char(1) null comment '设备材料入库/移交', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_material_source` (`material_source` asc) using btree comment '材料来源' +) comment '物料接收单' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `mat_material_receive_item`; +CREATE TABLE `mat_material_receive_item` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `receive_id` bigint not null comment '接收单id', + `name` varchar(255) null comment '名称', + `specification` varchar(255) null comment '规格', + `unit` varchar(255) null comment '单位', + `quantity` decimal(10, 2) null comment '数量', + `accepted_quantity` decimal(10, 2) null comment '验收', + `shortage_quantity` decimal(10, 2) null comment '缺件', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_receive_id` (`receive_id` asc) using btree comment '接收单id' +) comment '物料接收单明细项' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `mat_material_issue`; +CREATE TABLE `mat_material_issue` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `material_source` char(1) not null comment '材料来源(1甲供 2乙供)', + `form_code` varchar(50) null comment '表单编号', + `project_name` varchar(255) null comment '工程名称', + `material_name` varchar(255) null comment '设备材料名称', + `ordering_unit` varchar(255) null comment '订货单位', + `supplier_unit` varchar(255) null comment '供货单位', + `issue_unit` varchar(255) null comment '领料单位', + `storage_unit` varchar(255) null comment '保管单位', + `defect_description` text null comment '缺陷情况(承包单位填写)', + `cert_count` int default 0 null comment '合格证份数', + `cert_count_file_id` varchar(1024) null comment '合格证文件', + `report_count` int default 0 null comment '出厂报告份数', + `report_count_file_id` varchar(1024) null comment '出厂报告文件', + `tech_doc_count` int default 0 null comment '技术资料份数', + `tech_doc_count_file_id` varchar(1024) null comment '技术资料文件', + `license_count` int default 0 null comment '厂家资质文件份数', + `license_count_file_id` varchar(1024) null comment '厂家资质文件', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_material_source` (`material_source` asc) using btree comment '材料来源' +) comment '物料领料单' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `mat_material_issue_item`; +CREATE TABLE `mat_material_issue_item` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `issue_id` bigint not null comment '接收单id', + `name` varchar(255) null comment '名称', + `specification` varchar(255) null comment '规格', + `unit` varchar(255) null comment '单位', + `stock_quantity` decimal(10, 2) null comment '库存', + `issued_quantity` decimal(10, 2) null comment '领取', + `remaining_quantity` decimal(10, 2) null comment '剩余', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id', + index `idx_issue_id` (`issue_id` asc) using btree comment '领料单id' +) comment '物料领料单明细项' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `dro_drone_config`; +CREATE TABLE `dro_drone_config` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `config_name` varchar(255) null comment '配置名称', + `config_url` varchar(255) null comment '配置地址', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment '无人机配置' collate = utf8mb4_unicode_ci; + +DROP TABLE IF EXISTS `hse_violation_record`; +CREATE TABLE `hse_violation_record` +( + `id` bigint not null auto_increment comment '主键id', + `project_id` bigint not null comment '项目id', + `level_id` bigint not null comment '违章等级id', + `recognize_id` bigint not null comment '识别记录id', + `violation_type` varchar(32) null comment '违章类型', + `violation_time` datetime null comment '违章时间', + `handler_id` bigint null comment '违章处理人id', + `dispose_deadline` date null comment '处理期限', + `dispose_time` datetime null comment '处理时间', + `measure` varchar(300) null comment '整改措施', + `rectification_time` datetime null comment '整改时间', + `review` varchar(255) null comment '复查情况', + `review_type` char(1) null comment '复查状态(1通过 2未通过)', + `review_time` datetime null comment '复查时间', + `process_type` char(1) default '1' not null comment '处理流程类型(0仅通知 1通知整改复查)', + `status` char(1) default '1' not null comment '工单状态(1通知 2整改 3复查)', + `remark` varchar(255) null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_dept` bigint null comment '创建部门', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree, + index `idx_project_id` (`project_id` asc) using btree comment '项目id' +) comment '违规记录' collate = utf8mb4_unicode_ci; + diff --git a/script/sql/xinnengyuan_app.sql b/script/sql/xinnengyuan_app.sql new file mode 100644 index 0000000..805cbdf --- /dev/null +++ b/script/sql/xinnengyuan_app.sql @@ -0,0 +1,55 @@ +use xinnengyuandev; + +create table app_role +( + `id` bigint not null auto_increment comment '主键ID', + `role_name` varchar(30) not null comment '角色名称', + `role_key` varchar(100) not null comment '角色权限字符串', + `order_num` int(4) default 0 not null comment '显示顺序', + `data_scope` char(1) default '1' not null comment '数据范围(1:全部数据权限 2:自定数据权限)', + `status` char(1) default '0' not null comment '角色状态(0正常 1停用)', + `create_dept` bigint null comment '创建部门', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree +) collate = utf8mb4_unicode_ci comment = 'app角色'; + +create table app_menu +( + `id` bigint not null auto_increment comment '主键ID', + `menu_name` varchar(50) not null comment '菜单名称', + `parent_id` bigint default 0 not null comment '父菜单ID', + `order_num` int(4) default 0 not null comment '显示顺序', + `path` varchar(200) default '' not null comment '路由地址', + `component` varchar(255) null comment '组件路径', + `query_param` varchar(255) null comment '路由参数', + `menu_type` char(1) not null comment '菜单类型(M目录 C菜单 F按钮)', + `visible` char(1) default '0' not null comment '显示状态(0显示 1隐藏)', + `status` char(1) default '0' not null comment '菜单状态(0正常 1停用)', + `perms` varchar(100) null comment '权限标识', + `icon` varchar(100) default '#' not null comment '菜单图标', + `create_dept` bigint null comment '创建部门', + `remark` text null comment '备注', + `create_by` bigint null comment '创建者', + `update_by` bigint null comment '更新者', + `create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间', + `update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + primary key (`id`) using btree +) collate = utf8mb4_unicode_ci comment = 'app菜单'; + +create table app_user_role +( + user_id bigint not null comment '用户ID', + role_id bigint not null comment '角色ID', + primary key (user_id, role_id) +) collate = utf8mb4_unicode_ci comment = 'app用户和角色关联'; + +create table app_role_menu +( + role_id bigint not null comment '角色ID', + menu_id bigint not null comment '菜单ID', + primary key (role_id, menu_id) +) collate = utf8mb4_unicode_ci comment = 'app角色和菜单关联';