Merge remote-tracking branch 'origin/dev' into feature/springdoc

This commit is contained in:
xingyu 2022-12-21 22:46:52 +08:00
commit 4f2c08f8db
68 changed files with 3812 additions and 2122 deletions

View File

@ -169,21 +169,21 @@ ps核心功能已经实现正在对接微信小程序中...
## 🐨 技术栈 ## 🐨 技术栈
| 项目 | 说明 | | 项目 | 说明 |
|-----------------------|--------------------| |-------------------------|-----------------------|
| `yudao-dependencies` | Maven 依赖版本管理 | | `yudao-dependencies` | Maven 依赖版本管理 |
| `yudao-framework` | Java 框架拓展 | | `yudao-framework` | Java 框架拓展 |
| `yudao-server` | 管理后台 + 用户 APP 的服务端 | | `yudao-server` | 管理后台 + 用户 APP 的服务端 |
| `yudao-ui-admin` | 管理后台的 Vue2 前端项目 | | `yudao-ui-admin` | 管理后台的 Vue2 前端项目 |
| `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 | | `yudao-ui-admin-vue3` | 管理后台的 Vue3 前端项目 |
| `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 | | `yudao-ui-admin-uniapp` | 管理后台的 uni-app 多端项目 |
| `yudao-ui-app` | 用户 APP 的 UI 界面 | | `yudao-ui-app` | 用户 APP 的 UI 界面 |
| `yudao-module-system` | 系统功能的 Module 模块 | | `yudao-module-system` | 系统功能的 Module 模块 |
| `yudao-module-member` | 会员中心的 Module 模块 | | `yudao-module-member` | 会员中心的 Module 模块 |
| `yudao-module-infra` | 基础设施的 Module 模块 | | `yudao-module-infra` | 基础设施的 Module 模块 |
| `yudao-module-tool` | 研发工具的 Module 模块 | | `yudao-module-tool` | 研发工具的 Module 模块 |
| `yudao-module-bpm` | 工作流程的 Module 模块 | | `yudao-module-bpm` | 工作流程的 Module 模块 |
| `yudao-module-pay` | 支付系统的 Module 模块 | | `yudao-module-pay` | 支付系统的 Module 模块 |
### 后端 ### 后端
@ -193,7 +193,7 @@ ps核心功能已经实现正在对接微信小程序中...
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | | | [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | | [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | | | [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | |
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) | | [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) | | [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
@ -204,12 +204,12 @@ ps核心功能已经实现正在对接微信小程序中...
| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | | [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) | | [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.1 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.7 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | | [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | | | [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | |
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) | | [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) | | [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - | | [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - |
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.2 | - | | [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - |
### [管理后台 Vue2 前端](./yudao-ui-admin) ### [管理后台 Vue2 前端](./yudao-ui-admin)
@ -223,12 +223,12 @@ ps核心功能已经实现正在对接微信小程序中...
| 框架 | 说明 | 版本 | | 框架 | 说明 | 版本 |
|----------------------------------------------------------------------|:------------:|:------:| |----------------------------------------------------------------------|:------------:|:------:|
| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 | | [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 |
| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.2.3 | | [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.2 |
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.25 | | [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.27 |
| [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 | | [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 |
| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.27 | | [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.28 |
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.5.6 | | [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.7 |
### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp) ### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)
@ -242,15 +242,15 @@ ps核心功能已经实现正在对接微信小程序中...
### 系统功能 ### 系统功能
| 模块 | biu | biu | biu | | 模块 | biu | biu | biu |
|----------|--------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------| |------------|--------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|
| 登录 & 首页 | ![登录](https://static.iocoder.cn/images/ruoyi-vue-pro/登录.jpg?imageView2/2/format/webp/w/1280) | ![首页](https://static.iocoder.cn/images/ruoyi-vue-pro/首页.jpg?imageView2/2/format/webp/w/1280) | ![个人中心](https://static.iocoder.cn/images/ruoyi-vue-pro/个人中心.jpg?imageView2/2/format/webp/w/1280) | | 登录 & 首页 | ![登录](https://static.iocoder.cn/images/ruoyi-vue-pro/登录.jpg?imageView2/2/format/webp/w/1280) | ![首页](https://static.iocoder.cn/images/ruoyi-vue-pro/首页.jpg?imageView2/2/format/webp/w/1280) | ![个人中心](https://static.iocoder.cn/images/ruoyi-vue-pro/个人中心.jpg?imageView2/2/format/webp/w/1280) |
| 用户 & 应用 | ![用户管理](https://static.iocoder.cn/images/ruoyi-vue-pro/用户管理.jpg?imageView2/2/format/webp/w/1280) | ![令牌管理](https://static.iocoder.cn/images/ruoyi-vue-pro/令牌管理.jpg?imageView2/2/format/webp/w/1280) | ![应用管理](https://static.iocoder.cn/images/ruoyi-vue-pro/应用管理.jpg?imageView2/2/format/webp/w/1280) | | 用户 & 应用 | ![用户管理](https://static.iocoder.cn/images/ruoyi-vue-pro/用户管理.jpg?imageView2/2/format/webp/w/1280) | ![令牌管理](https://static.iocoder.cn/images/ruoyi-vue-pro/令牌管理.jpg?imageView2/2/format/webp/w/1280) | ![应用管理](https://static.iocoder.cn/images/ruoyi-vue-pro/应用管理.jpg?imageView2/2/format/webp/w/1280) |
| 租户 & 套餐 | ![租户管理](https://static.iocoder.cn/images/ruoyi-vue-pro/租户管理.jpg?imageView2/2/format/webp/w/1280) | ![租户套餐](https://static.iocoder.cn/images/ruoyi-vue-pro/租户套餐.png) | - | | 租户 & 套餐 | ![租户管理](https://static.iocoder.cn/images/ruoyi-vue-pro/租户管理.jpg?imageView2/2/format/webp/w/1280) | ![租户套餐](https://static.iocoder.cn/images/ruoyi-vue-pro/租户套餐.png) | - |
| 部门 & 岗位 | ![部门管理](https://static.iocoder.cn/images/ruoyi-vue-pro/部门管理.jpg?imageView2/2/format/webp/w/1280) | ![岗位管理](https://static.iocoder.cn/images/ruoyi-vue-pro/岗位管理.jpg?imageView2/2/format/webp/w/1280) | - | | 部门 & 岗位 | ![部门管理](https://static.iocoder.cn/images/ruoyi-vue-pro/部门管理.jpg?imageView2/2/format/webp/w/1280) | ![岗位管理](https://static.iocoder.cn/images/ruoyi-vue-pro/岗位管理.jpg?imageView2/2/format/webp/w/1280) | - |
| 菜单 & 角色 | ![菜单管理](https://static.iocoder.cn/images/ruoyi-vue-pro/菜单管理.jpg?imageView2/2/format/webp/w/1280) | ![角色管理](https://static.iocoder.cn/images/ruoyi-vue-pro/角色管理.jpg?imageView2/2/format/webp/w/1280) | - | | 菜单 & 角色 | ![菜单管理](https://static.iocoder.cn/images/ruoyi-vue-pro/菜单管理.jpg?imageView2/2/format/webp/w/1280) | ![角色管理](https://static.iocoder.cn/images/ruoyi-vue-pro/角色管理.jpg?imageView2/2/format/webp/w/1280) | - |
| 审计日志 | ![操作日志](https://static.iocoder.cn/images/ruoyi-vue-pro/操作日志.jpg?imageView2/2/format/webp/w/1280) | ![登录日志](https://static.iocoder.cn/images/ruoyi-vue-pro/登录日志.jpg?imageView2/2/format/webp/w/1280) | - | | 审计日志 | ![操作日志](https://static.iocoder.cn/images/ruoyi-vue-pro/操作日志.jpg?imageView2/2/format/webp/w/1280) | ![登录日志](https://static.iocoder.cn/images/ruoyi-vue-pro/登录日志.jpg?imageView2/2/format/webp/w/1280) | - |
| 短信 | ![短信渠道](https://static.iocoder.cn/images/ruoyi-vue-pro/短信渠道.jpg?imageView2/2/format/webp/w/1280) | ![短信模板](https://static.iocoder.cn/images/ruoyi-vue-pro/短信模板.jpg?imageView2/2/format/webp/w/1280) | ![短信日志](https://static.iocoder.cn/images/ruoyi-vue-pro/短信日志.jpg?imageView2/2/format/webp/w/1280) | | 短信 | ![短信渠道](https://static.iocoder.cn/images/ruoyi-vue-pro/短信渠道.jpg?imageView2/2/format/webp/w/1280) | ![短信模板](https://static.iocoder.cn/images/ruoyi-vue-pro/短信模板.jpg?imageView2/2/format/webp/w/1280) | ![短信日志](https://static.iocoder.cn/images/ruoyi-vue-pro/短信日志.jpg?imageView2/2/format/webp/w/1280) |
| 字典 & 敏感词 | ![字典类型](https://static.iocoder.cn/images/ruoyi-vue-pro/字典类型.jpg?imageView2/2/format/webp/w/1280) | ![字典数据](https://static.iocoder.cn/images/ruoyi-vue-pro/字典数据.jpg?imageView2/2/format/webp/w/1280) | ![敏感词](https://static.iocoder.cn/images/ruoyi-vue-pro/敏感词.jpg?imageView2/2/format/webp/w/1280) | | 字典 & 敏感词 | ![字典类型](https://static.iocoder.cn/images/ruoyi-vue-pro/字典类型.jpg?imageView2/2/format/webp/w/1280) | ![字典数据](https://static.iocoder.cn/images/ruoyi-vue-pro/字典数据.jpg?imageView2/2/format/webp/w/1280) | ![敏感词](https://static.iocoder.cn/images/ruoyi-vue-pro/敏感词.jpg?imageView2/2/format/webp/w/1280) |
| 错误码 & 通知 | ![错误码管理](https://static.iocoder.cn/images/ruoyi-vue-pro/错误码管理.jpg?imageView2/2/format/webp/w/1280) | ![通知公告](https://static.iocoder.cn/images/ruoyi-vue-pro/通知公告.jpg?imageView2/2/format/webp/w/1280) | - | | 错误码 & 通知 | ![错误码管理](https://static.iocoder.cn/images/ruoyi-vue-pro/错误码管理.jpg?imageView2/2/format/webp/w/1280) | ![通知公告](https://static.iocoder.cn/images/ruoyi-vue-pro/通知公告.jpg?imageView2/2/format/webp/w/1280) | - |
### 工作流程 ### 工作流程

View File

@ -11,7 +11,7 @@
Target Server Version : 80026 Target Server Version : 80026
File Encoding : 65001 File Encoding : 65001
Date: 29/07/2022 00:33:25 Date: 20/12/2022 00:33:25
*/ */
SET NAMES utf8mb4; SET NAMES utf8mb4;
@ -300,7 +300,7 @@ CREATE TABLE `bpm_form` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的表单定义'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的表单定义';
-- ---------------------------- -- ----------------------------
-- Records of bpm_form -- Records of bpm_form
@ -329,7 +329,7 @@ CREATE TABLE `bpm_oa_leave` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OA 请假申请表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OA 请假申请表';
-- ---------------------------- -- ----------------------------
-- Records of bpm_oa_leave -- Records of bpm_oa_leave
@ -359,7 +359,7 @@ CREATE TABLE `bpm_process_definition_ext` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 135 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 流程定义的拓展表\n'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 流程定义的拓展表\n';
-- ---------------------------- -- ----------------------------
-- Records of bpm_process_definition_ext -- Records of bpm_process_definition_ext
@ -389,7 +389,7 @@ CREATE TABLE `bpm_process_instance_ext` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 290 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程实例的拓展'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程实例的拓展';
-- ---------------------------- -- ----------------------------
-- Records of bpm_process_instance_ext -- Records of bpm_process_instance_ext
@ -415,7 +415,7 @@ CREATE TABLE `bpm_task_assign_rule` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 265 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 任务规则表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 任务规则表';
-- ---------------------------- -- ----------------------------
-- Records of bpm_task_assign_rule -- Records of bpm_task_assign_rule
@ -444,7 +444,7 @@ CREATE TABLE `bpm_task_ext` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 341 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程任务的拓展表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程任务的拓展表';
-- ---------------------------- -- ----------------------------
-- Records of bpm_task_ext -- Records of bpm_task_ext
@ -469,7 +469,7 @@ CREATE TABLE `bpm_user_group` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 111 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户组'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户组';
-- ---------------------------- -- ----------------------------
-- Records of bpm_user_group -- Records of bpm_user_group
@ -504,7 +504,7 @@ CREATE TABLE `infra_api_access_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 35822 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表';
-- ---------------------------- -- ----------------------------
-- Records of infra_api_access_log -- Records of infra_api_access_log
@ -546,7 +546,7 @@ CREATE TABLE `infra_api_error_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 647 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
-- ---------------------------- -- ----------------------------
-- Records of infra_api_error_log -- Records of infra_api_error_log
@ -584,7 +584,7 @@ CREATE TABLE `infra_codegen_column` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1126 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
-- ---------------------------- -- ----------------------------
-- Records of infra_codegen_column -- Records of infra_codegen_column
@ -616,7 +616,7 @@ CREATE TABLE `infra_codegen_table` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 99 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
-- ---------------------------- -- ----------------------------
-- Records of infra_codegen_table -- Records of infra_codegen_table
@ -673,7 +673,7 @@ CREATE TABLE `infra_data_source_config` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '数据源配置表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '数据源配置表';
-- ---------------------------- -- ----------------------------
-- Records of infra_data_source_config -- Records of infra_data_source_config
@ -699,7 +699,7 @@ CREATE TABLE `infra_file` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 93 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
-- ---------------------------- -- ----------------------------
-- Records of infra_file -- Records of infra_file
@ -753,7 +753,7 @@ CREATE TABLE `infra_file_content` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
-- ---------------------------- -- ----------------------------
-- Records of infra_file_content -- Records of infra_file_content
@ -781,13 +781,13 @@ CREATE TABLE `infra_job` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表';
-- ---------------------------- -- ----------------------------
-- Records of infra_job -- Records of infra_job
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2022-04-03 20:35:25', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2022-04-03 20:35:25', b'0');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
@ -811,7 +811,7 @@ CREATE TABLE `infra_job_log` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 25295 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表';
-- ---------------------------- -- ----------------------------
-- Records of infra_job_log -- Records of infra_job_log
@ -836,7 +836,7 @@ CREATE TABLE `infra_test_demo` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 108 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
-- ---------------------------- -- ----------------------------
-- Records of infra_test_demo -- Records of infra_test_demo
@ -866,7 +866,7 @@ CREATE TABLE `member_user` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' UNIQUE INDEX `uk_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
) ENGINE = InnoDB AUTO_INCREMENT = 248 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户';
-- ---------------------------- -- ----------------------------
-- Records of member_user -- Records of member_user
@ -893,7 +893,7 @@ CREATE TABLE `pay_app` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付应用信息'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付应用信息';
-- ---------------------------- -- ----------------------------
-- Records of pay_app -- Records of pay_app
@ -921,7 +921,7 @@ CREATE TABLE `pay_channel` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付渠道\n'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付渠道\n';
-- ---------------------------- -- ----------------------------
-- Records of pay_channel -- Records of pay_channel
@ -947,7 +947,7 @@ CREATE TABLE `pay_merchant` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付商户信息'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付商户信息';
-- ---------------------------- -- ----------------------------
-- Records of pay_merchant -- Records of pay_merchant
@ -972,7 +972,7 @@ CREATE TABLE `pay_notify_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 363051 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付通知 App 的日志'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付通知 App 的日志';
-- ---------------------------- -- ----------------------------
-- Records of pay_notify_log -- Records of pay_notify_log
@ -1004,7 +1004,7 @@ CREATE TABLE `pay_notify_task` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 112 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商户支付退款等的通知\n'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商户支付退款等的通知\n';
-- ---------------------------- -- ----------------------------
-- Records of pay_notify_task -- Records of pay_notify_task
@ -1048,7 +1048,7 @@ CREATE TABLE `pay_order` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 125 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付订单\n'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付订单\n';
-- ---------------------------- -- ----------------------------
-- Records of pay_order -- Records of pay_order
@ -1077,7 +1077,7 @@ CREATE TABLE `pay_order_extension` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 124 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付订单\n'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '支付订单\n';
-- ---------------------------- -- ----------------------------
-- Records of pay_order_extension -- Records of pay_order_extension
@ -1166,8 +1166,6 @@ INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`,
INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, '运维部门', 101, 5, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:33', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, '运维部门', 101, 5, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:33', b'0', 1);
INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, '市场部门', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, '市场部门', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', b'0', 1);
INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, '财务部门', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', b'0', 1); INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, '财务部门', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', b'0', 1);
INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (110, '新部门', 0, 1, NULL, NULL, NULL, 0, '110', '2022-02-23 20:46:30', '110', '2022-02-23 20:46:30', b'0', 121);
INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, '顶级部门', 0, 1, NULL, NULL, NULL, 0, '113', '2022-03-07 21:44:50', '113', '2022-03-07 21:44:50', b'0', 122);
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
@ -1335,19 +1333,20 @@ COMMIT;
-- Table structure for system_dict_type -- Table structure for system_dict_type
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `system_dict_type`; DROP TABLE IF EXISTS `system_dict_type`;
CREATE TABLE `system_dict_type` ( CREATE TABLE `system_dict_type`(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '字典主键', `id` bigint NOT NULL AUTO_INCREMENT COMMENT '字典主键',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典名称', `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典名称',
`type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典类型', `type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典类型',
`status` tinyint NOT NULL DEFAULT 0 COMMENT '状态0正常 1停用', `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态0正常 1停用',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted_time` datetime DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE, `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `dict_type`(`type` ASC,`deleted_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 149 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; ) ENGINE = InnoDB AUTO_INCREMENT = 149 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
-- ---------------------------- -- ----------------------------
@ -1413,7 +1412,7 @@ CREATE TABLE `system_error_code` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5832 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表';
-- ---------------------------- -- ----------------------------
-- Records of system_error_code -- Records of system_error_code
@ -1442,7 +1441,7 @@ CREATE TABLE `system_login_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1670 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
-- ---------------------------- -- ----------------------------
-- Records of system_login_log -- Records of system_login_log
@ -1761,7 +1760,7 @@ CREATE TABLE `system_oauth2_access_token` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 404 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
-- ---------------------------- -- ----------------------------
-- Records of system_oauth2_access_token -- Records of system_oauth2_access_token
@ -1788,7 +1787,7 @@ CREATE TABLE `system_oauth2_approve` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 79 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 批准表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 批准表';
-- ---------------------------- -- ----------------------------
-- Records of system_oauth2_approve -- Records of system_oauth2_approve
@ -1854,7 +1853,7 @@ CREATE TABLE `system_oauth2_code` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 103 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 授权码表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 授权码表';
-- ---------------------------- -- ----------------------------
-- Records of system_oauth2_code -- Records of system_oauth2_code
@ -1881,7 +1880,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 295 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '刷新令牌'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '刷新令牌';
-- ---------------------------- -- ----------------------------
-- Records of system_oauth2_refresh_token -- Records of system_oauth2_refresh_token
@ -1921,7 +1920,7 @@ CREATE TABLE `system_operate_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2764 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
-- ---------------------------- -- ----------------------------
-- Records of system_operate_log -- Records of system_operate_log
@ -1947,7 +1946,7 @@ CREATE TABLE `system_post` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '岗位信息表'; ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '岗位信息表';
-- ---------------------------- -- ----------------------------
-- Records of system_post -- Records of system_post
@ -2303,7 +2302,7 @@ CREATE TABLE `system_sms_code` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
) ENGINE = InnoDB AUTO_INCREMENT = 480 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
-- ---------------------------- -- ----------------------------
-- Records of system_sms_code -- Records of system_sms_code
@ -2346,7 +2345,7 @@ CREATE TABLE `system_sms_log` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 337 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
-- ---------------------------- -- ----------------------------
-- Records of system_sms_log -- Records of system_sms_log
@ -2416,7 +2415,7 @@ CREATE TABLE `system_social_user` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表';
-- ---------------------------- -- ----------------------------
-- Records of system_social_user -- Records of system_social_user
@ -2441,7 +2440,7 @@ CREATE TABLE `system_social_user_bind` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
-- ---------------------------- -- ----------------------------
-- Records of system_social_user_bind -- Records of system_social_user_bind
@ -2527,12 +2526,7 @@ CREATE TABLE `system_user_post` (
-- Records of system_user_post -- Records of system_user_post
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1); INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1);
INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1);
INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 114, 3, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1);
INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', b'0', 1);
INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', b'0', 1);
INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', b'0', 1);
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
@ -2550,7 +2544,7 @@ CREATE TABLE `system_user_role` (
`deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表'; ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表';
-- ---------------------------- -- ----------------------------
-- Records of system_user_role -- Records of system_user_role
@ -2558,21 +2552,6 @@ CREATE TABLE `system_user_role` (
BEGIN; BEGIN;
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', b'0', 1); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 107, 106, '1', '2022-02-20 22:59:33', '1', '2022-02-20 22:59:33', b'0', 118);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 108, 107, '1', '2022-02-20 23:00:50', '1', '2022-02-20 23:00:50', b'0', 119);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (13, 109, 108, '1', '2022-02-20 23:11:50', '1', '2022-02-20 23:11:50', b'0', 120);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (14, 110, 109, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', b'0', 121);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (15, 111, 110, '110', '2022-02-23 13:14:38', '110', '2022-02-23 13:14:38', b'0', 121);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (16, 113, 111, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (17, 114, 101, '1', '2022-03-19 21:51:13', '1', '2022-03-19 21:51:13', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (19, 116, 113, '1', '2022-05-17 10:07:10', '1', '2022-05-17 10:07:10', b'0', 124);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (20, 104, 101, '1', '2022-05-28 15:43:57', '1', '2022-05-28 15:43:57', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', b'0', 1);
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
@ -2595,7 +2574,7 @@ CREATE TABLE `system_user_session` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户在线 Session'; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户在线 Session';
-- ---------------------------- -- ----------------------------
-- Records of system_user_session -- Records of system_user_session

View File

@ -418,17 +418,19 @@ CREATE TABLE `jimu_report_data_source` (
`update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人', `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新日期', `update_time` datetime NULL DEFAULT NULL COMMENT '更新日期',
`connect_times` int(1) UNSIGNED NULL DEFAULT 0 COMMENT '连接失败次数', `connect_times` int(1) UNSIGNED NULL DEFAULT 0 COMMENT '连接失败次数',
`tenant_id` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '多租户标识',
`type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类型(report:报表;drag:仪表盘)',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_jmdatasource_report_id`(`report_id`) USING BTREE, INDEX `idx_jmdatasource_report_id`(`report_id`) USING BTREE,
INDEX `idx_jmdatasource_code`(`code`) USING BTREE INDEX `idx_jmdatasource_code`(`code`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
-- ---------------------------- -- ----------------------------
-- Records of jimu_report_data_source -- Records of jimu_report_data_source
-- ---------------------------- -- ----------------------------
INSERT INTO `jimu_report_data_source` VALUES ('1324261983692902402', 'jeewx', '1324261770294071296', '', NULL, 'MYSQL', 'com.mysql.jdbc.Driver', 'jdbc:mysql://127.0.0.1:3306/jeewx-boot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8', 'root', 'root', 'jeecg', '2020-11-05 16:07:15', NULL, '2020-11-05 16:07:15', 0); INSERT INTO `jimu_report_data_source` VALUES ('1324261983692902402', 'jeewx', '1324261770294071296', '', NULL, 'MYSQL', 'com.mysql.jdbc.Driver', 'jdbc:mysql://127.0.0.1:3306/jeewx-boot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8', 'root', 'root', 'jeecg', '2020-11-05 16:07:15', NULL, '2020-11-05 16:07:15', 0, NULL, 'report');
INSERT INTO `jimu_report_data_source` VALUES ('26d21fe4f27920d2f56abc8d90a8e527', 'oracle', '1308645288868712448', '', NULL, 'ORACLE', 'oracle.jdbc.OracleDriver', 'jdbc:oracle:thin:@192.168.1.199:1521:helowin', 'jeecgbootbpm', 'jeecg196283', 'admin', '2021-01-05 19:26:24', NULL, '2021-01-05 19:26:24', 1); INSERT INTO `jimu_report_data_source` VALUES ('26d21fe4f27920d2f56abc8d90a8e527', 'oracle', '1308645288868712448', '', NULL, 'ORACLE', 'oracle.jdbc.OracleDriver', 'jdbc:oracle:thin:@192.168.1.199:1521:helowin', 'jeecgbootbpm', 'jeecg196283', 'admin', '2021-01-05 19:26:24', NULL, '2021-01-05 19:26:24', 1, NULL, 'report');
INSERT INTO `jimu_report_data_source` VALUES ('8f90daf47d15d35ca6cf420748b8b9ba', 'localhost', '1316944968992034816', '', NULL, 'MYSQL5.7', 'com.mysql.cj.jdbc.Driver', 'jdbc:mysql://127.0.0.1:3306/jeecg-boot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8', 'root', 'root', 'admin', '2021-01-13 14:34:00', NULL, '2021-01-13 14:34:00', 0); INSERT INTO `jimu_report_data_source` VALUES ('8f90daf47d15d35ca6cf420748b8b9ba', 'localhost', '1316944968992034816', '', NULL, 'MYSQL5.7', 'com.mysql.cj.jdbc.Driver', 'jdbc:mysql://127.0.0.1:3306/jeecg-boot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8', 'root', 'root', 'admin', '2021-01-13 14:34:00', NULL, '2021-01-13 14:34:00', 0, NULL, 'report');
-- ---------------------------- -- ----------------------------
-- Table structure for jimu_report_db -- Table structure for jimu_report_db

View File

@ -2474,17 +2474,18 @@ COMMIT;
-- Table structure for SYSTEM_DICT_TYPE -- Table structure for SYSTEM_DICT_TYPE
-- ---------------------------- -- ----------------------------
DROP TABLE "SYSTEM_DICT_TYPE"; DROP TABLE "SYSTEM_DICT_TYPE";
CREATE TABLE "SYSTEM_DICT_TYPE" ( CREATE TABLE "SYSTEM_DICT_TYPE"(
"ID" NUMBER(20,0) NOT NULL, "ID" NUMBER(20,0) NOT NULL,
"NAME" NVARCHAR2(100), "NAME" NVARCHAR2(100),
"TYPE" NVARCHAR2(100), "TYPE" NVARCHAR2(100),
"STATUS" NUMBER(4,0) NOT NULL, "STATUS" NUMBER(4,0) NOT NULL,
"REMARK" NVARCHAR2(500), "REMARK" NVARCHAR2(500),
"CREATOR" NVARCHAR2(64), "CREATOR" NVARCHAR2(64),
"CREATE_TIME" DATE NOT NULL, "CREATE_TIME" DATE NOT NULL,
"UPDATER" NVARCHAR2(64), "UPDATER" NVARCHAR2(64),
"UPDATE_TIME" DATE NOT NULL, "UPDATE_TIME" DATE NOT NULL,
"DELETED" NUMBER(1,0) DEFAULT 0 NOT NULL "DELETED_TIME" DATE,
"DELETED" NUMBER(1,0) DEFAULT 0 NOT NULL
) )
LOGGING LOGGING
NOCOMPRESS NOCOMPRESS
@ -2503,25 +2504,54 @@ PARALLEL 1
NOCACHE NOCACHE
DISABLE ROW MOVEMENT DISABLE ROW MOVEMENT
; ;
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."ID" IS '字典主键'; COMMENT
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."NAME" IS '字典名称'; ON COLUMN "SYSTEM_DICT_TYPE"."ID" IS '字典主键';
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."TYPE" IS '字典类型'; COMMENT
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."STATUS" IS '状态0正常 1停用'; ON COLUMN "SYSTEM_DICT_TYPE"."NAME" IS '字典名称';
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."REMARK" IS '备注'; COMMENT
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."CREATOR" IS '创建者'; ON COLUMN "SYSTEM_DICT_TYPE"."TYPE" IS '字典类型';
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."CREATE_TIME" IS '创建时间'; COMMENT
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."UPDATER" IS '更新者'; ON COLUMN "SYSTEM_DICT_TYPE"."STATUS" IS '状态0正常 1停用';
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."UPDATE_TIME" IS '更新时间'; COMMENT
COMMENT ON COLUMN "SYSTEM_DICT_TYPE"."DELETED" IS '是否删除'; ON COLUMN "SYSTEM_DICT_TYPE"."REMARK" IS '备注';
COMMENT ON TABLE "SYSTEM_DICT_TYPE" IS '字典类型表'; COMMENT
ON COLUMN "SYSTEM_DICT_TYPE"."CREATOR" IS '创建者';
COMMENT
ON COLUMN "SYSTEM_DICT_TYPE"."CREATE_TIME" IS '创建时间';
COMMENT
ON COLUMN "SYSTEM_DICT_TYPE"."UPDATER" IS '更新者';
COMMENT
ON COLUMN "SYSTEM_DICT_TYPE"."UPDATE_TIME" IS '更新时间';
COMMENT
ON COLUMN "SYSTEM_DICT_TYPE"."DELETED_TIME" IS '删除时间';
COMMENT
ON COLUMN "SYSTEM_DICT_TYPE"."DELETED" IS '是否删除';
COMMENT
ON TABLE "SYSTEM_DICT_TYPE" IS '字典类型表';
-- ---------------------------- -- ----------------------------
-- Records of SYSTEM_DICT_TYPE -- Records of SYSTEM_DICT_TYPE
-- ---------------------------- -- ----------------------------
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('1', '用户性别', 'system_user_sex', '0', NULL, 'admin', TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-05-01 12:55:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER",
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('6', '参数类型', 'infra_config_type', '0', NULL, 'admin', TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:36:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); "UPDATE_TIME", "DELETED")
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('7', '通知类型', 'system_notice_type', '0', NULL, 'admin', TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:35:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); VALUES ('1', '用户性别', 'system_user_sex', '0', NULL, 'admin',
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('9', '操作类型', 'system_operate_type', '0', NULL, 'admin', TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', TO_DATE('2022-02-16 09:32:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1',
TO_DATE('2022-05-01 12:55:56', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER",
"UPDATE_TIME", "DELETED")
VALUES ('6', '参数类型', 'infra_config_type', '0', NULL, 'admin',
TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), NULL,
TO_DATE('2022-02-01 16:36:54', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER",
"UPDATE_TIME", "DELETED")
VALUES ('7', '通知类型', 'system_notice_type', '0', NULL, 'admin',
TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), NULL,
TO_DATE('2022-02-01 16:35:26', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER",
"UPDATE_TIME", "DELETED")
VALUES ('9', '操作类型', 'system_operate_type', '0', NULL, 'admin',
TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1',
TO_DATE('2022-02-16 09:32:21', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('10', '系统状态', 'common_status', '0', NULL, 'admin', TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:21:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('10', '系统状态', 'common_status', '0', NULL, 'admin', TO_DATE('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:21:28', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('11', 'Boolean 是否类型', 'infra_boolean_string', '0', 'boolean 转是否', NULL, TO_DATE('2021-01-19 03:20:08', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:37:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('11', 'Boolean 是否类型', 'infra_boolean_string', '0', 'boolean 转是否', NULL, TO_DATE('2021-01-19 03:20:08', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:37:10', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('104', '登陆结果', 'system_login_result', '0', '登陆结果', NULL, TO_DATE('2021-01-18 06:17:11', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:36:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO "SYSTEM_DICT_TYPE" ("ID", "NAME", "TYPE", "STATUS", "REMARK", "CREATOR", "CREATE_TIME", "UPDATER", "UPDATE_TIME", "DELETED") VALUES ('104', '登陆结果', 'system_login_result', '0', '登陆结果', NULL, TO_DATE('2021-01-18 06:17:11', 'SYYYY-MM-DD HH24:MI:SS'), NULL, TO_DATE('2022-02-01 16:36:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');

View File

@ -2357,38 +2357,58 @@ COMMIT;
-- Table structure for system_dict_type -- Table structure for system_dict_type
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS "system_dict_type"; DROP TABLE IF EXISTS "system_dict_type";
CREATE TABLE "system_dict_type" ( CREATE TABLE "system_dict_type"(
"id" int8 NOT NULL, "id" int8 NOT NULL,
"name" varchar(100) COLLATE "pg_catalog"."default" NOT NULL, "name" varchar(100) COLLATE "pg_catalog"."default" NOT NULL,
"type" varchar(100) COLLATE "pg_catalog"."default" NOT NULL, "type" varchar(100) COLLATE "pg_catalog"."default" NOT NULL,
"status" int2 NOT NULL, "status" int2 NOT NULL,
"remark" varchar(500) COLLATE "pg_catalog"."default", "remark" varchar(500) COLLATE "pg_catalog"."default",
"creator" varchar(64) COLLATE "pg_catalog"."default", "creator" varchar(64) COLLATE "pg_catalog"."default",
"create_time" timestamp(6) NOT NULL, "create_time" timestamp(6) NOT NULL,
"updater" varchar(64) COLLATE "pg_catalog"."default", "updater" varchar(64) COLLATE "pg_catalog"."default",
"update_time" timestamp(6) NOT NULL, "update_time" timestamp(6) NOT NULL,
"deleted" int2 NOT NULL DEFAULT 0 "deleted_time" timestamp(6),
"deleted" int2 NOT NULL DEFAULT 0
) )
; ;
COMMENT ON COLUMN "system_dict_type"."id" IS '字典主键'; COMMENT
COMMENT ON COLUMN "system_dict_type"."name" IS '字典名称'; ON COLUMN "system_dict_type"."id" IS '字典主键';
COMMENT ON COLUMN "system_dict_type"."type" IS '字典类型'; COMMENT
COMMENT ON COLUMN "system_dict_type"."status" IS '状态0正常 1停用'; ON COLUMN "system_dict_type"."name" IS '字典名称';
COMMENT ON COLUMN "system_dict_type"."remark" IS '备注'; COMMENT
COMMENT ON COLUMN "system_dict_type"."creator" IS '创建者'; ON COLUMN "system_dict_type"."type" IS '字典类型';
COMMENT ON COLUMN "system_dict_type"."create_time" IS '创建时间'; COMMENT
COMMENT ON COLUMN "system_dict_type"."updater" IS '更新者'; ON COLUMN "system_dict_type"."status" IS '状态0正常 1停用';
COMMENT ON COLUMN "system_dict_type"."update_time" IS '更新时间'; COMMENT
COMMENT ON COLUMN "system_dict_type"."deleted" IS '是否删除'; ON COLUMN "system_dict_type"."remark" IS '备注';
COMMENT ON TABLE "system_dict_type" IS '字典类型表'; COMMENT
ON COLUMN "system_dict_type"."creator" IS '创建者';
COMMENT
ON COLUMN "system_dict_type"."create_time" IS '创建时间';
COMMENT
ON COLUMN "system_dict_type"."updater" IS '更新者';
COMMENT
ON COLUMN "system_dict_type"."update_time" IS '更新时间';
COMMENT
ON COLUMN "system_dict_type"."deleted_time" IS '删除时间';
COMMENT
ON COLUMN "system_dict_type"."deleted" IS '是否删除';
COMMENT
ON TABLE "system_dict_type" IS '字典类型表';
-- ---------------------------- -- ----------------------------
-- Records of system_dict_type -- Records of system_dict_type
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (1, '用户性别', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:30:31', 0); INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater",
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (6, '参数类型', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', 0); "update_time", "deleted")
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (7, '通知类型', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', 0); VALUES (1, '用户性别', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:30:31', 0);
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater",
"update_time", "deleted")
VALUES (6, '参数类型', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', 0);
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater",
"update_time", "deleted")
VALUES (7, '通知类型', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', 0);
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (9, '操作类型', 'system_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 09:32:21', 0); INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (9, '操作类型', 'system_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 09:32:21', 0);
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (10, '系统状态', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', 0); INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (10, '系统状态', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', 0);
INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (11, 'Boolean 是否类型', 'infra_boolean_string', 0, 'boolean 转是否', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', 0); INSERT INTO "system_dict_type" ("id", "name", "type", "status", "remark", "creator", "create_time", "updater", "update_time", "deleted") VALUES (11, 'Boolean 是否类型', 'infra_boolean_string', 0, 'boolean 转是否', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', 0);

View File

@ -5813,18 +5813,51 @@ IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[sy
DROP TABLE [dbo].[system_dict_type] DROP TABLE [dbo].[system_dict_type]
GO GO
CREATE TABLE [dbo].[system_dict_type] ( CREATE TABLE [dbo].[system_dict_type]
[id] bigint IDENTITY(1,1) NOT NULL, (
[name] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [
[type] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, id]
[status] tinyint NOT NULL, bigint
[remark] nvarchar(500) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, IDENTITY
[creator] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, (
[create_time] datetime2(7) NOT NULL, 1,
[updater] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, 1
[update_time] datetime2(7) NOT NULL, ) NOT NULL,
[deleted] bit DEFAULT 0 NOT NULL [name] nvarchar
) (
100
) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[type] nvarchar
(
100
) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[status] tinyint NOT NULL,
[remark] nvarchar
(
500
) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[creator] nvarchar
(
64
) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[create_time] datetime2
(
7
) NOT NULL,
[updater] nvarchar
(
64
) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[update_time] datetime2
(
7
) NOT NULL,
[deleted_time] datetime2
(
7
),
[deleted] bit DEFAULT 0 NOT NULL
)
GO GO
ALTER TABLE [dbo].[system_dict_type] SET (LOCK_ESCALATION = TABLE) ALTER TABLE [dbo].[system_dict_type] SET (LOCK_ESCALATION = TABLE)
@ -5882,26 +5915,29 @@ GO
EXEC sp_addextendedproperty EXEC sp_addextendedproperty
'MS_Description', N'更新者', 'MS_Description', N'更新者',
'SCHEMA', N'dbo', 'SCHEMA', N'dbo',
'TABLE', N'system_dict_type', 'TABLE', N'system_dict_type',
'COLUMN', N'updater' 'COLUMN', N'updater'
GO GO
EXEC sp_addextendedproperty
EXEC sp_addextendedproperty 'MS_Description', N'更新时间',
'MS_Description', N'更新时间', 'SCHEMA', N'dbo',
'SCHEMA', N'dbo', 'TABLE', N'system_dict_type',
'TABLE', N'system_dict_type', 'COLUMN', N'update_time'
'COLUMN', N'update_time' GO
GO EXEC sp_addextendedproperty
'MS_Description', N'删除时间',
EXEC sp_addextendedproperty 'SCHEMA', N'dbo',
'MS_Description', N'是否删除', 'TABLE', N'system_dict_type',
'SCHEMA', N'dbo', 'COLUMN', N'deleted_time'
'TABLE', N'system_dict_type', GO
'COLUMN', N'deleted' EXEC sp_addextendedproperty
GO 'MS_Description', N'是否删除',
'SCHEMA', N'dbo',
EXEC sp_addextendedproperty 'TABLE', N'system_dict_type',
'MS_Description', N'字典类型表', 'COLUMN', N'deleted'
GO
EXEC sp_addextendedproperty
'MS_Description', N'字典类型表',
'SCHEMA', N'dbo', 'SCHEMA', N'dbo',
'TABLE', N'system_dict_type' 'TABLE', N'system_dict_type'
GO GO

View File

@ -24,15 +24,15 @@
<!-- DB 相关 --> <!-- DB 相关 -->
<druid.version>1.2.15</druid.version> <druid.version>1.2.15</druid.version>
<mybatis-plus.version>3.5.2</mybatis-plus.version> <mybatis-plus.version>3.5.2</mybatis-plus.version>
<mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version> <mybatis-plus-generator.version>3.5.3</mybatis-plus-generator.version>
<dynamic-datasource.version>3.5.2</dynamic-datasource.version> <dynamic-datasource.version>3.6.0</dynamic-datasource.version>
<redisson.version>3.18.0</redisson.version> <redisson.version>3.18.0</redisson.version>
<!-- 服务保障相关 --> <!-- 服务保障相关 -->
<lock4j.version>2.2.3</lock4j.version> <lock4j.version>2.2.3</lock4j.version>
<resilience4j.version>1.7.1</resilience4j.version> <resilience4j.version>1.7.1</resilience4j.version>
<!-- 监控相关 --> <!-- 监控相关 -->
<skywalking.version>8.12.0</skywalking.version> <skywalking.version>8.12.0</skywalking.version>
<spring-boot-admin.version>2.7.7</spring-boot-admin.version> <spring-boot-admin.version>2.7.9</spring-boot-admin.version>
<opentracing.version>0.33.0</opentracing.version> <opentracing.version>0.33.0</opentracing.version>
<!-- Test 测试相关 --> <!-- Test 测试相关 -->
<podam.version>7.2.11.RELEASE</podam.version> <podam.version>7.2.11.RELEASE</podam.version>
@ -53,7 +53,7 @@
<transmittable-thread-local.version>2.14.2</transmittable-thread-local.version> <transmittable-thread-local.version>2.14.2</transmittable-thread-local.version>
<commons-net.version>3.8.0</commons-net.version> <commons-net.version>3.8.0</commons-net.version>
<jsch.version>0.1.55</jsch.version> <jsch.version>0.1.55</jsch.version>
<tika-core.version>2.5.0</tika-core.version> <tika-core.version>2.6.0</tika-core.version>
<aj-captcha.version>1.3.0</aj-captcha.version> <aj-captcha.version>1.3.0</aj-captcha.version>
<netty-all.version>4.1.85.Final</netty-all.version> <netty-all.version>4.1.85.Final</netty-all.version>
<!-- 三方云服务相关 --> <!-- 三方云服务相关 -->
@ -64,7 +64,7 @@
<aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version> <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
<tencentcloud-sdk-java.version>3.1.637</tencentcloud-sdk-java.version> <tencentcloud-sdk-java.version>3.1.637</tencentcloud-sdk-java.version>
<justauth.version>1.4.0</justauth.version> <justauth.version>1.4.0</justauth.version>
<jimureport.version>1.5.4</jimureport.version> <jimureport.version>1.5.6</jimureport.version>
<xercesImpl.version>2.12.2</xercesImpl.version> <xercesImpl.version>2.12.2</xercesImpl.version>
</properties> </properties>

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
import cn.iocoder.yudao.framework.expression.OrExpressionX;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
@ -20,7 +21,6 @@ import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.NullValue; import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression; import net.sf.jsqlparser.expression.operators.relational.InExpression;
@ -143,8 +143,8 @@ public class DeptDataPermissionRule implements DataPermissionRule {
if (userExpression == null) { if (userExpression == null) {
return deptExpression; return deptExpression;
} }
// 目前如果有指定部门 + 可查看自己采用 OR 条件WHERE dept_id IN ? OR user_id = ? // 目前如果有指定部门 + 可查看自己采用 OR 条件WHERE (dept_id IN ? OR user_id = ?)
return new OrExpression(deptExpression, userExpression); return new OrExpressionX(deptExpression, userExpression);
} }
private Expression buildDeptExpression(String tableName, Alias tableAlias, Set<Long> deptIds) { private Expression buildDeptExpression(String tableName, Alias tableAlias, Set<Long> deptIds) {

View File

@ -52,7 +52,7 @@
<dependency> <dependency>
<groupId>com.alipay.sdk</groupId> <groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId> <artifactId>alipay-sdk-java</artifactId>
<version>4.34.71.ALL</version> <version>4.35.0.ALL</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>

View File

@ -46,7 +46,6 @@
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>2.13.4</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>

View File

@ -30,8 +30,8 @@
<!-- DB 相关 --> <!-- DB 相关 -->
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-j</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.oracle.database.jdbc</groupId> <groupId>com.oracle.database.jdbc</groupId>

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.expression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
/**
* AndExpression 的扩展类(会在原有表达式两端加上括号)
*/
public class AndExpressionX extends AndExpression {
public AndExpressionX() {
}
public AndExpressionX(Expression leftExpression, Expression rightExpression) {
this.setLeftExpression(leftExpression);
this.setRightExpression(rightExpression);
}
@Override
public String toString() {
return "(" + super.toString() + ")";
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.expression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
/**
* OrExpression 的扩展类(会在原有表达式两端加上括号)
*/
public class OrExpressionX extends OrExpression {
public OrExpressionX() {
}
public OrExpressionX(Expression leftExpression, Expression rightExpression) {
this.setLeftExpression(leftExpression);
this.setRightExpression(rightExpression);
}
@Override
public String toString() {
return "(" + super.toString() + ")";
}
}

View File

@ -4,6 +4,7 @@ import lombok.*;
#foreach ($column in $columns) #foreach ($column in $columns)
#if (${column.javaType} == "LocalDateTime") #if (${column.javaType} == "LocalDateTime")
import java.time.LocalDateTime; import java.time.LocalDateTime;
#break
#end #end
#end #end
import io.swagger.annotations.*; import io.swagger.annotations.*;

View File

@ -34,9 +34,9 @@ const crudSchemas = reactive<VxeCrudSchema>({
#if ("" != $dictType)## 有数据字典 #if ("" != $dictType)## 有数据字典
dictType: DICT_TYPE.$dictType.toUpperCase(), dictType: DICT_TYPE.$dictType.toUpperCase(),
#if (${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer") #if (${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer")
dictData: 'number', dictClass: 'number',
#else #else
dictData: 'string', dictClass: 'string',
#end #end
#end #end
#if (!$column.createOperation && !$column.updateOperation) #if (!$column.createOperation && !$column.updateOperation)
@ -78,10 +78,7 @@ const crudSchemas = reactive<VxeCrudSchema>({
}, },
#elseif($column.htmlType == "imageUpload")## 图片上传 #elseif($column.htmlType == "imageUpload")## 图片上传
form: { form: {
component: 'UploadImg', component: 'UploadImg' // 单图上传多图为UploadImgs
componentProps: {
limit: 1
}
}, },
#elseif($column.htmlType == "fileUpload")## 图片上传 #elseif($column.htmlType == "fileUpload")## 图片上传
form: { form: {

View File

@ -103,7 +103,7 @@ public class PayOrderServiceImpl implements PayOrderService {
if (order != null) { if (order != null) {
log.warn("[createPayOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(), log.warn("[createPayOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(),
order.getMerchantOrderId(), JsonUtils.toJsonString(order)); // 理论来说不会出现这个情况 order.getMerchantOrderId(), JsonUtils.toJsonString(order)); // 理论来说不会出现这个情况
return app.getId(); return order.getId();
} }
// 创建支付交易单 // 创建支付交易单

View File

@ -130,7 +130,7 @@ public class PayRefundServiceImpl implements PayRefundService {
} else { } else {
// 成功插入退款单 状态为生成.没有和渠道交互 // 成功插入退款单 状态为生成.没有和渠道交互
// TODO @jason搞到 convert 一些额外的自动手动 set // TODO @jason搞到 convert 一些额外的自动手动 set
payRefundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo()) payRefundDO = PayRefundDO.builder()
.appId(order.getAppId()) .appId(order.getAppId())
.channelOrderNo(order.getChannelOrderNo()) .channelOrderNo(order.getChannelOrderNo())
.channelCode(order.getChannelCode()) .channelCode(order.getChannelCode())

View File

@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*; import lombok.*;
import java.time.LocalDateTime;
/** /**
* 字典类型表 * 字典类型表
* *
@ -47,4 +49,9 @@ public class DictTypeDO extends BaseDO {
*/ */
private String remark; private String remark;
/**
* 删除时间
*/
private LocalDateTime deletedTime;
} }

View File

@ -7,8 +7,12 @@ import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeExpo
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
@ -39,4 +43,10 @@ public interface DictTypeMapper extends BaseMapperX<DictTypeDO> {
return selectOne(DictTypeDO::getName, name); return selectOne(DictTypeDO::getName, name);
} }
@Update("UPDATE system_dict_type SET DELETED = 1,DELETED_TIME=#{deletedTime} WHERE id = #{id}")
int deleteById(@Param("id") Long id, @Param("deletedTime") LocalDateTime deletedTime);
default int deleteById(Long id) {
return deleteById(id, LocalDateTime.now());
}
} }

View File

@ -13,6 +13,7 @@ import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

View File

@ -12,3 +12,6 @@ VITE_APP_TENANT_ENABLE=true
# 验证码的开关 # 验证码的开关
VITE_APP_CAPTCHA_ENABLE=true VITE_APP_CAPTCHA_ENABLE=true
# 路由在只有一个子集的时候是否显示父级
VITE_ROUTE_ALWAYSSHOW_ENABLE=true

View File

@ -1,21 +1,20 @@
<h1>🌈 yudao-ui-admin-vue3</h1> # 🌈 yudao-ui-admin-vue3 #
<p align="center"> <p style="text-align: center">
<img src="https://img.shields.io/badge/-Vue3.2-34495e?logo=vue.j" /> <img src="https://img.shields.io/badge/-Vue3.2-34495e?logo=vue.j" alt="vue" />
<img src="https://img.shields.io/badge/-Vite3-646cff?logo=vite&logoColor=white" /> <img src="https://img.shields.io/badge/-Vite4-646cff?logo=vite&logoColor=white" alt="vite" />
<img src="https://img.shields.io/badge/-TypeScript4.9-blue?logo=typescript&logoColor=white" /> <img src="https://img.shields.io/badge/-TypeScript4.9-blue?logo=typescript&logoColor=white" alt="typescript" />
<img src="https://img.shields.io/badge/-Pinia2-yellow?logo=picpay&logoColor=white" /> <img src="https://img.shields.io/badge/-Pinia2-yellow?logo=picpay&logoColor=white" alt="Pinia2" />
<img src="https://img.shields.io/badge/-ESLint-4b32c3?logo=eslint&logoColor=white" /> <img src="https://img.shields.io/badge/-ESLint-4b32c3?logo=eslint&logoColor=white" alt="eslint" />
<img src="https://img.shields.io/badge/-pnpm7-F69220?logo=pnpm&logoColor=white" /> <img src="https://img.shields.io/badge/-pnpm7-F69220?logo=pnpm&logoColor=white" alt="pnpm" />
<img src="https://img.shields.io/badge/-Axios-008fc7?logo=axios.js&logoColor=white" />
<img src="https://img.shields.io/badge/-Prettier-ef9421?logo=Prettier&logoColor=white" alt="Prettier"> <img src="https://img.shields.io/badge/-Prettier-ef9421?logo=Prettier&logoColor=white" alt="Prettier">
<img src="https://img.shields.io/badge/-Sass-1D365D?logo=Sass&logoColor=white" alt="Sass"> <img src="https://img.shields.io/badge/-Sass-1D365D?logo=Sass&logoColor=white" alt="Sass">
<img src="https://img.shields.io/badge/-Wind%20CSS-06B6D4?logo=Tailwind%20CSS&logoColor=white" alt="Taiwind"> <img src="https://img.shields.io/badge/-Wind%20CSS-06B6D4?logo=Tailwind%20CSS&logoColor=white" alt="WindCSS">
</p> </p>
## 介绍 ## 介绍
- 基于 vue3.2+ TypeScript Element Plus 2.2.0+ Vite3 Pinia Vxe-table , Windicss 等开发的后台管理系统 - 基于 vue3.2+ TypeScript Element Plus 2.2.0+ Vite4 Pinia Vxe-table , Windicss 等开发的后台管理系统
## 注意事项 ## 注意事项
@ -30,12 +29,12 @@
| 框架 | 说明 | 版本 | | 框架 | 说明 | 版本 |
| --- | --- | --- | | --- | --- | --- |
| [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.45 | | [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.45 |
| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.2.3 | | [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.2 |
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.23 | | [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.27 |
| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.9.4 | | [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.9.4 |
| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.26 | | [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.28 |
| [vueuse](https://vueuse.org/) | 常用工具集 | 9.6.0 | | [vueuse](https://vueuse.org/) | 常用工具集 | 9.6.0 |
| [vxe-table](https://vxetable.cn/) | vue 最强表单 | 4.3.6 | | [vxe-table](https://vxetable.cn/) | vue 最强表单 | 4.3.7 |
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 |
| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.6 | | [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.6 |
| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 | | [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |

View File

@ -1,7 +1,6 @@
import { resolve } from 'path' import { resolve } from 'path'
import Vue from '@vitejs/plugin-vue' import Vue from '@vitejs/plugin-vue'
import VueJsx from '@vitejs/plugin-vue-jsx' import VueJsx from '@vitejs/plugin-vue-jsx'
import VueI18n from '@intlify/vite-plugin-vue-i18n'
import WindiCSS from 'vite-plugin-windicss' import WindiCSS from 'vite-plugin-windicss'
import progress from 'vite-plugin-progress' import progress from 'vite-plugin-progress'
import EslintPlugin from 'vite-plugin-eslint' import EslintPlugin from 'vite-plugin-eslint'
@ -9,6 +8,7 @@ import PurgeIcons from 'vite-plugin-purge-icons'
import { ViteEjsPlugin } from 'vite-plugin-ejs' import { ViteEjsPlugin } from 'vite-plugin-ejs'
import viteCompression from 'vite-plugin-compression' import viteCompression from 'vite-plugin-compression'
import vueSetupExtend from 'vite-plugin-vue-setup-extend' import vueSetupExtend from 'vite-plugin-vue-setup-extend'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { import {
createStyleImportPlugin, createStyleImportPlugin,
@ -51,7 +51,7 @@ export function createVitePlugins(VITE_APP_TITLE: string) {
cache: false, cache: false,
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件 include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
}), }),
VueI18n({ VueI18nPlugin({
runtimeOnly: true, runtimeOnly: true,
compositionOnly: true, compositionOnly: true,
include: [resolve(__dirname, 'src/locales/**')] include: [resolve(__dirname, 'src/locales/**')]

View File

@ -1,7 +1,7 @@
{ {
"name": "yudao-ui-admin-vue3", "name": "yudao-ui-admin-vue3",
"version": "1.6.5.1874", "version": "1.6.5.1878",
"description": "基于vue3、vite3、element-plus、typesScript", "description": "基于vue3、vite4、element-plus、typesScript",
"author": "xingyu", "author": "xingyu",
"private": false, "private": false,
"scripts": { "scripts": {
@ -25,67 +25,67 @@
}, },
"dependencies": { "dependencies": {
"@iconify/iconify": "^3.0.1", "@iconify/iconify": "^3.0.1",
"@vueuse/core": "^9.6.0", "@vueuse/core": "^9.8.2",
"@wangeditor/editor": "^5.1.23", "@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.10", "@wangeditor/editor-for-vue": "^5.1.10",
"@zxcvbn-ts/core": "^2.1.0", "@zxcvbn-ts/core": "^2.1.0",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^1.2.1", "axios": "^1.2.1",
"cropperjs": "^1.5.13",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"echarts": "^5.4.0", "echarts": "^5.4.1",
"echarts-wordcloud": "^2.1.0", "echarts-wordcloud": "^2.1.0",
"element-plus": "2.2.26", "element-plus": "2.2.27",
"intro.js": "^6.0.0", "intro.js": "^6.0.0",
"jsencrypt": "^3.3.1", "jsencrypt": "^3.3.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mitt": "^3.0.0", "mitt": "^3.0.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.0.27", "pinia": "^2.0.28",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"qs": "^6.11.0", "qs": "^6.11.0",
"url": "^0.11.0", "url": "^0.11.0",
"vue": "3.2.45", "vue": "3.2.45",
"vue-cropper": "^1.0.3",
"vue-i18n": "9.2.2", "vue-i18n": "9.2.2",
"vue-router": "^4.1.6", "vue-router": "^4.1.6",
"vue-types": "^5.0.1", "vue-types": "^5.0.1",
"vxe-table": "^4.3.6", "vxe-table": "^4.3.7",
"web-storage-cache": "^1.1.1", "web-storage-cache": "^1.1.1",
"xe-utils": "^3.5.7" "xe-utils": "^3.5.7"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.3.0", "@commitlint/cli": "^17.3.0",
"@commitlint/config-conventional": "^17.3.0", "@commitlint/config-conventional": "^17.3.0",
"@iconify/json": "^2.1.149", "@iconify/json": "^2.1.155",
"@intlify/vite-plugin-vue-i18n": "^6.0.3", "@intlify/unplugin-vue-i18n": "^0.8.1",
"@purge-icons/generated": "^0.9.0", "@purge-icons/generated": "^0.9.0",
"@types/intro.js": "^5.1.0", "@types/intro.js": "^5.1.0",
"@types/lodash-es": "^4.17.6", "@types/lodash-es": "^4.17.6",
"@types/node": "^18.11.11", "@types/node": "^18.11.17",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.5.0", "@types/qrcode": "^1.5.0",
"@types/qs": "^6.9.7", "@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.46.0", "@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.46.0", "@typescript-eslint/parser": "^5.47.0",
"@vitejs/plugin-legacy": "^2.3.1", "@vitejs/plugin-legacy": "^3.0.1",
"@vitejs/plugin-vue": "^3.2.0", "@vitejs/plugin-vue": "^4.0.0",
"@vitejs/plugin-vue-jsx": "^2.1.1", "@vitejs/plugin-vue-jsx": "^3.0.0",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"consola": "^2.15.3", "consola": "^2.15.3",
"eslint": "^8.29.0", "eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-define-config": "^1.12.0", "eslint-define-config": "^1.12.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.8.0", "eslint-plugin-vue": "^9.8.0",
"lint-staged": "^13.1.0", "lint-staged": "^13.1.0",
"postcss": "^8.4.19", "postcss": "^8.4.20",
"postcss-html": "^1.5.0", "postcss-html": "^1.5.0",
"postcss-scss": "^4.0.6", "postcss-scss": "^4.0.6",
"prettier": "^2.8.1", "prettier": "^2.8.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^3.7.0", "rollup": "^3.7.5",
"sass": "^1.56.1", "sass": "^1.57.1",
"stylelint": "^14.16.0", "stylelint": "^14.16.0",
"stylelint-config-html": "^1.1.0", "stylelint-config-html": "^1.1.0",
"stylelint-config-prettier": "^9.0.4", "stylelint-config-prettier": "^9.0.4",
@ -94,17 +94,17 @@
"stylelint-order": "^5.0.0", "stylelint-order": "^5.0.0",
"terser": "^5.16.1", "terser": "^5.16.1",
"typescript": "4.9.4", "typescript": "4.9.4",
"vite": "3.2.5", "vite": "4.0.2",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-ejs": "^1.6.4", "vite-plugin-ejs": "^1.6.4",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-plugin-progress": "^0.0.6", "vite-plugin-progress": "^0.0.6",
"vite-plugin-purge-icons": "^0.9.1", "vite-plugin-purge-icons": "^0.9.2",
"vite-plugin-style-import": "2.0.0", "vite-plugin-style-import": "2.0.0",
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0", "vite-plugin-vue-setup-extend": "^0.4.0",
"vite-plugin-windicss": "^1.8.8", "vite-plugin-windicss": "^1.8.10",
"vue-tsc": "^1.0.11", "vue-tsc": "^1.0.16",
"windicss": "^3.5.6" "windicss": "^3.5.6"
}, },
"engines": { "engines": {

File diff suppressed because it is too large Load Diff

View File

@ -73,5 +73,5 @@ export const updateUserPwdApi = (oldPassword: string, newPassword: string) => {
// 用户头像上传 // 用户头像上传
export const uploadAvatarApi = (data) => { export const uploadAvatarApi = (data) => {
return request.put({ url: '/system/user/profile/update-avatar', data }) return request.upload({ url: '/system/user/profile/update-avatar', data: data })
} }

View File

@ -2,7 +2,7 @@
import { ElCard } from 'element-plus' import { ElCard } from 'element-plus'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { ref, onMounted, defineEmits } from 'vue' import { ref, onMounted } from 'vue'
import { Sticky } from '@/components/Sticky' import { Sticky } from '@/components/Sticky'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n() const { t } = useI18n()

View File

@ -0,0 +1,4 @@
import CropperImage from './src/Cropper.vue'
import CropperAvatar from './src/CropperAvatar.vue'
export { CropperImage, CropperAvatar }

View File

@ -0,0 +1,257 @@
<template>
<div>
<Dialog
v-model="dialogVisible"
:title="t('cropper.modalTitle')"
width="800px"
maxHeight="380px"
:canFullscreen="false"
>
<div :class="prefixCls">
<div :class="`${prefixCls}-left`">
<div :class="`${prefixCls}-cropper`">
<CropperImage
v-if="src"
:src="src"
height="300px"
:circled="circled"
@cropend="handleCropend"
@ready="handleReady"
/>
</div>
<div :class="`${prefixCls}-toolbar`">
<el-upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
<el-tooltip :content="t('cropper.selectImage')" placement="bottom">
<XButton preIcon="ant-design:upload-outlined" type="primary" />
</el-tooltip>
</el-upload>
<el-space>
<el-tooltip :content="t('cropper.btn_reset')" placement="bottom">
<XButton
type="primary"
preIcon="ant-design:reload-outlined"
size="small"
:disabled="!src"
@click="handlerToolbar('reset')"
/>
</el-tooltip>
<el-tooltip :content="t('cropper.btn_rotate_left')" placement="bottom">
<XButton
type="primary"
preIcon="ant-design:rotate-left-outlined"
size="small"
:disabled="!src"
@click="handlerToolbar('rotate', -45)"
/>
</el-tooltip>
<el-tooltip :content="t('cropper.btn_rotate_right')" placement="bottom">
<XButton
type="primary"
preIcon="ant-design:rotate-right-outlined"
size="small"
:disabled="!src"
@click="handlerToolbar('rotate', 45)"
/>
</el-tooltip>
<el-tooltip :content="t('cropper.btn_scale_x')" placement="bottom">
<XButton
type="primary"
preIcon="vaadin:arrows-long-h"
size="small"
:disabled="!src"
@click="handlerToolbar('scaleX')"
/>
</el-tooltip>
<el-tooltip :content="t('cropper.btn_scale_y')" placement="bottom">
<XButton
type="primary"
preIcon="vaadin:arrows-long-v"
size="small"
:disabled="!src"
@click="handlerToolbar('scaleY')"
/>
</el-tooltip>
<el-tooltip :content="t('cropper.btn_zoom_in')" placement="bottom">
<XButton
type="primary"
preIcon="ant-design:zoom-in-outlined"
size="small"
:disabled="!src"
@click="handlerToolbar('zoom', 0.1)"
/>
</el-tooltip>
<el-tooltip :content="t('cropper.btn_zoom_out')" placement="bottom">
<XButton
type="primary"
preIcon="ant-design:zoom-out-outlined"
size="small"
:disabled="!src"
@click="handlerToolbar('zoom', -0.1)"
/>
</el-tooltip>
</el-space>
</div>
</div>
<div :class="`${prefixCls}-right`">
<div :class="`${prefixCls}-preview`">
<img :src="previewSource" v-if="previewSource" :alt="t('cropper.preview')" />
</div>
<template v-if="previewSource">
<div :class="`${prefixCls}-group`">
<el-avatar :src="previewSource" size="large" />
<el-avatar :src="previewSource" :size="48" />
<el-avatar :src="previewSource" :size="64" />
<el-avatar :src="previewSource" :size="80" />
</div>
</template>
</div>
</div>
<template #footer>
<el-button type="primary" @click="handleOk">{{ t('cropper.okText') }}</el-button>
</template>
</Dialog>
</div>
</template>
<script setup lang="ts">
import { useDesign } from '@/hooks/web/useDesign'
import { dataURLtoBlob } from '@/utils/filt'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElUpload, ElAvatar, ElTooltip, ElSpace } from 'element-plus'
import { Dialog } from '@/components/Dialog'
import { CropperImage } from '@/components/Cropper'
import type { CropendResult, Cropper } from './types'
import { propTypes } from '@/utils/propTypes'
const props = defineProps({
srcValue: propTypes.string.def(''),
circled: propTypes.bool.def(true)
})
const emit = defineEmits(['uploadSuccess'])
const { t } = useI18n()
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('cropper-am')
const src = ref(props.srcValue)
const previewSource = ref('')
const cropper = ref<Cropper>()
const dialogVisible = ref(false)
let filename = ''
let scaleX = 1
let scaleY = 1
// Block upload
function handleBeforeUpload(file: File) {
const reader = new FileReader()
reader.readAsDataURL(file)
src.value = ''
previewSource.value = ''
reader.onload = function (e) {
src.value = (e.target?.result as string) ?? ''
filename = file.name
}
return false
}
function handleCropend({ imgBase64 }: CropendResult) {
previewSource.value = imgBase64
}
function handleReady(cropperInstance: Cropper) {
cropper.value = cropperInstance
}
function handlerToolbar(event: string, arg?: number) {
if (event === 'scaleX') {
scaleX = arg = scaleX === -1 ? 1 : -1
}
if (event === 'scaleY') {
scaleY = arg = scaleY === -1 ? 1 : -1
}
cropper?.value?.[event]?.(arg)
}
async function handleOk() {
const blob = dataURLtoBlob(previewSource.value)
emit('uploadSuccess', { source: previewSource.value, data: blob, filename: filename })
}
function openModal() {
dialogVisible.value = true
}
function closeModal() {
dialogVisible.value = false
}
defineExpose({ openModal, closeModal })
</script>
<style lang="scss">
$prefix-cls: #{$namespace}-cropper-am;
.#{$prefix-cls} {
display: flex;
&-left,
&-right {
height: 340px;
}
&-left {
width: 55%;
}
&-right {
width: 45%;
}
&-cropper {
height: 300px;
background: #eee;
background-image: linear-gradient(
45deg,
rgb(0 0 0 / 25%) 25%,
transparent 0,
transparent 75%,
rgb(0 0 0 / 25%) 0
),
linear-gradient(
45deg,
rgb(0 0 0 / 25%) 25%,
transparent 0,
transparent 75%,
rgb(0 0 0 / 25%) 0
);
background-position: 0 0, 12px 12px;
background-size: 24px 24px;
}
&-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
&-preview {
width: 220px;
height: 220px;
margin: 0 auto;
overflow: hidden;
border: 1px solid;
border-radius: 50%;
img {
width: 100%;
height: 100%;
}
}
&-group {
display: flex;
padding-top: 8px;
margin-top: 8px;
border-top: 1px solid;
justify-content: space-around;
align-items: center;
}
}
</style>

View File

@ -0,0 +1,190 @@
<template>
<div :class="getClass" :style="getWrapperStyle">
<img
v-show="isReady"
ref="imgElRef"
:src="src"
:alt="alt"
:crossorigin="crossorigin"
:style="getImageStyle"
/>
</div>
</template>
<script setup lang="ts">
import {
computed,
CSSProperties,
onMounted,
onUnmounted,
PropType,
ref,
unref,
useAttrs
} from 'vue'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import { useDesign } from '@/hooks/web/useDesign'
import { useDebounceFn } from '@vueuse/core'
import { propTypes } from '@/utils/propTypes'
type Options = Cropper.Options
const defaultOptions: Options = {
aspectRatio: 1,
zoomable: true,
zoomOnTouch: true,
zoomOnWheel: true,
cropBoxMovable: true,
cropBoxResizable: true,
toggleDragModeOnDblclick: true,
autoCrop: true,
background: true,
highlight: true,
center: true,
responsive: true,
restore: true,
checkCrossOrigin: true,
checkOrientation: true,
scalable: true,
modal: true,
guides: true,
movable: true,
rotatable: true
}
const props = defineProps({
src: propTypes.string.def(''),
alt: propTypes.string.def(''),
circled: propTypes.bool.def(false),
realTimePreview: propTypes.bool.def(true),
height: propTypes.string.def('360px'),
crossorigin: {
type: String as PropType<'' | 'anonymous' | 'use-credentials' | undefined>,
default: undefined
},
imageStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
options: { type: Object as PropType<Options>, default: () => ({}) }
})
const emit = defineEmits(['cropend', 'ready', 'cropendError'])
const attrs = useAttrs()
const imgElRef = ref<ElRef<HTMLImageElement>>()
const cropper = ref<Nullable<Cropper>>()
const isReady = ref(false)
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('cropper-image')
const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80)
const getImageStyle = computed((): CSSProperties => {
return {
height: props.height,
maxWidth: '100%',
...props.imageStyle
}
})
const getClass = computed(() => {
return [
prefixCls,
attrs.class,
{
[`${prefixCls}--circled`]: props.circled
}
]
})
const getWrapperStyle = computed((): CSSProperties => {
return { height: `${props.height}`.replace(/px/, '') + 'px' }
})
onMounted(init)
onUnmounted(() => {
cropper.value?.destroy()
})
async function init() {
const imgEl = unref(imgElRef)
if (!imgEl) {
return
}
cropper.value = new Cropper(imgEl, {
...defaultOptions,
ready: () => {
isReady.value = true
realTimeCroppered()
emit('ready', cropper.value)
},
crop() {
debounceRealTimeCroppered()
},
zoom() {
debounceRealTimeCroppered()
},
cropmove() {
debounceRealTimeCroppered()
},
...props.options
})
}
// Real-time display preview
function realTimeCroppered() {
props.realTimePreview && croppered()
}
// event: return base64 and width and height information after cropping
function croppered() {
if (!cropper.value) {
return
}
let imgInfo = cropper.value.getData()
const canvas = props.circled ? getRoundedCanvas() : cropper.value.getCroppedCanvas()
canvas.toBlob((blob) => {
if (!blob) {
return
}
let fileReader: FileReader = new FileReader()
fileReader.readAsDataURL(blob)
fileReader.onloadend = (e) => {
emit('cropend', {
imgBase64: e.target?.result ?? '',
imgInfo
})
}
fileReader.onerror = () => {
emit('cropendError')
}
}, 'image/png')
}
// Get a circular picture canvas
function getRoundedCanvas() {
const sourceCanvas = cropper.value!.getCroppedCanvas()
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')!
const width = sourceCanvas.width
const height = sourceCanvas.height
canvas.width = width
canvas.height = height
context.imageSmoothingEnabled = true
context.drawImage(sourceCanvas, 0, 0, width, height)
context.globalCompositeOperation = 'destination-in'
context.beginPath()
context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true)
context.fill()
return canvas
}
</script>
<style lang="scss">
$prefix-cls: #{$namespace}-cropper-image;
.#{$prefix-cls} {
&--circled {
.cropper-view-box,
.cropper-face {
border-radius: 50%;
}
}
}
</style>

View File

@ -0,0 +1,136 @@
<template>
<div class="user-info-head" @click="open()">
<img :src="sourceValue" v-if="sourceValue" class="img-circle img-lg" alt="avatar" />
<el-button :class="`${prefixCls}-upload-btn`" @click="open()" v-if="showBtn">
{{ btnText ? btnText : t('cropper.selectImage') }}
</el-button>
<CopperModal
ref="cropperModelRef"
@upload-success="handleUploadSuccess"
:srcValue="sourceValue"
/>
</div>
</template>
<script setup lang="ts">
import { useDesign } from '@/hooks/web/useDesign'
import { useMessage } from '@/hooks/web/useMessage'
import { propTypes } from '@/utils/propTypes'
import { ref, watch, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'
import CopperModal from './CopperModal.vue'
const props = defineProps({
width: propTypes.string.def('200px'),
value: propTypes.string.def(''),
showBtn: propTypes.bool.def(true),
btnText: propTypes.string.def('')
})
const emit = defineEmits(['update:value', 'change'])
const sourceValue = ref(props.value)
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('cropper-avatar')
const message = useMessage()
const { t } = useI18n()
const cropperModelRef = ref()
watchEffect(() => {
sourceValue.value = props.value
})
watch(
() => sourceValue.value,
(v: string) => {
emit('update:value', v)
}
)
function handleUploadSuccess({ source, data, filename }) {
sourceValue.value = source
emit('change', { source, data, filename })
message.success(t('cropper.uploadSuccess'))
}
function open() {
cropperModelRef.value.openModal()
}
function close() {
cropperModelRef.value.closeModal()
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
$prefix-cls: #{$namespace}--cropper-avatar;
.#{$prefix-cls} {
display: inline-block;
text-align: center;
&-image-wrapper {
overflow: hidden;
cursor: pointer;
border: 1px solid;
border-radius: 50%;
img {
width: 100%;
}
}
&-image-mask {
opacity: 0%;
position: absolute;
width: inherit;
height: inherit;
border-radius: inherit;
border: inherit;
background: rgb(0 0 0 / 40%);
cursor: pointer;
transition: opacity 0.4s;
::v-deep(svg) {
margin: auto;
}
}
&-image-mask:hover {
opacity: 4000%;
}
&-upload-btn {
margin: 10px auto;
}
}
.user-info-head {
position: relative;
display: inline-block;
}
.img-circle {
border-radius: 50%;
}
.img-lg {
width: 120px;
height: 120px;
}
.user-info-head:hover:after {
content: '+';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background: rgba(0, 0, 0, 0.5);
font-size: 24px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
line-height: 110px;
border-radius: 50%;
}
</style>

View File

@ -0,0 +1,8 @@
import type Cropper from 'cropperjs'
export interface CropendResult {
imgBase64: string
imgInfo: Cropper.Data
}
export type { Cropper }

View File

@ -23,6 +23,7 @@ const props = defineProps({
type: Object as PropType<IEditorConfig>, type: Object as PropType<IEditorConfig>,
default: () => undefined default: () => undefined
}, },
readonly: propTypes.bool.def(false),
modelValue: propTypes.string.def('') modelValue: propTypes.string.def('')
}) })
@ -61,7 +62,7 @@ const editorConfig = computed((): IEditorConfig => {
return Object.assign( return Object.assign(
{ {
placeholder: '请输入内容...', placeholder: '请输入内容...',
readOnly: false, readOnly: props.readonly,
customAlert: (s: string, t: string) => { customAlert: (s: string, t: string) => {
switch (t) { switch (t) {
case 'success': case 'success':

View File

@ -21,7 +21,7 @@ import {
} from 'element-plus' } from 'element-plus'
import { InputPassword } from '@/components/InputPassword' import { InputPassword } from '@/components/InputPassword'
import { Editor } from '@/components/Editor' import { Editor } from '@/components/Editor'
import { UploadImg, UploadFile } from '@/components/UploadFile' import { UploadImg, UploadImgs, UploadFile } from '@/components/UploadFile'
import { ComponentName } from '@/types/components' import { ComponentName } from '@/types/components'
const componentMap: Recordable<Component, ComponentName> = { const componentMap: Recordable<Component, ComponentName> = {
@ -48,6 +48,7 @@ const componentMap: Recordable<Component, ComponentName> = {
InputPassword: InputPassword, InputPassword: InputPassword,
Editor: Editor, Editor: Editor,
UploadImg: UploadImg, UploadImg: UploadImg,
UploadImgs: UploadImgs,
UploadFile: UploadFile UploadFile: UploadFile
} }

View File

@ -15,7 +15,9 @@ const props = defineProps({
// icon color // icon color
color: propTypes.string, color: propTypes.string,
// icon size // icon size
size: propTypes.number.def(16) size: propTypes.number.def(16),
// icon svg class
svgClass: propTypes.string.def('')
}) })
const elRef = ref<ElRef>(null) const elRef = ref<ElRef>(null)
@ -34,6 +36,11 @@ const getIconifyStyle = computed(() => {
} }
}) })
const getSvgClass = computed(() => {
const { svgClass } = props
return `iconify ${svgClass}`
})
const updateIcon = async (icon: string) => { const updateIcon = async (icon: string) => {
if (unref(isLocal)) return if (unref(isLocal)) return
@ -66,13 +73,13 @@ watch(
</script> </script>
<template> <template>
<ElIcon :class="prefixCls" :size="size" :color="color"> <ElIcon :class="prefixCls" :color="color" :size="size">
<svg v-if="isLocal" aria-hidden="true"> <svg v-if="isLocal" aria-hidden="true" :class="getSvgClass">
<use :xlink:href="symbolId" /> <use :xlink:href="symbolId" />
</svg> </svg>
<span v-else ref="elRef" :class="$attrs.class" :style="getIconifyStyle"> <span v-else ref="elRef" :class="$attrs.class" :style="getIconifyStyle">
<span class="iconify" :data-icon="symbolId"></span> <span :class="getSvgClass" :data-icon="symbolId"></span>
</span> </span>
</ElIcon> </ElIcon>
</template> </template>

View File

@ -64,7 +64,7 @@ const initQrcode = async () => {
options.errorCorrectionLevel || getErrorCorrectionLevel(unref(renderText)) options.errorCorrectionLevel || getErrorCorrectionLevel(unref(renderText))
const _width: number = await getOriginWidth(unref(renderText), options) const _width: number = await getOriginWidth(unref(renderText), options)
options.scale = props.width === 0 ? undefined : (props.width / _width) * 4 options.scale = props.width === 0 ? undefined : (props.width / _width) * 4
const canvasRef: HTMLCanvasElement = await toCanvas( const canvasRef: HTMLCanvasElement | any = await toCanvas(
unref(wrapRef) as HTMLCanvasElement, unref(wrapRef) as HTMLCanvasElement,
unref(renderText), unref(renderText),
options options

View File

@ -1,4 +1,5 @@
import UploadImg from './src/UploadImg.vue' import UploadImg from './src/UploadImg.vue'
import UploadImgs from './src/UploadImgs.vue'
import UploadFile from './src/UploadFile.vue' import UploadFile from './src/UploadFile.vue'
export { UploadImg, UploadFile } export { UploadImg, UploadImgs, UploadFile }

View File

@ -32,8 +32,8 @@
</el-upload> </el-upload>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts" name="UploadFile">
import { ref, watch } from 'vue' import { PropType, ref } from 'vue'
import { useMessage } from '@/hooks/web/useMessage' import { useMessage } from '@/hooks/web/useMessage'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { getAccessToken, getTenantId } from '@/utils/auth' import { getAccessToken, getTenantId } from '@/utils/auth'
@ -43,7 +43,10 @@ const message = useMessage() // 消息弹窗
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const props = defineProps({ const props = defineProps({
modelValue: propTypes.oneOfType([String, Object, Array]), modelValue: {
type: Array as PropType<UploadUserFile[]>,
required: true
},
title: propTypes.string.def('文件上传'), title: propTypes.string.def('文件上传'),
updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL), updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL),
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // , ['png', 'jpg', 'jpeg'] fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // , ['png', 'jpg', 'jpeg']
@ -57,40 +60,12 @@ const props = defineProps({
const valueRef = ref(props.modelValue) const valueRef = ref(props.modelValue)
const uploadRef = ref<UploadInstance>() const uploadRef = ref<UploadInstance>()
const uploadList = ref<UploadUserFile[]>([]) const uploadList = ref<UploadUserFile[]>([])
const fileList = ref<UploadUserFile[]>([]) const fileList = ref<UploadUserFile[]>(props.modelValue)
const uploadNumber = ref<number>(0) const uploadNumber = ref<number>(0)
const uploadHeaders = ref({ const uploadHeaders = ref({
Authorization: 'Bearer ' + getAccessToken(), Authorization: 'Bearer ' + getAccessToken(),
'tenant-id': getTenantId() 'tenant-id': getTenantId()
}) })
watch(
() => props.modelValue,
(val) => {
if (val) {
// , 穿map
const list = Array.isArray(props.modelValue)
? props.modelValue
: Array.isArray(props.modelValue?.split(','))
? props.modelValue?.split(',')
: Array.of(props.modelValue)
//
fileList.value = list.map((item) => {
if (typeof item === 'string') {
// edit by
item = { name: item, url: item }
}
return item
})
} else {
fileList.value = []
return []
}
},
{
deep: true,
immediate: true
}
)
// //
const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => { const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => {
if (fileList.value.length >= props.limit) { if (fileList.value.length >= props.limit) {

View File

@ -1,176 +1,267 @@
<template> <template>
<div class="component-upload-image"> <div class="upload-box">
<el-upload <el-upload
ref="uploadRef"
:multiple="props.limit > 1"
name="file"
v-model="valueRef"
list-type="picture-card"
v-model:file-list="fileList"
:show-file-list="true"
:action="updateUrl" :action="updateUrl"
:id="uuid"
:class="['upload', drag ? 'no-border' : '']"
:multiple="false"
:show-file-list="false"
:headers="uploadHeaders" :headers="uploadHeaders"
:limit="props.limit"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:on-exceed="handleExceed" :on-success="uploadSuccess"
:on-success="handleFileSuccess" :on-error="uploadError"
:on-error="excelUploadError" :drag="drag"
:on-remove="handleRemove" :accept="fileType.join(',')"
:on-preview="handlePictureCardPreview"
:class="{ hide: fileList.length >= props.limit }"
> >
<Icon icon="ep:upload-filled" /> <template v-if="modelValue">
<img :src="modelValue" class="upload-image" />
<div class="upload-handle" @click.stop>
<div class="handle-icon" @click="editImg">
<Icon icon="ep:edit" />
<span>{{ t('action.edit') }}</span>
</div>
<div class="handle-icon" @click="imgViewVisible = true">
<Icon icon="ep:zoom-in" />
<span>{{ t('action.detail') }}</span>
</div>
<div class="handle-icon" @click="deleteImg">
<Icon icon="ep:delete" />
<span>{{ t('action.del') }}</span>
</div>
</div>
</template>
<template v-else>
<div class="upload-empty">
<slot name="empty">
<Icon icon="ep:plus" />
<!-- <span>请上传图片</span> -->
</slot>
</div>
</template>
</el-upload> </el-upload>
<div class="el-upload__tip">
<slot name="tip"></slot>
</div>
<el-image-viewer
v-if="imgViewVisible"
@close="imgViewVisible = false"
:url-list="[modelValue]"
/>
</div> </div>
<!-- 文件列表 -->
<Dialog v-model="dialogVisible" title="预览" width="800" append-to-body>
<img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
</Dialog>
</template> </template>
<script setup lang="ts">
import { ref, watch } from 'vue' <script setup lang="ts" name="UploadImg">
import { Dialog } from '@/components/Dialog' import { ref } from 'vue'
import type { UploadProps } from 'element-plus'
import { ElUpload, ElNotification, ElImageViewer } from 'element-plus'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage' import { useMessage } from '@/hooks/web/useMessage'
import { generateUUID } from '@/utils'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { getAccessToken, getTenantId } from '@/utils/auth' import { getAccessToken, getTenantId } from '@/utils/auth'
import { ElUpload, UploadInstance, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus'
type FileTypes =
| 'image/apng'
| 'image/bmp'
| 'image/gif'
| 'image/jpeg'
| 'image/pjpeg'
| 'image/png'
| 'image/svg+xml'
| 'image/tiff'
| 'image/webp'
| 'image/x-icon'
//
const props = defineProps({
modelValue: propTypes.string.def(''),
updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL),
drag: propTypes.bool.def(true), // ==> true
disabled: propTypes.bool.def(false), // ==> false
fileSize: propTypes.number.def(5), // ==> 5M
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // ==> ["image/jpeg", "image/png", "image/gif"]
height: propTypes.string.def('150px'), // ==> 150px
width: propTypes.string.def('150px'), // ==> 150px
borderRadius: propTypes.string.def('8px') // ==> 8px
})
const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
// id
const uuid = ref('id-' + generateUUID())
//
const imgViewVisible = ref(false)
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const props = defineProps({ const deleteImg = () => {
modelValue: propTypes.oneOfType([String, Object, Array]), emit('update:modelValue', '')
title: propTypes.string.def('图片上传'), }
updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL),
fileType: propTypes.array.def(['jpg', 'png', 'gif', 'jpeg']), // , ['png', 'jpg', 'jpeg']
fileSize: propTypes.number.def(5), // (MB)
limit: propTypes.number.def(1), //
isShowTip: propTypes.bool.def(false) //
})
// ========== ==========
const valueRef = ref(props.modelValue)
const uploadRef = ref<UploadInstance>()
const uploadList = ref<UploadUserFile[]>([])
const fileList = ref<UploadUserFile[]>([])
const uploadNumber = ref<number>(0)
const dialogImageUrl = ref()
const dialogVisible = ref(false)
const uploadHeaders = ref({ const uploadHeaders = ref({
Authorization: 'Bearer ' + getAccessToken(), Authorization: 'Bearer ' + getAccessToken(),
'tenant-id': getTenantId() 'tenant-id': getTenantId()
}) })
watch(
() => props.modelValue, const editImg = () => {
(val) => { const dom = document.querySelector(`#${uuid.value} .el-upload__input`)
if (val) { dom && dom.dispatchEvent(new MouseEvent('click'))
// , 穿map
const list = Array.isArray(props.modelValue)
? props.modelValue
: Array.isArray(props.modelValue?.split(','))
? props.modelValue?.split(',')
: Array.of(props.modelValue)
//
fileList.value = list.map((item) => {
if (typeof item === 'string') {
// edit by
item = { name: item, url: item }
}
return item
})
} else {
fileList.value = []
return []
}
},
{
deep: true,
immediate: true
}
)
//
const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => {
if (fileList.value.length >= props.limit) {
message.error(`上传文件数量不能超过${props.limit}个!`)
return false
}
let fileExtension = ''
if (file.name.lastIndexOf('.') > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
}
const isImg = props.fileType.some((type: string) => {
if (file.type.indexOf(type) > -1) return true
return !!(fileExtension && fileExtension.indexOf(type) > -1)
})
const isLimit = file.size < props.fileSize * 1024 * 1024
if (!isImg) {
message.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式!`)
return false
}
if (!isLimit) {
message.error(`上传文件大小不能超过${props.fileSize}MB!`)
return false
}
message.success('正在上传文件,请稍候...')
uploadNumber.value++
} }
//
// const handleFileChange = (uploadFile: UploadFile): void => { const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
// uploadRef.value.data.path = uploadFile.name const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
// } const imgType = props.fileType
// if (!imgType.includes(rawFile.type as FileTypes))
const handleFileSuccess: UploadProps['onSuccess'] = (res: any): void => { ElNotification({
title: '温馨提示',
message: '上传图片不符合所需的格式!',
type: 'warning'
})
if (!imgSize)
ElNotification({
title: '温馨提示',
message: `上传图片大小不能超过 ${props.fileSize}M`,
type: 'warning'
})
return imgType.includes(rawFile.type as FileTypes) && imgSize
}
//
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
message.success('上传成功') message.success('上传成功')
uploadList.value.push({ name: res.data, url: res.data }) emit('update:modelValue', res.data)
if (uploadList.value.length == uploadNumber.value) {
fileList.value = fileList.value.concat(uploadList.value)
uploadList.value = []
uploadNumber.value = 0
emit('update:modelValue', listToString(fileList.value))
}
} }
//
const handleExceed: UploadProps['onExceed'] = (): void => { //
message.error(`上传文件数量不能超过${props.limit}个!`) const uploadError = () => {
} ElNotification({
// title: '温馨提示',
const excelUploadError: UploadProps['onError'] = (): void => { message: '图片上传失败,请您重新上传!',
message.error('导入数据失败,请您重新上传!') type: 'error'
} })
//
const handleRemove = (file) => {
const findex = fileList.value.map((f) => f.name).indexOf(file.name)
if (findex > -1) {
fileList.value.splice(findex, 1)
emit('update:modelValue', listToString(fileList.value))
}
}
//
const listToString = (list: UploadUserFile[], separator?: string) => {
let strs = ''
separator = separator || ','
for (let i in list) {
strs += list[i].url + separator
}
return strs != '' ? strs.substr(0, strs.length - 1) : ''
}
//
const handlePictureCardPreview: UploadProps['onPreview'] = (file) => {
dialogImageUrl.value = file.url
dialogVisible.value = true
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
// .el-upload--picture-card .is-error {
:deep(.hide .el-upload--picture-card) { .upload {
display: none; :deep(.el-upload),
:deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important;
&:hover {
border-color: var(--el-color-primary) !important;
}
}
}
} }
// :deep(.disabled) {
:deep(.el-list-enter-active, .el-list-leave-active) { .el-upload,
transition: all 0s; .el-upload-dragger {
cursor: not-allowed !important;
background: var(--el-disabled-bg-color);
border: 1px dashed var(--el-border-color-darker) !important;
&:hover {
border: 1px dashed var(--el-border-color-darker) !important;
}
}
} }
.upload-box {
:deep(.el-list-enter, .el-list-leave-active) { .no-border {
opacity: 0; :deep(.el-upload) {
transform: translateY(0); border: none !important;
}
}
:deep(.upload) {
.el-upload {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: v-bind(width);
height: v-bind(height);
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderRadius);
transition: var(--el-transition-duration-fast);
&:hover {
border-color: var(--el-color-primary);
.upload-handle {
opacity: 1;
}
}
.el-upload-dragger {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 0;
overflow: hidden;
background-color: transparent;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderRadius);
&:hover {
border: 1px dashed var(--el-color-primary);
}
}
.el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important;
}
.upload-image {
width: 100%;
height: 100%;
object-fit: contain;
}
.upload-empty {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 12px;
line-height: 30px;
color: var(--el-color-info);
.el-icon {
font-size: 28px;
color: var(--el-text-color-secondary);
}
}
.upload-handle {
position: absolute;
top: 0;
right: 0;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
cursor: pointer;
background: rgb(0 0 0 / 60%);
opacity: 0;
transition: var(--el-transition-duration-fast);
.handle-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 6%;
color: aliceblue;
.el-icon {
margin-bottom: 40%;
font-size: 130%;
line-height: 130%;
}
span {
font-size: 85%;
line-height: 85%;
}
}
}
}
}
.el-upload__tip {
line-height: 18px;
text-align: center;
}
} }
</style> </style>

View File

@ -0,0 +1,277 @@
<template>
<div class="upload-box">
<el-upload
:action="updateUrl"
list-type="picture-card"
:class="['upload', drag ? 'no-border' : '']"
v-model:file-list="fileList"
:multiple="true"
:limit="limit"
:headers="uploadHeaders"
:before-upload="beforeUpload"
:on-exceed="handleExceed"
:on-success="uploadSuccess"
:on-error="uploadError"
:drag="drag"
:accept="fileType.join(',')"
>
<div class="upload-empty">
<slot name="empty">
<Icon icon="ep:plus" />
<!-- <span>请上传图片</span> -->
</slot>
</div>
<template #file="{ file }">
<img :src="file.url" class="upload-image" />
<div class="upload-handle" @click.stop>
<div class="handle-icon" @click="handlePictureCardPreview(file)">
<Icon icon="ep:zoom-in" />
<span>查看</span>
</div>
<div class="handle-icon" @click="handleRemove(file)">
<Icon icon="ep:delete" />
<span>删除</span>
</div>
</div>
</template>
</el-upload>
<div class="el-upload__tip">
<slot name="tip"></slot>
</div>
<el-image-viewer
v-if="imgViewVisible"
@close="imgViewVisible = false"
:url-list="[viewImageUrl]"
/>
</div>
</template>
<script setup lang="ts" name="UploadImgs">
import { PropType, ref } from 'vue'
import { ElUpload, ElNotification, ElImageViewer } from 'element-plus'
import type { UploadProps, UploadFile, UploadUserFile } from 'element-plus'
import { useMessage } from '@/hooks/web/useMessage'
import { propTypes } from '@/utils/propTypes'
import { getAccessToken, getTenantId } from '@/utils/auth'
const message = useMessage() //
type FileTypes =
| 'image/apng'
| 'image/bmp'
| 'image/gif'
| 'image/jpeg'
| 'image/pjpeg'
| 'image/png'
| 'image/svg+xml'
| 'image/tiff'
| 'image/webp'
| 'image/x-icon'
const props = defineProps({
modelValue: {
type: Array as PropType<UploadUserFile[]>,
required: true
},
updateUrl: propTypes.string.def(import.meta.env.VITE_UPLOAD_URL),
drag: propTypes.bool.def(true), // ==> true
disabled: propTypes.bool.def(false), // ==> false
limit: propTypes.number.def(5), // ==> 5
fileSize: propTypes.number.def(5), // ==> 5M
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // ==> ["image/jpeg", "image/png", "image/gif"]
height: propTypes.string.def('150px'), // ==> 150px
width: propTypes.string.def('150px'), // ==> 150px
borderRadius: propTypes.string.def('8px') // ==> 8px
})
const uploadHeaders = ref({
Authorization: 'Bearer ' + getAccessToken(),
'tenant-id': getTenantId()
})
const fileList = ref<UploadUserFile[]>(props.modelValue)
/**
* @description 文件上传之前判断
* @param rawFile 上传的文件
* */
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
const imgType = props.fileType
if (!imgType.includes(rawFile.type as FileTypes))
ElNotification({
title: '温馨提示',
message: '上传图片不符合所需的格式!',
type: 'warning'
})
if (!imgSize)
ElNotification({
title: '温馨提示',
message: `上传图片大小不能超过 ${props.fileSize}M`,
type: 'warning'
})
return imgType.includes(rawFile.type as FileTypes) && imgSize
}
//
interface UploadEmits {
(e: 'update:modelValue', value: UploadUserFile[]): void
}
const emit = defineEmits<UploadEmits>()
const uploadSuccess = (response, uploadFile: UploadFile) => {
if (!response) return
uploadFile.url = response.data
emit('update:modelValue', fileList.value)
message.success('上传成功')
}
//
const handleRemove = (uploadFile: UploadFile) => {
fileList.value = fileList.value.filter(
(item) => item.url !== uploadFile.url || item.name !== uploadFile.name
)
emit('update:modelValue', fileList.value)
}
//
const uploadError = () => {
ElNotification({
title: '温馨提示',
message: '图片上传失败,请您重新上传!',
type: 'error'
})
}
//
const handleExceed = () => {
ElNotification({
title: '温馨提示',
message: `当前最多只能上传 ${props.limit} 张图片,请移除后上传!`,
type: 'warning'
})
}
//
const viewImageUrl = ref('')
const imgViewVisible = ref(false)
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
viewImageUrl.value = uploadFile.url!
imgViewVisible.value = true
}
</script>
<style scoped lang="scss">
.is-error {
.upload {
:deep(.el-upload--picture-card),
:deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important;
&:hover {
border-color: var(--el-color-primary) !important;
}
}
}
}
:deep(.disabled) {
.el-upload--picture-card,
.el-upload-dragger {
cursor: not-allowed;
background: var(--el-disabled-bg-color) !important;
border: 1px dashed var(--el-border-color-darker);
&:hover {
border-color: var(--el-border-color-darker) !important;
}
}
}
.upload-box {
.no-border {
:deep(.el-upload--picture-card) {
border: none !important;
}
}
:deep(.upload) {
.el-upload-dragger {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 0;
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderRadius);
&:hover {
border: 1px dashed var(--el-color-primary);
}
}
.el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important;
}
.el-upload-list__item,
.el-upload--picture-card {
width: v-bind(width);
height: v-bind(height);
background-color: transparent;
border-radius: v-bind(borderRadius);
}
.upload-image {
width: 100%;
height: 100%;
object-fit: contain;
}
.upload-handle {
position: absolute;
top: 0;
right: 0;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
cursor: pointer;
background: rgb(0 0 0 / 60%);
opacity: 0;
transition: var(--el-transition-duration-fast);
.handle-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 6%;
color: aliceblue;
.el-icon {
margin-bottom: 15%;
font-size: 140%;
}
span {
font-size: 100%;
}
}
}
.el-upload-list__item {
&:hover {
.upload-handle {
opacity: 1;
}
}
}
.upload-empty {
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
line-height: 30px;
color: var(--el-color-info);
.el-icon {
font-size: 28px;
color: var(--el-text-color-secondary);
}
}
}
.el-upload__tip {
line-height: 15px;
text-align: center;
}
}
</style>

View File

@ -44,7 +44,7 @@ export default {
}, },
upload: async <T = any>(option: any) => { upload: async <T = any>(option: any) => {
option.headersType = 'multipart/form-data' option.headersType = 'multipart/form-data'
const res = await request({ method: 'PUT', ...option }) const res = await request({ method: 'POST', ...option })
return res as unknown as Promise<T> return res as unknown as Promise<T>
} }
} }

View File

@ -1,6 +1,9 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { AxiosPromise } from 'axios'
import { findIndex } from '@/utils'
import { eachTree, treeMap, filter } from '@/utils/tree' import { eachTree, treeMap, filter } from '@/utils/tree'
import { getBoolDictOptions, getDictOptions, getIntDictOptions } from '@/utils/dict' import { getBoolDictOptions, getDictOptions, getIntDictOptions } from '@/utils/dict'
import { useI18n } from '@/hooks/web/useI18n'
import { FormSchema } from '@/types/form' import { FormSchema } from '@/types/form'
import { TableColumn } from '@/types/table' import { TableColumn } from '@/types/table'
import { DescriptionsSchema } from '@/types/descriptions' import { DescriptionsSchema } from '@/types/descriptions'
@ -23,6 +26,8 @@ export type CrudSchema = Omit<TableColumn, 'children'> & {
type CrudSearchParams = { type CrudSearchParams = {
// 是否显示在查询项 // 是否显示在查询项
show?: boolean show?: boolean
// 接口
api?: () => Promise<any>
} & Omit<FormSchema, 'field'> } & Omit<FormSchema, 'field'>
type CrudTableParams = { type CrudTableParams = {
@ -33,6 +38,8 @@ type CrudTableParams = {
type CrudFormParams = { type CrudFormParams = {
// 是否显示表单项 // 是否显示表单项
show?: boolean show?: boolean
// 接口
api?: () => Promise<any>
} & Omit<FormSchema, 'field'> } & Omit<FormSchema, 'field'>
type CrudDescriptionsParams = { type CrudDescriptionsParams = {
@ -47,6 +54,8 @@ interface AllSchemas {
detailSchema: DescriptionsSchema[] detailSchema: DescriptionsSchema[]
} }
const { t } = useI18n()
// 过滤所有结构 // 过滤所有结构
export const useCrudSchemas = ( export const useCrudSchemas = (
crudSchema: CrudSchema[] crudSchema: CrudSchema[]
@ -61,13 +70,13 @@ export const useCrudSchemas = (
detailSchema: [] detailSchema: []
}) })
const searchSchema = filterSearchSchema(crudSchema) const searchSchema = filterSearchSchema(crudSchema, allSchemas)
allSchemas.searchSchema = searchSchema || [] allSchemas.searchSchema = searchSchema || []
const tableColumns = filterTableSchema(crudSchema) const tableColumns = filterTableSchema(crudSchema)
allSchemas.tableColumns = tableColumns || [] allSchemas.tableColumns = tableColumns || []
const formSchema = filterFormSchema(crudSchema) const formSchema = filterFormSchema(crudSchema, allSchemas)
allSchemas.formSchema = formSchema allSchemas.formSchema = formSchema
const detailSchema = filterDescriptionsSchema(crudSchema) const detailSchema = filterDescriptionsSchema(crudSchema)
@ -79,9 +88,11 @@ export const useCrudSchemas = (
} }
// 过滤 Search 结构 // 过滤 Search 结构
const filterSearchSchema = (crudSchema: CrudSchema[]): FormSchema[] => { const filterSearchSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
const searchSchema: FormSchema[] = [] const searchSchema: FormSchema[] = []
// 获取字典列表队列
const searchRequestTask: Array<() => Promise<void>> = []
eachTree(crudSchema, (schemaItem: CrudSchema) => { eachTree(crudSchema, (schemaItem: CrudSchema) => {
// 判断是否显示 // 判断是否显示
if (schemaItem?.isSearch || schemaItem.search?.show) { if (schemaItem?.isSearch || schemaItem.search?.show) {
@ -107,12 +118,31 @@ const filterSearchSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
field: schemaItem.field, field: schemaItem.field,
label: schemaItem.search?.label || schemaItem.label label: schemaItem.search?.label || schemaItem.label
} }
if (searchSchemaItem.api) {
searchRequestTask.push(async () => {
const res = await (searchSchemaItem.api as () => AxiosPromise)()
if (res) {
const index = findIndex(allSchemas.searchSchema, (v: FormSchema) => {
return v.field === searchSchemaItem.field
})
if (index !== -1) {
allSchemas.searchSchema[index]!.componentProps!.options = filterOptions(
res,
searchSchemaItem.componentProps.optionsAlias?.labelField
)
}
}
})
}
// 删除不必要的字段 // 删除不必要的字段
delete searchSchemaItem.show delete searchSchemaItem.show
searchSchema.push(searchSchemaItem) searchSchema.push(searchSchemaItem)
} }
}) })
for (const task of searchRequestTask) {
task()
}
return searchSchema return searchSchema
} }
@ -139,9 +169,12 @@ const filterTableSchema = (crudSchema: CrudSchema[]): TableColumn[] => {
} }
// 过滤 form 结构 // 过滤 form 结构
const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => { const filterFormSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
const formSchema: FormSchema[] = [] const formSchema: FormSchema[] = []
// 获取字典列表队列
const formRequestTask: Array<() => Promise<void>> = []
eachTree(crudSchema, (schemaItem: CrudSchema) => { eachTree(crudSchema, (schemaItem: CrudSchema) => {
// 判断是否显示 // 判断是否显示
if (schemaItem?.isForm !== false && schemaItem?.form?.show !== false) { if (schemaItem?.isForm !== false && schemaItem?.form?.show !== false) {
@ -185,6 +218,23 @@ const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
label: schemaItem.form?.label || schemaItem.label label: schemaItem.form?.label || schemaItem.label
} }
if (formSchemaItem.api) {
formRequestTask.push(async () => {
const res = await (formSchemaItem.api as () => AxiosPromise)()
if (res) {
const index = findIndex(allSchemas.formSchema, (v: FormSchema) => {
return v.field === formSchemaItem.field
})
if (index !== -1) {
allSchemas.formSchema[index]!.componentProps!.options = filterOptions(
res,
formSchemaItem.componentProps.optionsAlias?.labelField
)
}
}
})
}
// 删除不必要的字段 // 删除不必要的字段
delete formSchemaItem.show delete formSchemaItem.show
@ -192,6 +242,9 @@ const filterFormSchema = (crudSchema: CrudSchema[]): FormSchema[] => {
} }
}) })
for (const task of formRequestTask) {
task()
}
return formSchema return formSchema
} }
@ -225,3 +278,15 @@ const filterDescriptionsSchema = (crudSchema: CrudSchema[]): DescriptionsSchema[
return descriptionsSchema return descriptionsSchema
} }
// 给options添加国际化
const filterOptions = (options: Recordable, labelField?: string) => {
return options.map((v: Recordable) => {
if (labelField) {
v['labelField'] = t(v.labelField)
} else {
v['label'] = t(v.label)
}
return v
})
}

View File

@ -63,7 +63,7 @@ type CrudDescriptionsParams = {
} & Omit<DescriptionsSchema, 'field'> } & Omit<DescriptionsSchema, 'field'>
type CrudPrintParams = { type CrudPrintParams = {
// 是否显示表单 // 是否显示打印
show?: boolean show?: boolean
} & Omit<VxeTableDefines.ColumnInfo[], 'field'> } & Omit<VxeTableDefines.ColumnInfo[], 'field'>

View File

@ -53,7 +53,8 @@ export default defineComponent({
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}> <ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
{meta?.icon && breadcrumbIcon.value ? ( {meta?.icon && breadcrumbIcon.value ? (
<> <>
<Icon icon={meta.icon} class="mr-[5px]"></Icon> {t(v?.meta?.title)} <Icon icon={meta.icon} class="mr-[2px]" svgClass="inline-block"></Icon>
{t(v?.meta?.title)}
</> </>
) : ( ) : (
t(v?.meta?.title) t(v?.meta?.title)

View File

@ -55,31 +55,33 @@ watch(
</script> </script>
<template> <template>
<router-link <div>
:class="[ <router-link
prefixCls,
layout !== 'classic' ? `${prefixCls}__Top` : '',
'flex !h-[var(--logo-height)] items-center cursor-pointer justify-center relative',
'dark:bg-[var(--el-bg-color)]'
]"
to="/"
>
<img
src="@/assets/imgs/logo.png"
class="w-[calc(var(--logo-height)-10px)] h-[calc(var(--logo-height)-10px)]"
/>
<div
v-if="show"
:class="[ :class="[
'ml-10px text-16px font-700', prefixCls,
{ layout !== 'classic' ? `${prefixCls}__Top` : '',
'text-[var(--logo-title-text-color)]': layout === 'classic', 'flex !h-[var(--logo-height)] items-center cursor-pointer justify-center relative',
'text-[var(--top-header-text-color)]': 'dark:bg-[var(--el-bg-color)]'
layout === 'topLeft' || layout === 'top' || layout === 'cutMenu'
}
]" ]"
to="/"
> >
{{ title }} <img
</div> src="@/assets/imgs/logo.png"
</router-link> class="w-[calc(var(--logo-height)-10px)] h-[calc(var(--logo-height)-10px)]"
/>
<div
v-if="show"
:class="[
'ml-10px text-16px font-700',
{
'text-[var(--logo-title-text-color)]': layout === 'classic',
'text-[var(--top-header-text-color)]':
layout === 'topLeft' || layout === 'top' || layout === 'cutMenu'
}
]"
>
{{ title }}
</div>
</router-link>
</div>
</template> </template>

View File

@ -161,6 +161,7 @@ $prefix-cls: #{$namespace}-menu;
// //
.#{$elNamespace}-sub-menu__title, .#{$elNamespace}-sub-menu__title,
.#{$elNamespace}-menu-item { .#{$elNamespace}-menu-item {
height: 59px;
&:hover { &:hover {
color: var(--left-menu-text-active-color) !important; color: var(--left-menu-text-active-color) !important;
background-color: var(--left-menu-bg-color) !important; background-color: var(--left-menu-bg-color) !important;
@ -170,6 +171,7 @@ $prefix-cls: #{$namespace}-menu;
// //
.#{$elNamespace}-sub-menu.is-active, .#{$elNamespace}-sub-menu.is-active,
.#{$elNamespace}-menu-item.is-active { .#{$elNamespace}-menu-item.is-active {
height: 59px;
color: var(--left-menu-text-active-color) !important; color: var(--left-menu-text-active-color) !important;
background-color: var(--left-menu-bg-active-color) !important; background-color: var(--left-menu-bg-active-color) !important;

View File

@ -426,5 +426,19 @@ export default {
cfPwdMsg: 'Please Enter Confirm Password', cfPwdMsg: 'Please Enter Confirm Password',
diffPwd: 'The Passwords Entered Twice No Match' diffPwd: 'The Passwords Entered Twice No Match'
} }
},
cropper: {
selectImage: 'Select Image',
uploadSuccess: 'Uploaded success!',
modalTitle: 'Avatar upload',
okText: 'Confirm and upload',
btn_reset: 'Reset',
btn_rotate_left: 'Counterclockwise rotation',
btn_rotate_right: 'Clockwise rotation',
btn_scale_x: 'Flip horizontal',
btn_scale_y: 'Flip vertical',
btn_zoom_in: 'Zoom in',
btn_zoom_out: 'Zoom out',
preview: 'Preivew'
} }
} }

View File

@ -419,5 +419,19 @@ export default {
pwdRules: '长度在 6 到 20 个字符', pwdRules: '长度在 6 到 20 个字符',
diffPwd: '两次输入密码不一致' diffPwd: '两次输入密码不一致'
} }
},
cropper: {
selectImage: '选择图片',
uploadSuccess: '上传成功',
modalTitle: '头像上传',
okText: '确认并上传',
btn_reset: '重置',
btn_rotate_left: '逆时针旋转',
btn_rotate_right: '顺时针旋转',
btn_scale_x: '水平翻转',
btn_scale_y: '垂直翻转',
btn_zoom_in: '放大',
btn_zoom_out: '缩小',
preview: '预览'
} }
} }

View File

@ -56,7 +56,7 @@ watch(
import('./theme/light.scss') import('./theme/light.scss')
} }
}, },
{ immediate: true } { deep: true }
) )
// 全局默认参数 // 全局默认参数
VXETable.setup({ VXETable.setup({

View File

@ -14,7 +14,7 @@ import { usePermissionStoreWithOut } from '@/store/modules/permission'
import { getInfoApi } from '@/api/login' import { getInfoApi } from '@/api/login'
import { listSimpleDictDataApi } from '@/api/system/dict/dict.data' import { listSimpleDictDataApi } from '@/api/system/dict/dict.data'
const { wsCache } = useCache('sessionStorage') const { wsCache } = useCache()
const { start, done } = useNProgress() const { start, done } = useNProgress()

View File

@ -64,7 +64,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
meta: { meta: {
title: t('router.home'), title: t('router.home'),
icon: 'ep:home-filled', icon: 'ep:home-filled',
noCache: true, noCache: false,
affix: true affix: true
} }
} }
@ -85,7 +85,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
meta: { meta: {
canTo: true, canTo: true,
hidden: true, hidden: true,
noTagsView: true, noTagsView: false,
icon: 'ep:user', icon: 'ep:user',
title: t('common.profile') title: t('common.profile')
} }

View File

@ -22,6 +22,7 @@ export type ComponentName =
| 'InputPassword' | 'InputPassword'
| 'Editor' | 'Editor'
| 'UploadImg' | 'UploadImg'
| 'UploadImgs'
| 'UploadFile' | 'UploadFile'
export type ColProps = { export type ColProps = {

View File

@ -69,7 +69,7 @@ export const trim = (str: string) => {
* @param {Date | number | string} time * @param {Date | number | string} time
* @param {String} fmt yyyy-MM-ddyyyy-MM-dd HH:mm:ss * @param {String} fmt yyyy-MM-ddyyyy-MM-dd HH:mm:ss
*/ */
export function formatTime(time: Date | number | string, fmt: string) { export const formatTime = (time: Date | number | string, fmt: string) => {
if (!time) return '' if (!time) return ''
else { else {
const date = new Date(time) const date = new Date(time)
@ -100,7 +100,7 @@ export function formatTime(time: Date | number | string, fmt: string) {
/** /**
* *
*/ */
export function toAnyString() { export const toAnyString = () => {
const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => { const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => {
const r: number = (Math.random() * 16) | 0 const r: number = (Math.random() * 16) | 0
const v: number = c === 'x' ? r : (r & 0x3) | 0x8 const v: number = c === 'x' ? r : (r & 0x3) | 0x8
@ -108,3 +108,34 @@ export function toAnyString() {
}) })
return str return str
} }
export const generateUUID = () => {
if (typeof crypto === 'object') {
if (typeof crypto.randomUUID === 'function') {
return crypto.randomUUID()
}
if (typeof crypto.getRandomValues === 'function' && typeof Uint8Array === 'function') {
const callback = (c: any) => {
const num = Number(c)
return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(
16
)
}
return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, callback)
}
}
let timestamp = new Date().getTime()
let performanceNow =
(typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
let random = Math.random() * 16
if (timestamp > 0) {
random = (timestamp + random) % 16 | 0
timestamp = Math.floor(timestamp / 16)
} else {
random = (performanceNow + random) % 16 | 0
performanceNow = Math.floor(performanceNow / 16)
}
return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16)
})
}

View File

@ -56,7 +56,13 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord
title: route.name, title: route.name,
icon: route.icon, icon: route.icon,
hidden: !route.visible, hidden: !route.visible,
noCache: !route.keepAlive noCache: !route.keepAlive,
alwaysShow:
route.children &&
route.children.length === 1 &&
import.meta.env.VITE_ROUTE_ALWAYSSHOW_ENABLE === 'true'
? true
: false
} }
// 路由地址转首字母大写驼峰作为路由名称适配keepAlive // 路由地址转首字母大写驼峰作为路由名称适配keepAlive
let data: AppRouteRecordRaw = { let data: AppRouteRecordRaw = {
@ -71,6 +77,7 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord
data.meta = {} data.meta = {}
data.name = toCamelCase(route.path, true) + 'Parent' data.name = toCamelCase(route.path, true) + 'Parent'
data.redirect = '' data.redirect = ''
meta.alwaysShow = true
const childrenData: AppRouteRecordRaw = { const childrenData: AppRouteRecordRaw = {
path: '', path: '',
name: toCamelCase(route.path, true), name: toCamelCase(route.path, true),

View File

@ -1,245 +1,40 @@
<template> <template>
<div class="user-info-head" @click="editCropper()"> <div class="change-avatar">
<img :src="props.img" title="点击上传头像" class="img-circle img-lg" alt="" /> <CropperAvatar
ref="cropperRef"
:value="avatar"
:showBtn="false"
@change="handelUpload"
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
width="120px"
/>
</div> </div>
<el-dialog
v-model="dialogVisible"
title="编辑头像"
:mask-closable="false"
width="800px"
append-to-body
@opened="cropperVisible = true"
>
<el-row>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<VueCropper
ref="cropper"
v-if="cropperVisible"
:img="options.img"
:info="true"
:infoTrue="options.infoTrue"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedNumber="options.fixedNumber"
:fixedBox="options.fixedBox"
:centerBox="options.centerBox"
@real-time="realTime"
/>
</el-col>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<div
class="avatar-upload-preview"
:style="{
width: previews.w + 'px',
height: previews.h + 'px',
overflow: 'hidden',
margin: '5px'
}"
>
<div :style="previews.div">
<img :src="previews.url" :style="previews.img" style="!max-width: 100%" alt="" />
</div>
</div>
</el-col>
</el-row>
<template #footer>
<el-row>
<el-col :lg="2" :md="2">
<el-upload
action="#"
:http-request="requestUpload"
:show-file-list="false"
:before-upload="beforeUpload"
>
<el-button size="small">
<Icon icon="ep:upload-filled" class="mr-5px" />
选择
</el-button>
</el-upload>
</el-col>
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
<el-button size="small" @click="changeScale(1)">
<Icon icon="ep:zoom-in" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button size="small" @click="changeScale(-1)">
<Icon icon="ep:zoom-out" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button size="small" @click="rotateLeft()">
<Icon icon="ep:arrow-left-bold" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button size="small" @click="rotateRight()">
<Icon icon="ep:arrow-right-bold" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
<el-button size="small" type="primary" @click="uploadImg()"> </el-button>
</el-col>
</el-row>
</template>
</el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, watch, Ref, UnwrapNestedRefs } from 'vue' import { computed, ref } from 'vue'
import VueCropper from 'vue-cropper/lib/vue-cropper.vue'
import 'vue-cropper/dist/index.css'
import { ElRow, ElCol, ElUpload, ElMessage, ElDialog } from 'element-plus'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { CropperAvatar } from '@/components/Cropper'
import { uploadAvatarApi } from '@/api/system/user/profile' import { uploadAvatarApi } from '@/api/system/user/profile'
const cropper = ref()
const dialogVisible = ref(false)
const cropperVisible = ref(false)
const props = defineProps({ const props = defineProps({
img: propTypes.string.def('') img: propTypes.string.def('')
}) })
interface Options { const avatar = computed(() => {
img: string | ArrayBuffer | null // return props.img
info: true //
outputSize: number // [10.1]
outputType: 'jpeg' //
canScale: boolean //
autoCrop: boolean //
autoCropWidth: number //
autoCropHeight: number //
fixedBox: boolean //
fixed: boolean //
fixedNumber: Array<number> // centerBox使
full: boolean //
canMoveBox: boolean //
original: boolean //
centerBox: boolean //
infoTrue: boolean // true false
}
const options: UnwrapNestedRefs<Options> = reactive({
img: '', //
autoCrop: true, //
autoCropWidth: 200, //
autoCropHeight: 200, //
fixedBox: false, //
info: true, //
outputSize: 1, // [10.1]
outputType: 'jpeg', //
canScale: false, //
fixed: true, //
fixedNumber: [1, 1], // centerBox使
full: true, //
canMoveBox: false, //
original: false, //
centerBox: true, //
infoTrue: true // true false
}) })
const previews: Ref<any> = ref({})
/** 编辑头像 */ const cropperRef = ref()
const editCropper = () => { const handelUpload = async ({ data }) => {
dialogVisible.value = true await uploadAvatarApi({ avatarFile: data })
cropperRef.value.close()
} }
/** 向左旋转 */
const rotateLeft = () => {
cropper.value.rotateLeft()
}
/** 向右旋转 */
const rotateRight = () => {
cropper.value.rotateRight()
}
/** 图片缩放 */
const changeScale = (num: number) => {
num = num || 1
cropper.value.changeScale(num)
}
//
const requestUpload: any = () => {}
/** 上传预处理 */
const beforeUpload = (file: Blob) => {
if (file.type.indexOf('image/') == -1) {
ElMessage('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。')
} else {
const reader = new FileReader()
// base64
reader.readAsDataURL(file)
reader.onload = () => {
if (reader.result) {
//
options.img = reader.result as string
}
return false
}
}
}
/** 上传图片 */
const uploadImg = () => {
cropper.value.getCropBlob((data: any) => {
let formData = new FormData()
formData.append('avatarFile', data)
uploadAvatarApi(formData).then((res) => {
options.img = res
window.location.reload()
})
dialogVisible.value = false
cropperVisible.value = false
})
}
/** 实时预览 */
const realTime = (data: any) => {
previews.value = data
}
watch(
() => props.img,
() => {
if (props.img) {
options.img = props.img
previews.value.img = props.img
previews.value.url = props.img
}
}
)
</script> </script>
<style scoped> <style scoped lang="scss">
.user-info-head { .change-avatar {
position: relative; img {
display: inline-block; display: block;
} margin-bottom: 15px;
.img-circle { border-radius: 50%;
border-radius: 50%; }
}
.img-lg {
width: 120px;
height: 120px;
}
.avatar-upload-preview {
position: absolute;
top: 50%;
-webkit-transform: translate(50%, -50%);
transform: translate(50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
-webkit-box-shadow: 0 0 4px #ccc;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
}
.user-info-head:hover:after {
content: '+';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background: rgba(0, 0, 0, 0.5);
font-size: 24px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
line-height: 110px;
border-radius: 50%;
} }
</style> </style>

View File

@ -95,9 +95,8 @@ const handleProcessClick = (
message message
.confirm('确认标记为' + type + '?', t('common.reminder')) .confirm('确认标记为' + type + '?', t('common.reminder'))
.then(async () => { .then(async () => {
ApiErrorLogApi.updateApiErrorLogPageApi(row.id, processSttatus).then(() => { await ApiErrorLogApi.updateApiErrorLogPageApi(row.id, processSttatus)
message.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
})
}) })
.finally(async () => { .finally(async () => {
// //

View File

@ -64,8 +64,8 @@
<el-form-item label="存储器" prop="storage"> <el-form-item label="存储器" prop="storage">
<el-select v-model="form.storage" placeholder="请选择存储器" :disabled="form.id !== 0"> <el-select v-model="form.storage" placeholder="请选择存储器" :disabled="form.id !== 0">
<el-option <el-option
v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_FILE_STORAGE)" v-for="(dict, index) in getIntDictOptions(DICT_TYPE.INFRA_FILE_STORAGE)"
:key="dict.value" :key="index"
:label="dict.label" :label="dict.label"
:value="dict.value" :value="dict.value"
/> />
@ -197,7 +197,7 @@ const dialogVisible = ref(false) // 是否显示弹出层
const dialogTitle = ref('edit') // const dialogTitle = ref('edit') //
const formRef = ref<FormInstance>() // Ref const formRef = ref<FormInstance>() // Ref
const detailData = ref() // Ref const detailData = ref() // Ref
let form = ref<FileConfigApi.FileConfigVO>({ const form = ref<FileConfigApi.FileConfigVO>({
id: 0, id: 0,
name: '', name: '',
storage: 0, storage: 0,
@ -230,6 +230,28 @@ const setDialogTile = (type: string) => {
const handleCreate = (formEl: FormInstance | undefined) => { const handleCreate = (formEl: FormInstance | undefined) => {
setDialogTile('create') setDialogTile('create')
formEl?.resetFields() formEl?.resetFields()
form.value = {
id: 0,
name: '',
storage: 0,
master: false,
visible: false,
config: {
basePath: '',
host: '',
port: 0,
username: '',
password: '',
mode: '',
endpoint: '',
bucket: '',
accessKey: '',
accessSecret: '',
domain: ''
},
remark: '',
createTime: new Date()
}
} }
// //

View File

@ -12,8 +12,7 @@ export const rules = reactive({
email: [required], email: [required],
phone: [ phone: [
{ {
min: 11, len: 11,
max: 11,
trigger: 'blur', trigger: 'blur',
message: '请输入正确的手机号码' message: '请输入正确的手机号码'
} }

View File

@ -75,16 +75,15 @@
</XModal> </XModal>
</template> </template>
<script setup lang="ts" name="Dept"> <script setup lang="ts" name="Dept">
import { nextTick, onMounted, reactive, ref, unref } from 'vue' import { nextTick, onMounted, ref, unref } from 'vue'
import { ElSelect, ElTreeSelect, ElOption } from 'element-plus' import { ElSelect, ElTreeSelect, ElOption } from 'element-plus'
import { VxeGridInstance } from 'vxe-table' import { VxeGridInstance } from 'vxe-table'
import { handleTree, defaultProps } from '@/utils/tree' import { handleTree, defaultProps } from '@/utils/tree'
import { required } from '@/utils/formRules.js'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage' import { useMessage } from '@/hooks/web/useMessage'
import { useVxeGrid } from '@/hooks/web/useVxeGrid' import { useVxeGrid } from '@/hooks/web/useVxeGrid'
import { FormExpose } from '@/components/Form' import { FormExpose } from '@/components/Form'
import { allSchemas } from './dept.data' import { allSchemas, rules } from './dept.data'
import * as DeptApi from '@/api/system/dept' import * as DeptApi from '@/api/system/dept'
import { getListSimpleUsersApi, UserVO } from '@/api/system/user' import { getListSimpleUsersApi, UserVO } from '@/api/system/user'
@ -107,13 +106,6 @@ const actionLoading = ref(false) // 遮罩层
const formRef = ref<FormExpose>() // Ref const formRef = ref<FormExpose>() // Ref
const deptOptions = ref() // const deptOptions = ref() //
const userOption = ref<UserVO[]>([]) const userOption = ref<UserVO[]>([])
//
const rules = reactive({
name: [required],
sort: [required],
path: [required],
status: [required]
})
const getUserList = async () => { const getUserList = async () => {
const res = await getListSimpleUsersApi() const res = await getListSimpleUsersApi()

View File

@ -1,34 +1,8 @@
<template> <template>
<ContentWrap> <ContentWrap>
<!-- 搜索工作栏 --> <!-- 列表 -->
<el-form :model="queryParams" ref="queryForm" :inline="true"> <vxe-grid ref="xGrid" v-bind="gridOptions" show-overflow class="xtable-scrollbar">
<el-form-item label="菜单名称" prop="name"> <template #toolbar_buttons>
<el-input v-model="queryParams.name" placeholder="请输入菜单名称" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择菜单状态">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<!-- 操作搜索 -->
<XButton
type="primary"
preIcon="ep:search"
:title="t('common.query')"
@click="handleQuery()"
/>
<!-- 操作重置 -->
<XButton preIcon="ep:refresh-right" :title="t('common.reset')" @click="resetQuery()" />
</el-form-item>
</el-form>
<vxe-toolbar>
<template #buttons>
<!-- 操作新增 --> <!-- 操作新增 -->
<XButton <XButton
type="primary" type="primary"
@ -37,63 +11,30 @@
v-hasPermi="['system:menu:create']" v-hasPermi="['system:menu:create']"
@click="handleCreate()" @click="handleCreate()"
/> />
<XButton title="展开所有" @click="xTable?.setAllTreeExpand(true)" /> <XButton title="展开所有" @click="xGrid?.setAllTreeExpand(true)" />
<XButton title="关闭所有" @click="xTable?.clearTreeExpand()" /> <XButton title="关闭所有" @click="xGrid?.clearTreeExpand()" />
</template> </template>
</vxe-toolbar> <template #name_default="{ row }">
<!-- 列表 --> <Icon :icon="row.icon" />
<vxe-table <span class="ml-3">{{ row.name }}</span>
show-overflow </template>
keep-source <template #actionbtns_default="{ row }">
ref="xTable" <!-- 操作修改 -->
:loading="tableLoading" <XTextButton
:row-config="{ keyField: 'id' }" preIcon="ep:edit"
:column-config="{ resizable: true }" :title="t('action.edit')"
:tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }" v-hasPermi="['system:menu:update']"
:print-config="{}" @click="handleUpdate(row.id)"
:export-config="{}" />
:data="tableData" <!-- 操作删除 -->
> <XTextButton
<vxe-column title="菜单名称" field="name" width="200" tree-node> preIcon="ep:delete"
<template #default="{ row }"> :title="t('action.del')"
<Icon :icon="row.icon" /> v-hasPermi="['system:menu:delete']"
<span class="ml-3">{{ row.name }}</span> @click="handleDelete(row.id)"
</template> />
</vxe-column> </template>
<vxe-column title="菜单类型" field="type"> </vxe-grid>
<template #default="{ row }">
<DictTag :type="DICT_TYPE.SYSTEM_MENU_TYPE" :value="row.type" />
</template>
</vxe-column>
<vxe-column title="路由地址" field="path" />
<vxe-column title="组件路径" field="component" />
<vxe-column title="权限标识" field="permission" />
<vxe-column title="排序" field="sort" />
<vxe-column title="状态" field="status">
<template #default="{ row }">
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />
</template>
</vxe-column>
<vxe-column title="创建时间" field="createTime" formatter="formatDate" />
<vxe-column title="操作" width="200">
<template #default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['system:menu:update']"
@click="handleUpdate(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['system:menu:delete']"
@click="handleDelete(row.id)"
/>
</template>
</vxe-column>
</vxe-table>
</ContentWrap> </ContentWrap>
<!-- 添加或修改菜单对话框 --> <!-- 添加或修改菜单对话框 -->
<XModal id="menuModel" v-model="dialogVisible" :title="dialogTitle"> <XModal id="menuModel" v-model="dialogVisible" :title="dialogTitle">
@ -124,7 +65,7 @@
<el-radio-group v-model="menuForm.type"> <el-radio-group v-model="menuForm.type">
<el-radio-button <el-radio-button
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_MENU_TYPE)" v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_MENU_TYPE)"
:key="dict.value" :key="dict.label"
:label="dict.value" :label="dict.value"
> >
{{ dict.label }} {{ dict.label }}
@ -178,7 +119,7 @@
<el-radio <el-radio
border border
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :key="dict.label"
:label="dict.value" :label="dict.value"
> >
{{ dict.label }} {{ dict.label }}
@ -235,7 +176,7 @@
</template> </template>
<script setup lang="ts" name="Menu"> <script setup lang="ts" name="Menu">
// import // import
import { onMounted, reactive, ref } from 'vue' import { ref } from 'vue'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache' import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import { useMessage } from '@/hooks/web/useMessage' import { useMessage } from '@/hooks/web/useMessage'
@ -245,9 +186,7 @@ import {
ElFormItem, ElFormItem,
ElInput, ElInput,
ElInputNumber, ElInputNumber,
ElSelect,
ElTreeSelect, ElTreeSelect,
ElOption,
ElRadio, ElRadio,
ElRadioGroup, ElRadioGroup,
ElRadioButton, ElRadioButton,
@ -255,21 +194,33 @@ import {
} from 'element-plus' } from 'element-plus'
import { Tooltip } from '@/components/Tooltip' import { Tooltip } from '@/components/Tooltip'
import { IconSelect } from '@/components/Icon' import { IconSelect } from '@/components/Icon'
import { VxeTableInstance } from 'vxe-table' import { VxeGridInstance } from 'vxe-table'
// import // import
import * as MenuApi from '@/api/system/menu'
import { required } from '@/utils/formRules.js'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants' import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
import { handleTree, defaultProps } from '@/utils/tree' import { handleTree, defaultProps } from '@/utils/tree'
import * as MenuApi from '@/api/system/menu'
import { allSchemas, rules } from './menu.data'
import { useVxeGrid } from '@/hooks/web/useVxeGrid'
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
const { wsCache } = useCache() const { wsCache } = useCache()
// //
const xTable = ref<VxeTableInstance>() //
const tableLoading = ref(false) const xGrid = ref<VxeGridInstance>() // Grid Ref
const tableData = ref() const treeConfig = {
transform: true,
rowField: 'id',
parentField: 'parentId',
expandAll: false
}
const { gridOptions, getList, deleteData } = useVxeGrid<MenuApi.MenuVO>({
allSchemas: allSchemas,
treeConfig: treeConfig,
getListApi: MenuApi.getMenuListApi,
deleteApi: MenuApi.deleteMenuApi
})
// //
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('edit') // const dialogTitle = ref('edit') //
@ -292,13 +243,6 @@ const menuForm = ref<MenuApi.MenuVO>({
keepAlive: true, keepAlive: true,
createTime: new Date() createTime: new Date()
}) })
//
const rules = reactive({
name: [required],
sort: [required],
path: [required],
status: [required]
})
// ========== [] ========== // ========== [] ==========
const menuOptions = ref<any[]>([]) // const menuOptions = ref<any[]>([]) //
@ -311,31 +255,6 @@ const getTree = async () => {
menuOptions.value.push(menu) menuOptions.value.push(menu)
} }
// ========== ==========
const queryParams = reactive<MenuApi.MenuPageReqVO>({
name: undefined,
status: undefined
})
//
const getList = async () => {
tableLoading.value = true
const res = await MenuApi.getMenuListApi(queryParams)
tableData.value = res
tableLoading.value = false
}
//
const handleQuery = async () => {
await getList()
}
//
const resetQuery = async () => {
queryParams.name = undefined
queryParams.status = undefined
await getList()
}
// ========== / ========== // ========== / ==========
// //
@ -407,7 +326,7 @@ const submitForm = async () => {
actionLoading.value = false actionLoading.value = false
wsCache.delete(CACHE_KEY.ROLE_ROUTERS) wsCache.delete(CACHE_KEY.ROLE_ROUTERS)
// //
await getList() await getList(xGrid)
} }
} }
@ -419,15 +338,6 @@ const isExternal = (path: string) => {
// ========== ========== // ========== ==========
// //
const handleDelete = async (rowId: number) => { const handleDelete = async (rowId: number) => {
message.delConfirm().then(async () => { await deleteData(xGrid, rowId)
await MenuApi.deleteMenuApi(rowId)
message.success(t('common.delSuccess'))
await getList()
})
} }
// ========== ==========
onMounted(async () => {
await getList()
})
</script> </script>

View File

@ -0,0 +1,75 @@
import { reactive } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { DICT_TYPE } from '@/utils/dict'
import { required } from '@/utils/formRules'
import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 新增和修改的表单校验
export const rules = reactive({
name: [required],
sort: [required],
path: [required],
status: [required]
})
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: null,
action: true,
columns: [
{
title: '上级菜单',
field: 'parentId',
isTable: false
},
{
title: '菜单名称',
field: 'name',
isSearch: true,
table: {
treeNode: true,
align: 'left',
width: '200px',
slots: {
default: 'name_default'
}
}
},
{
title: '菜单类型',
field: 'type',
dictType: DICT_TYPE.SYSTEM_MENU_TYPE
},
{
title: '路由地址',
field: 'path'
},
{
title: '组件路径',
field: 'component'
},
{
title: '权限标识',
field: 'permission'
},
{
title: '排序',
field: 'sort'
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate'
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -53,7 +53,7 @@
:data="detailData" :data="detailData"
> >
<template #content="{ row }"> <template #content="{ row }">
<Editor :model-value="row.content" read-only="true" /> <Editor :model-value="row.content" :readonly="true" />
</template> </template>
</Descriptions> </Descriptions>
<template #footer> <template #footer>

View File

@ -43,10 +43,7 @@ const crudSchemas = reactive<VxeCrudSchema>({
} }
}, },
form: { form: {
component: 'UploadImg', component: 'UploadImg'
componentProps: {
limit: 1
}
} }
}, },
{ {

View File

@ -145,7 +145,7 @@
v-for="item in postOptions" v-for="item in postOptions"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item.id" :value="(item.id as unknown as number)"
/> />
</el-select> </el-select>
</template> </template>

View File

@ -10,12 +10,10 @@ export const rules = reactive({
username: [required], username: [required],
nickname: [required], nickname: [required],
email: [required], email: [required],
postIds: [required],
status: [required], status: [required],
mobile: [ mobile: [
{ {
min: 11, len: 11,
max: 11,
trigger: 'blur', trigger: 'blur',
message: '请输入正确的手机号码' message: '请输入正确的手机号码'
} }

View File

@ -24,7 +24,7 @@
"@/*": ["src/*"] "@/*": ["src/*"]
}, },
"types": [ "types": [
"@intlify/vite-plugin-vue-i18n/client", "@intlify/unplugin-vue-i18n/types",
"vite/client", "vite/client",
"element-plus/global", "element-plus/global",
"@types/intro.js", "@types/intro.js",

View File

@ -10,7 +10,8 @@ declare module '*.vue' {
interface ImportMetaEnv { interface ImportMetaEnv {
readonly VITE_APP_TITLE: string readonly VITE_APP_TITLE: string
readonly VITE_PORT: number readonly VITE_PORT: number
readonly VITE_OPEN: boolean readonly VITE_OPEN: string
readonly VITE_ROUTE_ALWAYSSHOW_ENABLE: string
readonly VITE_APP_CAPTCHA_ENABLE: string readonly VITE_APP_CAPTCHA_ENABLE: string
readonly VITE_APP_TENANT_ENABLE: string readonly VITE_APP_TENANT_ENABLE: string
readonly VITE_BASE_URL: string readonly VITE_BASE_URL: string

View File

@ -30,7 +30,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
// 端口号 // 端口号
port: env.VITE_PORT, port: env.VITE_PORT,
host: "0.0.0.0", host: "0.0.0.0",
open: env.VITE_OPEN, open: env.VITE_OPEN === 'true',
// 本地跨域代理 // 本地跨域代理
proxy: { proxy: {
['/admin-api']: { ['/admin-api']: {