From 2a702fa6a963054d4fcdcb4a4439d112a2dc2aa1 Mon Sep 17 00:00:00 2001 From: gin Date: Tue, 26 May 2026 11:54:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20app=E5=8A=9F=E8=83=BD=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 12 + .gitignore | 3 +- README.md | 265 ++-- backend/.dockerignore | 12 + backend/Dockerfile | 19 + .../controller/app/AppAuthController.java | 84 ++ .../app/AppCollaborationRecordController.java | 90 ++ .../controller/app/AppProfileController.java | 56 + .../controller/common/FileController.java | 5 +- .../controller/common/LoginController.java | 25 +- .../controller/system/SysDeptController.java | 111 -- .../controller/system/SysPostController.java | 122 -- .../system/SysProfileController.java | 3 +- .../controller/system/SysRoleController.java | 16 - .../controller/system/SysUserController.java | 4 +- .../customize/config/SecurityConfig.java | 1 + .../customize/service/login/LoginService.java | 34 + .../service/login/UserDetailsServiceImpl.java | 15 +- .../service/login/dto/ConfigDTO.java | 2 + .../DataPermissionCheckerFactory.java | 27 +- .../permission/DataPermissionService.java | 12 +- .../model/AbstractDataPermissionChecker.java | 3 - .../permission/model/DataCondition.java | 1 - .../checker/AllDataPermissionChecker.java | 4 - .../checker/CustomDataPermissionChecker.java | 42 - .../checker/DefaultDataPermissionChecker.java | 3 - .../DeptTreeDataPermissionChecker.java | 44 - .../OnlySelfDataPermissionChecker.java | 5 - .../SingleDeptDataPermissionChecker.java | 42 - .../src/main/resources/application-dev.yml | 4 +- .../src/main/resources/application-prod.yml | 65 + .../CustomDataPermissionCheckerTest.java | 83 -- .../DeptTreeDataPermissionCheckerTest.java | 92 -- .../OnlySelfDataPermissionCheckerTest.java | 12 +- .../SingleDeptDataPermissionCheckerTest.java | 72 -- .../common/exception/error/ErrorCode.java | 32 +- ...CollaborationRecordApplicationService.java | 161 ++- .../record/enumtype/SettlementStatusEnum.java | 30 + .../model/CollaborationRecordModel.java | 2 +- .../query/CollaborationRecordQuery.java | 4 + .../domain/common/cache/CacheCenter.java | 8 - .../common/cache/GuavaCacheService.java | 12 - .../common/cache/RedisCacheService.java | 14 - .../domain/common/dto/TreeSelectedDTO.java | 1 - .../system/dept/DeptApplicationService.java | 88 -- .../system/dept/command/AddDeptCommand.java | 58 - .../dept/command/UpdateDeptCommand.java | 19 - .../domain/system/dept/db/SysDeptEntity.java | 75 -- .../domain/system/dept/db/SysDeptMapper.java | 15 - .../domain/system/dept/db/SysDeptService.java | 50 - .../system/dept/db/SysDeptServiceImpl.java | 62 - .../domain/system/dept/dto/DeptDTO.java | 51 - .../domain/system/dept/model/DeptModel.java | 106 -- .../system/dept/model/DeptModelFactory.java | 45 - .../domain/system/dept/query/DeptQuery.java | 36 - .../system/log/db/SysOperationLogEntity.java | 8 - .../system/log/dto/OperationLogDTO.java | 6 - .../system/menu/MenuApplicationService.java | 4 +- .../system/monitor/dto/OnlineUserDTO.java | 13 - .../system/post/PostApplicationService.java | 85 -- .../system/post/command/AddPostCommand.java | 37 - .../post/command/UpdatePostCommand.java | 19 - .../domain/system/post/db/SysPostEntity.java | 60 - .../domain/system/post/db/SysPostMapper.java | 15 - .../domain/system/post/db/SysPostService.java | 40 - .../system/post/db/SysPostServiceImpl.java | 55 - .../domain/system/post/dto/PostDTO.java | 52 - .../domain/system/post/model/PostModel.java | 63 - .../system/post/model/PostModelFactory.java | 31 - .../domain/system/post/query/PostQuery.java | 35 - .../system/role/RoleApplicationService.java | 16 - .../system/role/command/AddRoleCommand.java | 1 - .../role/command/UpdateDataScopeCommand.java | 26 - .../domain/system/role/db/SysRoleEntity.java | 6 +- .../domain/system/role/db/SysRoleService.java | 7 + .../system/role/db/SysRoleServiceImpl.java | 9 + .../domain/system/role/dto/RoleDTO.java | 2 - .../domain/system/role/model/RoleModel.java | 22 +- .../system/role/model/RoleModelFactory.java | 6 - .../system/user/UserApplicationService.java | 93 +- .../system/user/command/AddUserCommand.java | 6 - .../user/command/RegisterUserCommand.java | 40 + .../command/UpdateUserPasswordCommand.java | 5 +- .../domain/system/user/db/SearchUserDO.java | 5 +- .../domain/system/user/db/SysUserEntity.java | 8 - .../domain/system/user/db/SysUserMapper.java | 20 +- .../domain/system/user/db/SysUserService.java | 8 - .../system/user/db/SysUserServiceImpl.java | 8 - .../domain/system/user/dto/UserDTO.java | 26 +- .../domain/system/user/dto/UserDetailDTO.java | 8 - .../system/user/dto/UserProfileDTO.java | 8 +- .../domain/system/user/model/UserModel.java | 35 +- .../system/user/model/UserModelFactory.java | 10 +- .../system/user/query/SearchUserQuery.java | 8 +- .../enumtype/SettlementStatusEnumTest.java | 38 + .../system/dept/model/DeptModelTest.java | 157 --- .../system/post/model/PostModelTest.java | 86 -- .../system/role/model/RoleModelTest.java | 33 - .../system/user/model/UserModelTest.java | 30 +- .../db/SysDeptServiceImplTest.java | 68 - .../db/SysMenuServiceImplTest.java | 23 +- .../db/SysPostServiceImplTest.java | 57 - .../db/SysUserServiceImplTest.java | 26 +- .../cache/redis/CacheKeyEnum.java | 1 - .../mybatisplus/MySqlFunction.java | 30 - .../user/web/DataScopeEnum.java | 3 - .../infrastructure/user/web/RoleInfo.java | 6 +- .../user/web/SystemLoginUser.java | 11 +- .../main/resources/h2sql/agileboot_data.sql | 115 +- .../main/resources/h2sql/agileboot_schema.sql | 47 +- .../main/resources/pgsql/agileboot_data.sql | 118 +- .../main/resources/pgsql/agileboot_schema.sql | 42 +- .../mybatisplus/MySqlFunctionTest.java | 17 - backend/docker-compose.yml | 38 - backend/sql/agileboot.sql | 147 +-- docker-compose.yml | 102 ++ frontend/.dockerignore | 20 + frontend/.env.example | 15 - frontend/README.md | 52 + frontend/app/config/index.ts | 26 +- frontend/app/package.json | 54 +- frontend/app/project.config.json | 2 +- frontend/app/src/api/auth.ts | 41 + frontend/app/src/api/collaboration.ts | 165 +++ frontend/app/src/api/profile.ts | 32 + frontend/app/src/api/types.ts | 52 + frontend/app/src/app.config.ts | 40 +- frontend/app/src/app.scss | 197 +++ frontend/app/src/app.ts | 11 +- frontend/app/src/components/AppNavbar.vue | 149 +++ frontend/app/src/components/ThemePicker.vue | 352 ++++++ .../app/src/components/themePickerLock.ts | 25 + frontend/app/src/custom-tab-bar/index.vue | 124 ++ .../collaboration/detail/index.config.ts | 4 + .../src/pages/collaboration/detail/index.vue | 181 +++ .../form/components/PickableFormItem.vue | 70 ++ .../pages/collaboration/form/index.config.ts | 4 + .../src/pages/collaboration/form/index.vue | 1112 +++++++++++++++++ .../collaboration/records/index.config.ts | 5 + .../src/pages/collaboration/records/index.vue | 620 +++++++++ .../collaboration/statistics/index.config.ts | 4 + .../pages/collaboration/statistics/index.vue | 380 ++++++ frontend/app/src/pages/index/index.config.ts | 3 - frontend/app/src/pages/index/index.scss | 0 frontend/app/src/pages/index/index.vue | 19 - frontend/app/src/pages/login/index.config.ts | 4 + frontend/app/src/pages/login/index.vue | 318 +++++ .../app/src/pages/profile/index.config.ts | 4 + frontend/app/src/pages/profile/index.vue | 126 ++ .../src/pages/profile/info/index.config.ts | 4 + frontend/app/src/pages/profile/info/index.vue | 88 ++ .../pages/profile/password/index.config.ts | 4 + .../app/src/pages/profile/password/index.vue | 98 ++ frontend/app/src/stores/user.ts | 31 + frontend/app/src/theme/tokens.ts | 13 + frontend/app/src/theme/variables.scss | 90 ++ frontend/app/src/utils/auth.ts | 37 + frontend/app/src/utils/crypt.ts | 15 + frontend/app/src/utils/http.ts | 140 +++ frontend/app/types/global.d.ts | 13 + frontend/app/types/wxmp-rsa.d.ts | 6 + frontend/pnpm-lock.yaml | 64 +- frontend/pnpm-workspace.yaml | 18 +- frontend/web/.env | 2 - frontend/web/Dockerfile | 19 +- frontend/web/build/index.ts | 1 - frontend/web/nginx/default.conf | 20 + frontend/web/package.json | 1 + frontend/web/src/api/common/login.ts | 30 +- frontend/web/src/api/system/dept.ts | 83 -- frontend/web/src/api/system/log.ts | 2 - frontend/web/src/api/system/monitor.ts | 1 - frontend/web/src/api/system/post.ts | 70 -- frontend/web/src/api/system/role.ts | 1 - frontend/web/src/api/system/user.ts | 8 +- .../src/components/ReIcon/src/offlineIcon.ts | 2 - .../web/src/layout/components/tag/index.vue | 11 +- frontend/web/src/layout/types.ts | 14 +- frontend/web/src/router/defaultEntry.ts | 1 + frontend/web/src/router/index.ts | 6 - frontend/web/src/router/modules/home.ts | 19 +- frontend/web/src/router/utils.ts | 23 +- frontend/web/src/utils/http/index.ts | 1 + frontend/web/src/utils/tree.ts | 2 +- .../record/record-form-modal.vue | 600 +++++---- .../views/collaboration/record/utils/hook.tsx | 26 +- .../web/src/views/login/components/phone.vue | 106 -- .../web/src/views/login/components/qrCode.vue | 27 - .../src/views/login/components/register.vue | 189 --- .../views/login/components/resetPassword.vue | 154 --- frontend/web/src/views/login/index.vue | 383 ++++-- frontend/web/src/views/login/utils/enums.ts | 35 - frontend/web/src/views/login/utils/rule.ts | 177 +-- .../web/src/views/login/utils/verifyCode.ts | 50 - frontend/web/src/views/system/dept/form.vue | 134 -- frontend/web/src/views/system/dept/index.vue | 149 --- .../web/src/views/system/dept/utils/hook.tsx | 206 --- .../web/src/views/system/dept/utils/rule.ts | 37 - .../system/log/operationLog/description.vue | 3 - frontend/web/src/views/system/menu/form.vue | 10 +- .../web/src/views/system/menu/utils/rule.ts | 2 +- .../system/monitor/onlineUser/utils/hook.tsx | 5 - frontend/web/src/views/system/post/index.vue | 271 ---- .../src/views/system/post/post-form-modal.vue | 79 -- .../web/src/views/system/post/utils/hook.tsx | 229 ---- frontend/web/src/views/system/role/index.vue | 3 +- .../src/views/system/role/role-form-modal.vue | 2 +- frontend/web/src/views/system/user/form.vue | 48 - frontend/web/src/views/system/user/hook.tsx | 30 - frontend/web/src/views/system/user/index.vue | 15 +- .../src/views/system/user/profile/index.vue | 8 +- .../views/system/user/profile/resetPwd.vue | 15 +- frontend/web/src/views/system/user/rule.ts | 1 - .../web/src/views/system/user/svg/expand.svg | 1 - .../src/views/system/user/svg/unexpand.svg | 1 - frontend/web/src/views/system/user/tree.vue | 212 ---- frontend/web/src/views/welcome/index.vue | 9 - frontend/web/types/global.d.ts | 1 - 218 files changed, 6766 insertions(+), 5961 deletions(-) create mode 100644 .env.example create mode 100644 backend/.dockerignore create mode 100644 backend/Dockerfile create mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppAuthController.java create mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppCollaborationRecordController.java create mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppProfileController.java delete mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysDeptController.java delete mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysPostController.java delete mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/CustomDataPermissionChecker.java delete mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DeptTreeDataPermissionChecker.java delete mode 100644 backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/SingleDeptDataPermissionChecker.java create mode 100644 backend/agileboot-admin/src/main/resources/application-prod.yml delete mode 100644 backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/CustomDataPermissionCheckerTest.java delete mode 100644 backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/DeptTreeDataPermissionCheckerTest.java delete mode 100644 backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/SingleDeptDataPermissionCheckerTest.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/DeptApplicationService.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/AddDeptCommand.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/UpdateDeptCommand.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptEntity.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptMapper.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptService.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptServiceImpl.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/dto/DeptDTO.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModel.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModelFactory.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/query/DeptQuery.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/PostApplicationService.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/AddPostCommand.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/UpdatePostCommand.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostEntity.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostMapper.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostService.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostServiceImpl.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/dto/PostDTO.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModel.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModelFactory.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/query/PostQuery.java delete mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/UpdateDataScopeCommand.java create mode 100644 backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/RegisterUserCommand.java create mode 100644 backend/agileboot-domain/src/test/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnumTest.java delete mode 100644 backend/agileboot-domain/src/test/java/com/agileboot/domain/system/dept/model/DeptModelTest.java delete mode 100644 backend/agileboot-domain/src/test/java/com/agileboot/domain/system/post/model/PostModelTest.java delete mode 100644 backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysDeptServiceImplTest.java delete mode 100644 backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysPostServiceImplTest.java delete mode 100644 backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/MySqlFunction.java delete mode 100644 backend/agileboot-infrastructure/src/test/java/com/agileboot/infrastructure/mybatisplus/MySqlFunctionTest.java delete mode 100644 backend/docker-compose.yml create mode 100644 docker-compose.yml create mode 100644 frontend/.dockerignore delete mode 100644 frontend/.env.example create mode 100644 frontend/README.md create mode 100644 frontend/app/src/api/auth.ts create mode 100644 frontend/app/src/api/collaboration.ts create mode 100644 frontend/app/src/api/profile.ts create mode 100644 frontend/app/src/api/types.ts create mode 100644 frontend/app/src/components/AppNavbar.vue create mode 100644 frontend/app/src/components/ThemePicker.vue create mode 100644 frontend/app/src/components/themePickerLock.ts create mode 100644 frontend/app/src/custom-tab-bar/index.vue create mode 100644 frontend/app/src/pages/collaboration/detail/index.config.ts create mode 100644 frontend/app/src/pages/collaboration/detail/index.vue create mode 100644 frontend/app/src/pages/collaboration/form/components/PickableFormItem.vue create mode 100644 frontend/app/src/pages/collaboration/form/index.config.ts create mode 100644 frontend/app/src/pages/collaboration/form/index.vue create mode 100644 frontend/app/src/pages/collaboration/records/index.config.ts create mode 100644 frontend/app/src/pages/collaboration/records/index.vue create mode 100644 frontend/app/src/pages/collaboration/statistics/index.config.ts create mode 100644 frontend/app/src/pages/collaboration/statistics/index.vue delete mode 100644 frontend/app/src/pages/index/index.config.ts delete mode 100644 frontend/app/src/pages/index/index.scss delete mode 100644 frontend/app/src/pages/index/index.vue create mode 100644 frontend/app/src/pages/login/index.config.ts create mode 100644 frontend/app/src/pages/login/index.vue create mode 100644 frontend/app/src/pages/profile/index.config.ts create mode 100644 frontend/app/src/pages/profile/index.vue create mode 100644 frontend/app/src/pages/profile/info/index.config.ts create mode 100644 frontend/app/src/pages/profile/info/index.vue create mode 100644 frontend/app/src/pages/profile/password/index.config.ts create mode 100644 frontend/app/src/pages/profile/password/index.vue create mode 100644 frontend/app/src/stores/user.ts create mode 100644 frontend/app/src/theme/tokens.ts create mode 100644 frontend/app/src/theme/variables.scss create mode 100644 frontend/app/src/utils/auth.ts create mode 100644 frontend/app/src/utils/crypt.ts create mode 100644 frontend/app/src/utils/http.ts create mode 100644 frontend/app/types/wxmp-rsa.d.ts create mode 100644 frontend/web/nginx/default.conf delete mode 100644 frontend/web/src/api/system/dept.ts delete mode 100644 frontend/web/src/api/system/post.ts create mode 100644 frontend/web/src/router/defaultEntry.ts delete mode 100644 frontend/web/src/views/login/components/phone.vue delete mode 100644 frontend/web/src/views/login/components/qrCode.vue delete mode 100644 frontend/web/src/views/login/components/register.vue delete mode 100644 frontend/web/src/views/login/components/resetPassword.vue delete mode 100644 frontend/web/src/views/login/utils/enums.ts delete mode 100644 frontend/web/src/views/login/utils/verifyCode.ts delete mode 100644 frontend/web/src/views/system/dept/form.vue delete mode 100644 frontend/web/src/views/system/dept/index.vue delete mode 100644 frontend/web/src/views/system/dept/utils/hook.tsx delete mode 100644 frontend/web/src/views/system/dept/utils/rule.ts delete mode 100644 frontend/web/src/views/system/post/index.vue delete mode 100644 frontend/web/src/views/system/post/post-form-modal.vue delete mode 100644 frontend/web/src/views/system/post/utils/hook.tsx delete mode 100644 frontend/web/src/views/system/user/svg/expand.svg delete mode 100644 frontend/web/src/views/system/user/svg/unexpand.svg delete mode 100644 frontend/web/src/views/system/user/tree.vue delete mode 100644 frontend/web/src/views/welcome/index.vue diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4ac59f0 --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +MYSQL_ROOT_PASSWORD=root123 +MYSQL_DATABASE=todo_agileboot_pure +MYSQL_APP_USERNAME=todo_app +MYSQL_APP_PASSWORD=todo_app123 +MYSQL_PORT=3306 + +REDIS_PASSWORD=redis123 +REDIS_PORT=6379 + +APP_PORT=8080 +WEB_PORT=8081 +JAVA_OPTS=-Xms256m -Xmx512m diff --git a/.gitignore b/.gitignore index b1d7852..86ead69 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Common .DS_Store +/.env .idea/ *.iws *.iml @@ -68,4 +69,4 @@ !/backend/*/build/*.xml # Backend local configuration -/backend/agileboot-admin/src/main/resources/application-prod.yml +/backend/.env diff --git a/README.md b/README.md index 6c9afb8..0d56a1b 100644 --- a/README.md +++ b/README.md @@ -1,127 +1,232 @@ -# Simple Template +# Simple Todo -## Quick Start +`simple-todo` 是一个前后端分离的待办/后台管理模板项目。后端基于 AgileBoot 的 Spring Boot 分层架构改造,前端包含 Web 管理端和 Taro 多端应用,根目录提供 Docker Compose 用于本地依赖启动和生产部署。 -This project contains: +## 项目架构 -- `backend`: Spring Boot admin API. -- `frontend/web`: Vite + Vue 3 admin frontend. -- `frontend/app`: Taro + Vue 3 app frontend. +### 原仓库地址 -The local development flow starts MySQL and Redis with Docker, then runs the -backend and web frontend locally. +当前项目是在以下开源项目基础上改造: -### Requirements +- 后端原仓库: +- Web 前端原仓库: +- Web UI 上游项目: + +### 目录结构 + +```text +simple-todo +├── backend # Spring Boot 后端 +│ ├── agileboot-admin # 后台管理接口启动模块 +│ ├── agileboot-api # 开放接口模块 +│ ├── agileboot-common # 通用工具与基础能力 +│ ├── agileboot-domain # 业务领域模块 +│ ├── agileboot-infrastructure # 基础设施、配置、集成能力 +│ └── sql # 初始化 SQL +├── frontend +│ ├── web # Vite + Vue 3 Web 管理端 +│ └── app # Taro + Vue 3 多端应用 +├── docs # 项目开发约定 +├── docker-compose.yml # MySQL、Redis、后端、Web 编排 +└── .env.example # Docker Compose 环境变量示例 +``` + +## 基础环境 - JDK 8+ -- Docker Desktop or Docker Engine with Compose -- Node.js -- pnpm +- Maven 3.8+,也可以直接使用 `backend/mvnw` 或 `backend/mvnw.cmd` +- Node.js 22+,推荐配合 Corepack 使用 pnpm +- pnpm,Dockerfile 中使用 `pnpm@11.1.3` +- Docker Desktop 或 Docker Engine + Docker Compose -### Start Infrastructure +## 开发启动步骤 -The development backend is configured to use the same defaults as -`backend/docker-compose.yml`: +### 1. 准备环境变量 -- MySQL: `localhost:3306`, user `root`, password `root123` -- Redis: `localhost:6379`, password `redis123` -- Database name: `agileboot_pure` - -You can start MySQL and Redis manually: +Docker Compose 在项目根目录执行时会自动读取 `.env`。可以从示例文件复制: ```bash -cd backend -docker compose up -d +cp .env.example .env ``` -The compose configuration mounts `backend/sql/agileboot.sql` into the MySQL -container as `/docker-entrypoint-initdb.d/01-agileboot.sql`. -The official MySQL image only runs files in `/docker-entrypoint-initdb.d` when -the database directory is empty, during the first initialization of the -`mysql_data` volume. +Windows PowerShell: -If MySQL has already been started before, the `mysql_data` volume already -contains data and `docker compose up -d` will not import the SQL again. To -reinitialize the local database, remove the volumes first: +```powershell +Copy-Item .env.example .env +``` + +`.env.example` 默认把 MySQL 和 Redis 映射到宿主机 `3306`、`6379`,与后端 `application-dev.yml` 的本地开发配置保持一致。 + +### 2. 启动 MySQL 和 Redis + +```bash +docker compose up -d mysql redis +``` + +首次启动 MySQL 容器时,Compose 会把 `backend/sql/agileboot.sql` 挂载到 `/docker-entrypoint-initdb.d/01-agileboot.sql`,由 MySQL 镜像自动初始化数据库。 + +如果数据库卷已经存在,初始化 SQL 不会重复执行。需要重建本地数据时可以执行: ```bash -cd backend docker compose down -v -docker compose up -d +docker compose up -d mysql redis ``` -Warning: `docker compose down -v` deletes the local MySQL and Redis volumes, -including existing database data and Redis data. +`docker compose down -v` 会删除本地 MySQL 和 Redis 数据卷,请确认不需要保留本地数据后再执行。 -If you do not want to delete the volumes, import the SQL manually: +### 3. 启动后端 -```bash +Windows PowerShell: + +```powershell cd backend -docker exec -i mysql-server mysql -uroot -proot123 agileboot_pure < sql/agileboot.sql +.\mvnw.cmd -pl agileboot-admin spring-boot:run ``` -### Install Frontend Dependencies - -```bash -cd frontend -pnpm install -``` - -### Start Backend and Web Frontend - -Start the backend: +macOS / Linux: ```bash cd backend ./mvnw -pl agileboot-admin spring-boot:run ``` -Start the web frontend: +后端默认地址: -```bash -cd frontend -pnpm dev:web +```text +http://localhost:8080 ``` -- Backend: `http://localhost:8080` -- Frontend: Vite output, usually `http://localhost:80/` +接口文档地址: -The frontend development proxy maps `/dev-api` to `http://localhost:8080`. - -Optional app commands: - -```bash -cd frontend -pnpm dev:app:weapp -pnpm dev:app:h5 +```text +http://localhost:8080/swagger-ui/index.html +http://localhost:8080/v3/api-docs ``` -## Git Hooks - -This repository uses `.githooks` as the single Git hooks entrypoint. - -```bash -git config core.hooksPath .githooks -``` - -The frontend workspace uses pnpm: +### 4. 启动 Web 管理端 ```bash cd frontend pnpm install pnpm dev:web -pnpm build:web -pnpm dev:app:weapp -pnpm build:app:weapp -pnpm lint -pnpm typecheck ``` -## Frontend +`frontend/web/.env.development` 默认配置: -`frontend` is a pnpm workspace: +```env +VITE_PORT=80 +VITE_APP_BASE_API=/dev-api +``` -- `web`: Vite + Vue 3 admin frontend. -- `app`: Taro + Vue 3 app frontend. +Web 开发服务默认地址: -Shared engineering configuration lives in `frontend` root. Subprojects should extend the shared TypeScript, ESLint, Stylelint, Prettier, commitlint, and lint-staged configuration instead of duplicating it. +```text +http://localhost:80 +``` + +如果 80 端口被占用,可以修改 `frontend/web/.env.development` 中的 `VITE_PORT`。 + +### 5. 启动 App 端,可选 + +```bash +cd frontend +pnpm dev:app:weapp +``` + +H5 模式: + +```bash +cd frontend +pnpm dev:app:h5 +``` + +## 部署步骤 + +生产部署推荐使用根目录的 Docker Compose。它会启动 MySQL、Redis、后端服务和 Web Nginx 服务。 + +### 1. 准备生产环境变量 + +```bash +cp .env.example .env +``` + +按实际环境修改 `.env`,至少建议调整: + +```env +MYSQL_ROOT_PASSWORD=请替换为强密码 +MYSQL_DATABASE=todo_agileboot_pure +MYSQL_APP_USERNAME=todo_app +MYSQL_APP_PASSWORD=请替换为强密码 +MYSQL_PORT=13306 + +REDIS_PASSWORD=请替换为强密码 +REDIS_PORT=16379 + +APP_PORT=8080 +WEB_PORT=8081 +JAVA_OPTS=-Xms256m -Xmx512m +``` + +生产环境建议把 `MYSQL_PORT`、`REDIS_PORT` 改成非默认宿主机端口,例如上面的 `13306`、`16379`。这两个变量只影响宿主机暴露端口,不影响容器内部端口;后端容器仍通过 Compose 内部网络访问 MySQL `3306` 和 Redis `6379`。 + +如果数据库和 Redis 只给后端容器使用,建议进一步通过服务器防火墙限制这些端口的外部访问,或按实际部署需要移除 `docker-compose.yml` 中 MySQL/Redis 的 `ports` 暴露配置。 + +不要提交真实生产 `.env` 文件。 + +### 2. 构建并启动完整服务 + +```bash +docker compose --profile prod up -d --build +``` + +Compose 会执行以下构建: + +- `backend/Dockerfile`:使用 Maven 构建 `agileboot-admin`,运行 Spring Boot Jar。 +- `frontend/web/Dockerfile`:构建 Web 静态文件,并用 Nginx 提供访问。 + +Web 容器中的 Nginx 会把 `/prod-api/` 代理到 Compose 内部的后端服务 `app:8080`。 + +### 3. 访问服务 + +默认访问地址: + +```text +Web:http://localhost:8081 +后端:http://localhost:8080 +``` + +如果修改了 `.env` 中的 `WEB_PORT` 或 `APP_PORT`,以实际端口为准。 + +### 4. 常用运维命令 + +查看服务状态: + +```bash +docker compose --profile prod ps +``` + +查看后端日志: + +```bash +docker compose --profile prod logs -f app +``` + +查看 Web 日志: + +```bash +docker compose --profile prod logs -f web +``` + +停止服务: + +```bash +docker compose --profile prod down +``` + +停止并删除数据卷: + +```bash +docker compose --profile prod down -v +``` + +`down -v` 会删除数据库和 Redis 数据,生产环境谨慎使用。 diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..f54f1e8 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,12 @@ +.git +.gitignore +.idea +*.iml +*.log +**/target +build +dist +.gradle +.mvn/wrapper/maven-wrapper.jar +.env +docker-compose.yml diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..6f8a122 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,19 @@ +FROM maven:3.8.8-eclipse-temurin-8 AS build-stage + +WORKDIR /app + +COPY . . + +RUN mvn -pl agileboot-admin -am package -Dmaven.test.skip=true -B + +FROM eclipse-temurin:8-jre + +WORKDIR /app + +ENV TZ=Asia/Shanghai + +COPY --from=build-stage /app/agileboot-admin/target/*.jar /app/app.jar + +EXPOSE 8080 + +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"] diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppAuthController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppAuthController.java new file mode 100644 index 0000000..20bf9f3 --- /dev/null +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppAuthController.java @@ -0,0 +1,84 @@ +package com.agileboot.admin.controller.app; + +import com.agileboot.admin.customize.service.login.LoginService; +import com.agileboot.admin.customize.service.login.command.LoginCommand; +import com.agileboot.admin.customize.service.login.dto.CaptchaDTO; +import com.agileboot.admin.customize.service.login.dto.ConfigDTO; +import com.agileboot.common.core.dto.ResponseDTO; +import com.agileboot.domain.common.dto.CurrentLoginUserDTO; +import com.agileboot.domain.common.dto.TokenDTO; +import com.agileboot.domain.system.user.UserApplicationService; +import com.agileboot.domain.system.user.command.RegisterUserCommand; +import com.agileboot.infrastructure.user.AuthenticationUtils; +import com.agileboot.infrastructure.user.web.SystemLoginUser; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author codex + */ +@Tag(name = "小程序登录API", description = "小程序登录注册相关接口") +@RestController +@RequestMapping("/app") +@RequiredArgsConstructor +public class AppAuthController { + + private final LoginService loginService; + private final UserApplicationService userApplicationService; + + @Operation(summary = "小程序配置") + @GetMapping("/getConfig") + public ResponseDTO getConfig() { + return ResponseDTO.ok(loginService.getConfig()); + } + + @Operation(summary = "小程序验证码") + @GetMapping("/captchaImage") + public ResponseDTO getCaptchaImg() { + return ResponseDTO.ok(loginService.generateCaptchaImg()); + } + + @Operation(summary = "小程序登录") + @PostMapping("/login") + public ResponseDTO login(@RequestBody LoginCommand command) { + String token = loginService.login(command); + return ResponseDTO.ok(buildTokenDTO(token)); + } + + @Operation(summary = "小程序注册") + @PostMapping("/register") + public ResponseDTO register(@Validated @RequestBody RegisterUserCommand command) { + decryptRegisterPassword(command); + loginService.validateCaptchaIfEnabled(command.getUsername(), command.getCaptchaCode(), + command.getCaptchaCodeKey()); + userApplicationService.registerUser(command); + loginService.recordRegisterInfo(command.getUsername()); + return ResponseDTO.ok(buildTokenDTO(loginService.createTokenForRegisteredUser(command.getUsername()))); + } + + @Operation(summary = "小程序当前登录用户") + @GetMapping("/getLoginUserInfo") + public ResponseDTO getLoginUserInfo() { + SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); + return ResponseDTO.ok(userApplicationService.getLoginUserInfo(loginUser)); + } + + private TokenDTO buildTokenDTO(String token) { + SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); + CurrentLoginUserDTO currentUser = userApplicationService.getLoginUserInfo(loginUser); + return new TokenDTO(token, currentUser); + } + + private void decryptRegisterPassword(RegisterUserCommand command) { + command.setPassword(loginService.decryptPassword(command.getPassword())); + command.setConfirmPassword(loginService.decryptPassword(command.getConfirmPassword())); + } + +} diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppCollaborationRecordController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppCollaborationRecordController.java new file mode 100644 index 0000000..c3e0044 --- /dev/null +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppCollaborationRecordController.java @@ -0,0 +1,90 @@ +package com.agileboot.admin.controller.app; + +import com.agileboot.common.core.dto.ResponseDTO; +import com.agileboot.common.core.page.PageDTO; +import com.agileboot.domain.collaboration.record.CollaborationRecordApplicationService; +import com.agileboot.domain.collaboration.record.command.AddCollaborationRecordCommand; +import com.agileboot.domain.collaboration.record.command.UpdateCollaborationRecordCommand; +import com.agileboot.domain.collaboration.record.dto.CollaborationMonthlyStatisticsDTO; +import com.agileboot.domain.collaboration.record.dto.CollaborationOptionDTO; +import com.agileboot.domain.collaboration.record.dto.CollaborationRecordDTO; +import com.agileboot.domain.collaboration.record.dto.CollaborationRecordDetailDTO; +import com.agileboot.domain.collaboration.record.query.CollaborationRecordQuery; +import com.agileboot.domain.common.command.BulkOperationCommand; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author codex + */ +@Tag(name = "小程序合作记录API", description = "小程序合作记录相关接口") +@RestController +@RequestMapping("/app/collaboration/record") +@Validated +@RequiredArgsConstructor +public class AppCollaborationRecordController { + + private final CollaborationRecordApplicationService recordApplicationService; + + @Operation(summary = "小程序合作记录列表") + @GetMapping("/list") + public ResponseDTO> list(CollaborationRecordQuery query) { + return ResponseDTO.ok(recordApplicationService.getRecordList(query)); + } + + @Operation(summary = "小程序合作记录详情") + @GetMapping("/{recordId}") + public ResponseDTO getInfo(@PathVariable @Positive Long recordId) { + return ResponseDTO.ok(recordApplicationService.getRecordInfo(recordId)); + } + + @Operation(summary = "小程序合作记录选项") + @GetMapping("/options") + public ResponseDTO> options() { + return ResponseDTO.ok(recordApplicationService.getOptions()); + } + + @Operation(summary = "小程序合作记录月度统计") + @GetMapping("/monthly-statistics") + public ResponseDTO> monthlyStatistics(@RequestParam Integer year) { + return ResponseDTO.ok(recordApplicationService.getMonthlyStatistics(year)); + } + + @Operation(summary = "小程序新增合作记录") + @PostMapping + public ResponseDTO add(@Valid @RequestBody AddCollaborationRecordCommand command) { + recordApplicationService.addRecord(command); + return ResponseDTO.ok(); + } + + @Operation(summary = "小程序修改合作记录") + @PutMapping + public ResponseDTO edit(@Valid @RequestBody UpdateCollaborationRecordCommand command) { + recordApplicationService.updateRecord(command); + return ResponseDTO.ok(); + } + + @Operation(summary = "小程序删除合作记录") + @DeleteMapping + public ResponseDTO remove(@RequestParam @NotNull @NotEmpty List ids) { + recordApplicationService.deleteRecord(new BulkOperationCommand<>(ids)); + return ResponseDTO.ok(); + } + +} diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppProfileController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppProfileController.java new file mode 100644 index 0000000..c4ebde8 --- /dev/null +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/app/AppProfileController.java @@ -0,0 +1,56 @@ +package com.agileboot.admin.controller.app; + +import com.agileboot.common.core.dto.ResponseDTO; +import com.agileboot.domain.system.user.UserApplicationService; +import com.agileboot.domain.system.user.command.UpdateProfileCommand; +import com.agileboot.domain.system.user.command.UpdateUserPasswordCommand; +import com.agileboot.domain.system.user.dto.UserProfileDTO; +import com.agileboot.infrastructure.user.AuthenticationUtils; +import com.agileboot.infrastructure.user.web.SystemLoginUser; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author codex + */ +@Tag(name = "小程序个人信息API", description = "小程序个人信息相关接口") +@RestController +@RequestMapping("/app/user/profile") +@RequiredArgsConstructor +public class AppProfileController { + + private final UserApplicationService userApplicationService; + + @Operation(summary = "小程序获取个人信息") + @GetMapping + public ResponseDTO profile() { + SystemLoginUser user = AuthenticationUtils.getSystemLoginUser(); + return ResponseDTO.ok(userApplicationService.getUserProfile(user.getUserId())); + } + + @Operation(summary = "小程序修改个人信息") + @PutMapping + public ResponseDTO updateProfile(@RequestBody UpdateProfileCommand command) { + SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); + command.setUserId(loginUser.getUserId()); + userApplicationService.updateUserProfile(command); + return ResponseDTO.ok(); + } + + @Operation(summary = "小程序修改个人密码") + @PutMapping("/password") + public ResponseDTO updatePassword(@Validated @RequestBody UpdateUserPasswordCommand command) { + SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); + command.setUserId(loginUser.getUserId()); + userApplicationService.updatePasswordBySelf(loginUser, command); + return ResponseDTO.ok(); + } + +} diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/FileController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/FileController.java index 7290371..d6fce6b 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/FileController.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/FileController.java @@ -24,6 +24,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -73,7 +74,7 @@ public class FileController { */ @Operation(summary = "单个上传文件") @PostMapping("/upload") - public ResponseDTO uploadFile(MultipartFile file) { + public ResponseDTO uploadFile(@RequestParam("file") MultipartFile file) { if (file == null) { throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY); } @@ -101,7 +102,7 @@ public class FileController { */ @Operation(summary = "多个上传文件") @PostMapping("/uploads") - public ResponseDTO> uploadFiles(List files) { + public ResponseDTO> uploadFiles(@RequestParam("files") List files) { if (CollUtil.isEmpty(files)) { throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY); } diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/LoginController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/LoginController.java index 6c365ca..66b513e 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/LoginController.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/LoginController.java @@ -3,14 +3,12 @@ package com.agileboot.admin.controller.common; import cn.hutool.core.util.StrUtil; import com.agileboot.common.config.AgileBootConfig; import com.agileboot.common.core.dto.ResponseDTO; -import com.agileboot.common.exception.ApiException; -import com.agileboot.common.exception.error.ErrorCode.Business; import com.agileboot.domain.common.dto.CurrentLoginUserDTO; import com.agileboot.domain.common.dto.TokenDTO; import com.agileboot.domain.system.menu.MenuApplicationService; import com.agileboot.domain.system.menu.dto.RouterDTO; import com.agileboot.domain.system.user.UserApplicationService; -import com.agileboot.domain.system.user.command.AddUserCommand; +import com.agileboot.domain.system.user.command.RegisterUserCommand; import com.agileboot.infrastructure.annotations.ratelimit.RateLimit; import com.agileboot.infrastructure.annotations.ratelimit.RateLimit.CacheType; import com.agileboot.infrastructure.annotations.ratelimit.RateLimit.LimitType; @@ -25,6 +23,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -130,10 +129,24 @@ public class LoginController { } - @Operation(summary = "注册接口", description = "暂未实现") + @Operation(summary = "注册接口") @PostMapping("/register") - public ResponseDTO register(@RequestBody AddUserCommand command) { - return ResponseDTO.fail(new ApiException(Business.COMMON_UNSUPPORTED_OPERATION)); + public ResponseDTO register(@Validated @RequestBody RegisterUserCommand command) { + decryptRegisterPassword(command); + loginService.validateCaptchaIfEnabled(command.getUsername(), command.getCaptchaCode(), command.getCaptchaCodeKey()); + userApplicationService.registerUser(command); + loginService.recordRegisterInfo(command.getUsername()); + + String token = loginService.createTokenForRegisteredUser(command.getUsername()); + SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); + CurrentLoginUserDTO currentUserDTO = userApplicationService.getLoginUserInfo(loginUser); + + return ResponseDTO.ok(new TokenDTO(token, currentUserDTO)); + } + + private void decryptRegisterPassword(RegisterUserCommand command) { + command.setPassword(loginService.decryptPassword(command.getPassword())); + command.setConfirmPassword(loginService.decryptPassword(command.getConfirmPassword())); } } diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysDeptController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysDeptController.java deleted file mode 100644 index 21f7860..0000000 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysDeptController.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.agileboot.admin.controller.system; - -import cn.hutool.core.lang.tree.Tree; -import com.agileboot.common.core.base.BaseController; -import com.agileboot.common.core.dto.ResponseDTO; -import com.agileboot.domain.system.dept.DeptApplicationService; -import com.agileboot.domain.system.dept.command.AddDeptCommand; -import com.agileboot.domain.system.dept.command.UpdateDeptCommand; -import com.agileboot.domain.system.dept.dto.DeptDTO; -import com.agileboot.domain.system.dept.query.DeptQuery; -import com.agileboot.admin.customize.aop.accessLog.AccessLog; -import com.agileboot.common.enums.common.BusinessTypeEnum; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import java.util.List; -import javax.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * 部门信息 - * - * @author valarchie - */ -@RestController -@RequestMapping("/system") -@Validated -@RequiredArgsConstructor -@Tag(name = "部门API", description = "部门相关的增删查改") -public class SysDeptController extends BaseController { - - private final DeptApplicationService deptApplicationService; - - /** - * 获取部门列表 - */ - @Operation(summary = "部门列表") - @PreAuthorize("@permission.has('system:dept:list')") - @GetMapping("/depts") - public ResponseDTO> list(DeptQuery query) { - List deptList = deptApplicationService.getDeptList(query); - return ResponseDTO.ok(deptList); - } - - /** - * 根据部门编号获取详细信息 - */ - @Operation(summary = "部门详情") - @PreAuthorize("@permission.has('system:dept:query')") - @GetMapping(value = "/dept/{deptId}") - public ResponseDTO getInfo(@PathVariable Long deptId) { - DeptDTO dept = deptApplicationService.getDeptInfo(deptId); - return ResponseDTO.ok(dept); - } - - /** - * 获取部门下拉树列表 - */ - @Operation(summary = "获取部门树级结构") - @GetMapping("/depts/dropdown") - public ResponseDTO>> dropdownList() { - List> deptTree = deptApplicationService.getDeptTree(); - return ResponseDTO.ok(deptTree); - } - - /** - * 新增部门 - */ - @Operation(summary = "新增部门") - @PreAuthorize("@permission.has('system:dept:add')") - @AccessLog(title = "部门管理", businessType = BusinessTypeEnum.ADD) - @PostMapping("/dept") - public ResponseDTO add(@RequestBody AddDeptCommand addCommand) { - deptApplicationService.addDept(addCommand); - return ResponseDTO.ok(); - } - - /** - * 修改部门 - */ - @Operation(summary = "修改部门") - @PreAuthorize("@permission.has('system:dept:edit') AND @dataScope.checkDeptId(#updateCommand.deptId)") - @AccessLog(title = "部门管理", businessType = BusinessTypeEnum.MODIFY) - @PutMapping("/dept/{deptId}") - public ResponseDTO edit(@PathVariable("deptId")Long deptId, @RequestBody UpdateDeptCommand updateCommand) { - updateCommand.setDeptId(deptId); - deptApplicationService.updateDept(updateCommand); - return ResponseDTO.ok(); - } - - /** - * 删除部门 - */ - @Operation(summary = "删除部门") - @PreAuthorize("@permission.has('system:dept:remove') AND @dataScope.checkDeptId(#deptId)") - @AccessLog(title = "部门管理", businessType = BusinessTypeEnum.DELETE) - @DeleteMapping("/dept/{deptId}") - public ResponseDTO remove(@PathVariable @NotNull Long deptId) { - deptApplicationService.removeDept(deptId); - return ResponseDTO.ok(); - } -} diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysPostController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysPostController.java deleted file mode 100644 index a3fb248..0000000 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysPostController.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.agileboot.admin.controller.system; - -import com.agileboot.admin.customize.aop.accessLog.AccessLog; -import com.agileboot.common.core.base.BaseController; -import com.agileboot.common.core.dto.ResponseDTO; -import com.agileboot.common.core.page.PageDTO; -import com.agileboot.common.enums.common.BusinessTypeEnum; -import com.agileboot.common.utils.poi.CustomExcelUtil; -import com.agileboot.domain.common.command.BulkOperationCommand; -import com.agileboot.domain.system.post.PostApplicationService; -import com.agileboot.domain.system.post.command.AddPostCommand; -import com.agileboot.domain.system.post.command.UpdatePostCommand; -import com.agileboot.domain.system.post.dto.PostDTO; -import com.agileboot.domain.system.post.query.PostQuery; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import java.util.List; -import javax.servlet.http.HttpServletResponse; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -/** - * 岗位信息操作处理 - * - * @author ruoyi - */ -@Tag(name = "职位API", description = "职位相关的增删查改") -@RestController -@RequestMapping("/system/post") -@Validated -@RequiredArgsConstructor -public class SysPostController extends BaseController { - - private final PostApplicationService postApplicationService; - - /** - * 获取岗位列表 - */ - @Operation(summary = "职位列表") - @PreAuthorize("@permission.has('system:post:list')") - @GetMapping("/list") - public ResponseDTO> list(PostQuery query) { - PageDTO pageDTO = postApplicationService.getPostList(query); - return ResponseDTO.ok(pageDTO); - } - - /** - * 导出查询到的所有岗位信息到excel文件 - * @param response http响应 - * @param query 查询参数 - * @author Kevin Zhang - * @date 2023-10-02 - */ - @Operation(summary = "职位列表导出") - @AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.EXPORT) - @PreAuthorize("@permission.has('system:post:export')") - @GetMapping("/excel") - public void export(HttpServletResponse response, PostQuery query) { - List all = postApplicationService.getPostListAll(query); - CustomExcelUtil.writeToResponse(all, PostDTO.class, response); - } - - /** - * 根据岗位编号获取详细信息 - */ - @Operation(summary = "职位详情") - @PreAuthorize("@permission.has('system:post:query')") - @GetMapping(value = "/{postId}") - public ResponseDTO getInfo(@PathVariable Long postId) { - PostDTO post = postApplicationService.getPostInfo(postId); - return ResponseDTO.ok(post); - } - - /** - * 新增岗位 - */ - @Operation(summary = "添加职位") - @PreAuthorize("@permission.has('system:post:add')") - @AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.ADD) - @PostMapping - public ResponseDTO add(@RequestBody AddPostCommand addCommand) { - postApplicationService.addPost(addCommand); - return ResponseDTO.ok(); - } - - /** - * 修改岗位 - */ - @Operation(summary = "修改职位") - @PreAuthorize("@permission.has('system:post:edit')") - @AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.MODIFY) - @PutMapping - public ResponseDTO edit(@RequestBody UpdatePostCommand updateCommand) { - postApplicationService.updatePost(updateCommand); - return ResponseDTO.ok(); - } - - /** - * 删除岗位 - */ - @Operation(summary = "删除职位") - @PreAuthorize("@permission.has('system:post:remove')") - @AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.DELETE) - @DeleteMapping - public ResponseDTO remove(@RequestParam @NotNull @NotEmpty List ids) { - postApplicationService.deletePost(new BulkOperationCommand<>(ids)); - return ResponseDTO.ok(); - } - -} diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysProfileController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysProfileController.java index 36905c8..7a4a8a2 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysProfileController.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysProfileController.java @@ -19,6 +19,7 @@ import com.agileboot.common.enums.common.BusinessTypeEnum; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -71,7 +72,7 @@ public class SysProfileController extends BaseController { @Operation(summary = "重置个人密码") @AccessLog(title = "个人信息", businessType = BusinessTypeEnum.MODIFY) @PutMapping("/password") - public ResponseDTO updatePassword(@RequestBody UpdateUserPasswordCommand command) { + public ResponseDTO updatePassword(@Validated @RequestBody UpdateUserPasswordCommand command) { SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); command.setUserId(loginUser.getUserId()); userApplicationService.updatePasswordBySelf(loginUser, command); diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysRoleController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysRoleController.java index 75c12d9..ba3e709 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysRoleController.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysRoleController.java @@ -6,7 +6,6 @@ import com.agileboot.common.core.page.PageDTO; import com.agileboot.common.utils.poi.CustomExcelUtil; import com.agileboot.domain.system.role.RoleApplicationService; import com.agileboot.domain.system.role.command.AddRoleCommand; -import com.agileboot.domain.system.role.command.UpdateDataScopeCommand; import com.agileboot.domain.system.role.command.UpdateRoleCommand; import com.agileboot.domain.system.role.command.UpdateStatusCommand; import com.agileboot.domain.system.role.dto.RoleDTO; @@ -111,21 +110,6 @@ public class SysRoleController extends BaseController { return ResponseDTO.ok(); } - /** - * 修改保存数据权限 - */ - @Operation(summary = "修改角色数据权限") - @PreAuthorize("@permission.has('system:role:edit')") - @AccessLog(title = "角色管理", businessType = BusinessTypeEnum.MODIFY) - @PutMapping("/{roleId}/dataScope") - public ResponseDTO dataScope(@PathVariable("roleId") Long roleId, - @RequestBody UpdateDataScopeCommand command) { - command.setRoleId(roleId); - - roleApplicationService.updateDataScope(command); - return ResponseDTO.ok(); - } - /** * 角色状态修改 */ diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysUserController.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysUserController.java index 8863560..722bf2f 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysUserController.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/controller/system/SysUserController.java @@ -52,7 +52,7 @@ public class SysUserController extends BaseController { * 获取用户列表 */ @Operation(summary = "用户列表") - @PreAuthorize("@permission.has('system:user:list') AND @dataScope.checkDeptId(#query.deptId)") + @PreAuthorize("@permission.has('system:user:list')") @GetMapping public ResponseDTO> userList(SearchUserQuery query) { PageDTO page = userApplicationService.getUserList(query); @@ -105,7 +105,7 @@ public class SysUserController extends BaseController { * 新增用户 */ @Operation(summary = "新增用户") - @PreAuthorize("@permission.has('system:user:add') AND @dataScope.checkDeptId(#command.deptId)") + @PreAuthorize("@permission.has('system:user:add')") @AccessLog(title = "用户管理", businessType = BusinessTypeEnum.ADD) @PostMapping public ResponseDTO add(@Validated @RequestBody AddUserCommand command) { diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java index e8a6cc4..c793f58 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java @@ -135,6 +135,7 @@ public class SecurityConfig { // 对于登录login 注册register 验证码captchaImage 以及公共Api的请求允许匿名访问 // 注意: 当携带token请求以下这几个接口时 会返回403的错误 .antMatchers("/login", "/register", "/getConfig", "/captchaImage", "/api/**").anonymous() + .antMatchers("/app/login", "/app/register", "/app/getConfig", "/app/captchaImage").anonymous() .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() // TODO this is danger. diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java index 0282bf1..0b0cebd 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java @@ -40,6 +40,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import org.springframework.util.FastByteArrayOutputStream; @@ -61,6 +62,8 @@ public class LoginService { private final AuthenticationManager authenticationManager; + private final UserDetailsService userDetailsService; + @Resource(name = "captchaProducer") private Producer captchaProducer; @@ -115,6 +118,7 @@ public class LoginService { boolean isCaptchaOn = isCaptchaOn(); configDTO.setIsCaptchaOn(isCaptchaOn); + configDTO.setIsRegisterUserOn(isRegisterUserOn()); configDTO.setDictionary(MapCache.dictionaryCache()); return configDTO; } @@ -179,6 +183,9 @@ public class LoginService { * @param captchaCodeKey 验证码对应的缓存key */ public void validateCaptcha(String username, String captchaCode, String captchaCodeKey) { + if (StrUtil.isBlank(captchaCode) || StrUtil.isBlank(captchaCodeKey)) { + throw new ApiException(ErrorCode.Business.LOGIN_CAPTCHA_CODE_NULL); + } String captcha = redisCache.captchaCache.getObjectById(captchaCodeKey); redisCache.captchaCache.delete(captchaCodeKey); if (captcha == null) { @@ -193,6 +200,26 @@ public class LoginService { } } + public void validateCaptchaIfEnabled(String username, String captchaCode, String captchaCodeKey) { + if (isCaptchaOn()) { + validateCaptcha(username, captchaCode, captchaCodeKey); + } + } + + public String createTokenForRegisteredUser(String username) { + SystemLoginUser loginUser = (SystemLoginUser) userDetailsService.loadUserByUsername(username); + Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser, null, + loginUser.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + updateLoginInfo(loginUser); + return tokenService.createTokenAndPutUserInCache(loginUser); + } + + public void recordRegisterInfo(String username) { + ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(username, LoginStatusEnum.REGISTER, + LoginStatusEnum.REGISTER.description())); + } + /** * 记录登录信息 * @param loginUser 登录用户 @@ -200,7 +227,10 @@ public class LoginService { public void recordLoginInfo(SystemLoginUser loginUser) { ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginUser.getUsername(), LoginStatusEnum.LOGIN_SUCCESS, LoginStatusEnum.LOGIN_SUCCESS.description())); + updateLoginInfo(loginUser); + } + private void updateLoginInfo(SystemLoginUser loginUser) { SysUserEntity entity = redisCache.userCache.getObjectById(loginUser.getUserId()); entity.setLoginIp(ServletUtil.getClientIP(ServletHolderUtil.getRequest())); @@ -219,4 +249,8 @@ public class LoginService { return Convert.toBool(guavaCache.configCache.get(ConfigKeyEnum.CAPTCHA.getValue())); } + private boolean isRegisterUserOn() { + return Convert.toBool(guavaCache.configCache.get(ConfigKeyEnum.REGISTER.getValue())); + } + } diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/UserDetailsServiceImpl.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/UserDetailsServiceImpl.java index fc82fee..5cbf04a 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/UserDetailsServiceImpl.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/UserDetailsServiceImpl.java @@ -1,7 +1,5 @@ package com.agileboot.admin.customize.service.login; -import cn.hutool.core.convert.Convert; -import cn.hutool.core.util.StrUtil; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.infrastructure.user.web.SystemLoginUser; @@ -24,7 +22,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.SetUtils; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -67,7 +64,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { RoleInfo roleInfo = getRoleInfo(userEntity.getRoleId(), userEntity.getIsAdmin()); SystemLoginUser loginUser = new SystemLoginUser(userEntity.getUserId(), userEntity.getIsAdmin(), userEntity.getUsername(), - userEntity.getPassword(), roleInfo, userEntity.getDeptId()); + userEntity.getPassword(), roleInfo); loginUser.fillLoginInfo(); loginUser.setAutoRefreshCacheTime(loginUser.getLoginInfo().getLoginTime() + TimeUnit.MINUTES.toMillis(tokenService.getAutoRefreshTime())); @@ -86,7 +83,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { Set allMenuIds = allMenus.stream().map(SysMenuEntity::getMenuId).collect(Collectors.toSet()); - return new RoleInfo(RoleInfo.ADMIN_ROLE_ID, RoleInfo.ADMIN_ROLE_KEY, DataScopeEnum.ALL, SetUtils.emptySet(), + return new RoleInfo(RoleInfo.ADMIN_ROLE_ID, RoleInfo.ADMIN_ROLE_KEY, DataScopeEnum.ALL, RoleInfo.ADMIN_PERMISSIONS, allMenuIds); } @@ -104,13 +101,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { DataScopeEnum dataScopeEnum = BasicEnumUtil.fromValue(DataScopeEnum.class, roleEntity.getDataScope()); - Set deptIdSet = SetUtils.emptySet(); - if (StrUtil.isNotEmpty(roleEntity.getDeptIdSet())) { - deptIdSet = StrUtil.split(roleEntity.getDeptIdSet(), ",").stream() - .map(Convert::toLong).collect(Collectors.toSet()); - } - - return new RoleInfo(roleId, roleEntity.getRoleKey(), dataScopeEnum, deptIdSet, permissions, menuIds); + return new RoleInfo(roleId, roleEntity.getRoleKey(), dataScopeEnum, permissions, menuIds); } diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/dto/ConfigDTO.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/dto/ConfigDTO.java index f82ed4d..f895d9c 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/dto/ConfigDTO.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/dto/ConfigDTO.java @@ -13,6 +13,8 @@ public class ConfigDTO { private Boolean isCaptchaOn; + private Boolean isRegisterUserOn; + private Map> dictionary; } diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionCheckerFactory.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionCheckerFactory.java index c7fdcca..93add90 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionCheckerFactory.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionCheckerFactory.java @@ -1,16 +1,11 @@ package com.agileboot.admin.customize.service.permission; -import cn.hutool.extra.spring.SpringUtil; import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker; import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.admin.customize.service.permission.model.checker.AllDataPermissionChecker; -import com.agileboot.admin.customize.service.permission.model.checker.CustomDataPermissionChecker; import com.agileboot.admin.customize.service.permission.model.checker.DefaultDataPermissionChecker; -import com.agileboot.admin.customize.service.permission.model.checker.DeptTreeDataPermissionChecker; import com.agileboot.admin.customize.service.permission.model.checker.OnlySelfDataPermissionChecker; -import com.agileboot.admin.customize.service.permission.model.checker.SingleDeptDataPermissionChecker; import com.agileboot.infrastructure.user.web.DataScopeEnum; -import com.agileboot.domain.system.dept.db.SysDeptService; import javax.annotation.PostConstruct; import org.springframework.stereotype.Component; @@ -21,41 +16,31 @@ import org.springframework.stereotype.Component; @Component public class DataPermissionCheckerFactory { private static AbstractDataPermissionChecker allChecker; - private static AbstractDataPermissionChecker customChecker; - private static AbstractDataPermissionChecker singleDeptChecker; - private static AbstractDataPermissionChecker deptTreeChecker; private static AbstractDataPermissionChecker onlySelfChecker; private static AbstractDataPermissionChecker defaultSelfChecker; @PostConstruct public void initAllChecker() { - SysDeptService deptService = SpringUtil.getBean(SysDeptService.class); - allChecker = new AllDataPermissionChecker(); - customChecker = new CustomDataPermissionChecker(deptService); - singleDeptChecker = new SingleDeptDataPermissionChecker(deptService); - deptTreeChecker = new DeptTreeDataPermissionChecker(deptService); - onlySelfChecker = new OnlySelfDataPermissionChecker(deptService); + onlySelfChecker = new OnlySelfDataPermissionChecker(); defaultSelfChecker = new DefaultDataPermissionChecker(); } public static AbstractDataPermissionChecker getChecker(SystemLoginUser loginUser) { if (loginUser == null) { - return deptTreeChecker; + return defaultSelfChecker; + } + + if (loginUser.getRoleInfo() == null || loginUser.getRoleInfo().getDataScope() == null) { + return defaultSelfChecker; } DataScopeEnum dataScope = loginUser.getRoleInfo().getDataScope(); switch (dataScope) { case ALL: return allChecker; - case CUSTOM_DEFINE: - return customChecker; - case SINGLE_DEPT: - return singleDeptChecker; - case DEPT_TREE: - return deptTreeChecker; case ONLY_SELF: return onlySelfChecker; default: diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionService.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionService.java index 53a24f3..83c993f 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionService.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/DataPermissionService.java @@ -33,7 +33,7 @@ public class DataPermissionService { if (targetUser == null) { return true; } - return checkDataScope(loginUser, targetUser.getDeptId(), userId); + return checkDataScope(loginUser, userId); } /** @@ -53,14 +53,8 @@ public class DataPermissionService { return true; } - public boolean checkDeptId(Long deptId) { - SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); - return checkDataScope(loginUser, deptId, null); - } - - - public boolean checkDataScope(SystemLoginUser loginUser, Long targetDeptId, Long targetUserId) { - DataCondition dataCondition = DataCondition.builder().targetDeptId(targetDeptId).targetUserId(targetUserId).build(); + public boolean checkDataScope(SystemLoginUser loginUser, Long targetUserId) { + DataCondition dataCondition = DataCondition.builder().targetUserId(targetUserId).build(); AbstractDataPermissionChecker checker = DataPermissionCheckerFactory.getChecker(loginUser); return checker.check(loginUser, dataCondition); } diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/AbstractDataPermissionChecker.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/AbstractDataPermissionChecker.java index 091cea1..d9b68e3 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/AbstractDataPermissionChecker.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/AbstractDataPermissionChecker.java @@ -1,7 +1,6 @@ package com.agileboot.admin.customize.service.permission.model; import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.domain.system.dept.db.SysDeptService; import lombok.Data; /** @@ -11,8 +10,6 @@ import lombok.Data; @Data public abstract class AbstractDataPermissionChecker { - private SysDeptService deptService; - /** * 检测当前用户对于 给定条件的数据 是否有权限 * diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/DataCondition.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/DataCondition.java index edec2bd..c70d59a 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/DataCondition.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/DataCondition.java @@ -15,7 +15,6 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class DataCondition { - private Long targetDeptId; private Long targetUserId; } diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/AllDataPermissionChecker.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/AllDataPermissionChecker.java index e908dca..750a973 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/AllDataPermissionChecker.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/AllDataPermissionChecker.java @@ -3,7 +3,6 @@ package com.agileboot.admin.customize.service.permission.model.checker; import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker; import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; import lombok.Data; import lombok.EqualsAndHashCode; @@ -15,9 +14,6 @@ import lombok.EqualsAndHashCode; @Data public class AllDataPermissionChecker extends AbstractDataPermissionChecker { - private SysDeptService deptService; - - @Override public boolean check(SystemLoginUser loginUser, DataCondition condition) { return true; diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/CustomDataPermissionChecker.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/CustomDataPermissionChecker.java deleted file mode 100644 index 801542e..0000000 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/CustomDataPermissionChecker.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.agileboot.admin.customize.service.permission.model.checker; - -import cn.hutool.core.collection.CollUtil; -import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker; -import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; -import java.util.Set; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -/** - * 数据权限测试接口 - * @author valarchie - */ -@EqualsAndHashCode(callSuper = true) -@Data -@AllArgsConstructor -@NoArgsConstructor -public class CustomDataPermissionChecker extends AbstractDataPermissionChecker { - - private SysDeptService deptService; - - - @Override - public boolean check(SystemLoginUser loginUser, DataCondition condition) { - if (condition == null || loginUser == null) { - return false; - } - - if (loginUser.getRoleInfo() == null) { - return false; - } - - Set deptIdSet = loginUser.getRoleInfo().getDeptIdSet(); - Long targetDeptId = condition.getTargetDeptId(); - - return condition.getTargetDeptId() != null && CollUtil.safeContains(deptIdSet, targetDeptId); - } -} diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DefaultDataPermissionChecker.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DefaultDataPermissionChecker.java index 44cc15a..ecfae29 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DefaultDataPermissionChecker.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DefaultDataPermissionChecker.java @@ -3,7 +3,6 @@ package com.agileboot.admin.customize.service.permission.model.checker; import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker; import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; import lombok.Data; import lombok.EqualsAndHashCode; @@ -15,8 +14,6 @@ import lombok.EqualsAndHashCode; @Data public class DefaultDataPermissionChecker extends AbstractDataPermissionChecker { - private SysDeptService deptService; - @Override public boolean check(SystemLoginUser loginUser, DataCondition condition) { return false; diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DeptTreeDataPermissionChecker.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DeptTreeDataPermissionChecker.java deleted file mode 100644 index 4f03541..0000000 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/DeptTreeDataPermissionChecker.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.agileboot.admin.customize.service.permission.model.checker; - -import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker; -import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; -import java.util.Objects; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -/** - * 数据权限测试接口 - * @author valarchie - */ -@EqualsAndHashCode(callSuper = true) -@Data -@AllArgsConstructor -@NoArgsConstructor -public class DeptTreeDataPermissionChecker extends AbstractDataPermissionChecker { - - private SysDeptService deptService; - - @Override - public boolean check(SystemLoginUser loginUser, DataCondition condition) { - if (condition == null || loginUser == null) { - return false; - } - - if (loginUser.getDeptId() == null || condition.getTargetDeptId() == null) { - return false; - } - - Long currentDeptId = loginUser.getDeptId(); - Long targetDeptId = condition.getTargetDeptId(); - - boolean isContainsTargetDept = deptService.isChildOfTheDept(loginUser.getDeptId(), targetDeptId); - boolean isSameDept = Objects.equals(currentDeptId, targetDeptId); - - return isContainsTargetDept || isSameDept; - } - -} diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/OnlySelfDataPermissionChecker.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/OnlySelfDataPermissionChecker.java index b1d5554..cb6053b 100644 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/OnlySelfDataPermissionChecker.java +++ b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/OnlySelfDataPermissionChecker.java @@ -3,9 +3,7 @@ package com.agileboot.admin.customize.service.permission.model.checker; import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker; import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; import java.util.Objects; -import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -16,12 +14,9 @@ import lombok.NoArgsConstructor; */ @EqualsAndHashCode(callSuper = true) @Data -@AllArgsConstructor @NoArgsConstructor public class OnlySelfDataPermissionChecker extends AbstractDataPermissionChecker { - private SysDeptService deptService; - @Override public boolean check(SystemLoginUser loginUser, DataCondition condition) { if (condition == null || loginUser == null) { diff --git a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/SingleDeptDataPermissionChecker.java b/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/SingleDeptDataPermissionChecker.java deleted file mode 100644 index 0692db7..0000000 --- a/backend/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/permission/model/checker/SingleDeptDataPermissionChecker.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.agileboot.admin.customize.service.permission.model.checker; - -import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker; -import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; -import java.util.Objects; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -/** - * 数据权限测试接口 - * @author valarchie - */ -@EqualsAndHashCode(callSuper = true) -@Data -@AllArgsConstructor -@NoArgsConstructor -public class SingleDeptDataPermissionChecker extends AbstractDataPermissionChecker { - - private SysDeptService deptService; - - @Override - public boolean check(SystemLoginUser loginUser, DataCondition condition) { - if (condition == null || loginUser == null) { - return false; - } - - if (loginUser.getDeptId() == null || condition.getTargetDeptId() == null) { - return false; - } - - Long currentDeptId = loginUser.getDeptId(); - Long targetDeptId = condition.getTargetDeptId(); - - return Objects.equals(currentDeptId, targetDeptId); - } - - -} diff --git a/backend/agileboot-admin/src/main/resources/application-dev.yml b/backend/agileboot-admin/src/main/resources/application-dev.yml index eab641f..8720fe2 100644 --- a/backend/agileboot-admin/src/main/resources/application-dev.yml +++ b/backend/agileboot-admin/src/main/resources/application-dev.yml @@ -50,7 +50,7 @@ spring: datasource: # 主库数据源 master: - url: jdbc:mysql://localhost:33061/todo_agileboot_pure?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://localhost:3306/todo_agileboot_pure?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: root123 # 从库数据源 @@ -64,7 +64,7 @@ spring: # 地址 host: localhost # 端口,默认为6379 - port: 63791 + port: 6379 # 数据库索引 database: 0 # 密码 diff --git a/backend/agileboot-admin/src/main/resources/application-prod.yml b/backend/agileboot-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..767ddfd --- /dev/null +++ b/backend/agileboot-admin/src/main/resources/application-prod.yml @@ -0,0 +1,65 @@ +# 数据源配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + druid: + webStatFilter: + enabled: true + statViewServlet: + enabled: false + filter: + stat: + enabled: true + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: + primary: master + strict: false + druid: + initialSize: 5 + minIdle: 10 + maxActive: 20 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + maxEvictableIdleTimeMillis: 900000 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + datasource: + master: + url: jdbc:mysql://${MYSQL_HOST:mysql}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:todo_agileboot_pure}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8 + username: ${MYSQL_USERNAME:todo_app} + password: ${MYSQL_PASSWORD:todo_app123} + + redis: + host: ${REDIS_HOST:redis} + port: ${REDIS_PORT:6379} + database: 0 + password: ${REDIS_PASSWORD:redis123} + timeout: 10s + lettuce: + pool: + min-idle: 0 + max-idle: 8 + max-active: 8 + max-wait: -1ms + +logging: + file: + path: /home/agileboot/logs/agileboot-prod + +springdoc: + swagger-ui: + enabled: false + +agileboot: + file-base-dir: /home/agileboot + api-prefix: /dev-api + demo-enabled: false diff --git a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/CustomDataPermissionCheckerTest.java b/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/CustomDataPermissionCheckerTest.java deleted file mode 100644 index 9b2dee0..0000000 --- a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/CustomDataPermissionCheckerTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.agileboot.admin.customize.service.permission; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.agileboot.admin.customize.service.permission.model.checker.CustomDataPermissionChecker; -import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.infrastructure.user.web.RoleInfo; -import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; -import org.apache.commons.collections4.SetUtils; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class CustomDataPermissionCheckerTest { - - private final SysDeptService deptService = mock(SysDeptService.class); - public SystemLoginUser loginUser = mock(SystemLoginUser.class); - - @BeforeEach - public void mockBefore() { - when(loginUser.getRoleInfo()).thenReturn(RoleInfo.EMPTY_ROLE); - } - - @Test - void testCheckWhenParameterNull() { - CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService); - - boolean check1 = customChecker.check(null, null); - boolean check2 = customChecker.check(loginUser, null); - boolean check3 = customChecker.check(null, new DataCondition()); - - assertFalse(check1); - assertFalse(check2); - assertFalse(check3); - } - - @Test - void testCheckWhenTargetDeptIdNull() { - CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService); - - boolean check = customChecker.check(loginUser, new DataCondition(null, 1L)); - - assertFalse(check); - } - - - @Test - void testCheckWhenRoleIsNull() { - CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService); - - when(loginUser.getRoleInfo()).thenReturn(null); - boolean check = customChecker.check(loginUser, new DataCondition(1L, 1L)); - - assertFalse(check); - } - - - @Test - void testCheckWhenNotContainTargetDeptId() { - CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService); - - loginUser.getRoleInfo().setDeptIdSet(SetUtils.hashSet(2L)); - boolean check = customChecker.check(loginUser, new DataCondition(1L, 1L)); - - assertFalse(check); - } - - - @Test - void testCheckWhenContainTargetDeptId() { - CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService); - - loginUser.getRoleInfo().setDeptIdSet(SetUtils.hashSet(1L)); - boolean check = customChecker.check(loginUser, new DataCondition(1L, 1L)); - - assertTrue(check); - } - - -} diff --git a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/DeptTreeDataPermissionCheckerTest.java b/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/DeptTreeDataPermissionCheckerTest.java deleted file mode 100644 index 9e9885f..0000000 --- a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/DeptTreeDataPermissionCheckerTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.agileboot.admin.customize.service.permission; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.agileboot.admin.customize.service.permission.model.checker.DeptTreeDataPermissionChecker; -import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.infrastructure.user.web.RoleInfo; -import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class DeptTreeDataPermissionCheckerTest { - - private final SysDeptService deptService = mock(SysDeptService.class); - - public SystemLoginUser loginUser = mock(SystemLoginUser.class); - - @BeforeEach - public void mockBefore() { - when(loginUser.getRoleInfo()).thenReturn(RoleInfo.EMPTY_ROLE); - } - - @Test - void testCheckWhenParameterNull() { - DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService); - - boolean check1 = checker.check(null, null); - boolean check2 = checker.check(new SystemLoginUser(), null); - boolean check3 = checker.check(null, new DataCondition()); - boolean check4 = checker.check(loginUser, new DataCondition()); - - assertFalse(check1); - assertFalse(check2); - assertFalse(check3); - assertFalse(check4); - } - - - @Test - void testCheckWhenIsChildOfDept() { - DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService); - - when(deptService.isChildOfTheDept(any(), any())).thenReturn(true); - when(loginUser.getDeptId()).thenReturn(1L); - - DataCondition dataCondition = new DataCondition(); - dataCondition.setTargetDeptId(2L); - - boolean check = checker.check(loginUser, dataCondition); - - assertTrue(check); - } - - - @Test - void testCheckWhenIsSameDept() { - DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService); - - when(deptService.isChildOfTheDept(any(), any())).thenReturn(false); - when(loginUser.getDeptId()).thenReturn(1L); - DataCondition dataCondition = new DataCondition(); - dataCondition.setTargetDeptId(1L); - - boolean check = checker.check(loginUser, dataCondition); - - assertTrue(check); - } - - - @Test - void testCheckWhenFailed() { - DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService); - - when(deptService.isChildOfTheDept(any(), any())).thenReturn(false); - when(loginUser.getDeptId()).thenReturn(1L); - DataCondition dataCondition = new DataCondition(); - dataCondition.setTargetDeptId(2L); - - boolean check = checker.check(loginUser, dataCondition); - - assertFalse(check); - } - - - - -} diff --git a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/OnlySelfDataPermissionCheckerTest.java b/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/OnlySelfDataPermissionCheckerTest.java index 94d3759..f3d30b9 100644 --- a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/OnlySelfDataPermissionCheckerTest.java +++ b/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/OnlySelfDataPermissionCheckerTest.java @@ -2,21 +2,17 @@ package com.agileboot.admin.customize.service.permission; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; import com.agileboot.admin.customize.service.permission.model.checker.OnlySelfDataPermissionChecker; import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; import org.junit.jupiter.api.Test; class OnlySelfDataPermissionCheckerTest { - private final SysDeptService deptService = mock(SysDeptService.class); - @Test void testCheckWhenParameterNull() { - OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(deptService); + OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(); boolean check1 = checker.check(null, null); boolean check2 = checker.check(new SystemLoginUser(), null); @@ -31,7 +27,7 @@ class OnlySelfDataPermissionCheckerTest { @Test void testCheckWhenSameUserId() { - OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(deptService); + OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(); SystemLoginUser loginUser = new SystemLoginUser(); loginUser.setUserId(1L); DataCondition dataCondition = new DataCondition(); @@ -45,11 +41,11 @@ class OnlySelfDataPermissionCheckerTest { @Test void testCheckWhenDifferentUserId() { - OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(deptService); + OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(); SystemLoginUser loginUser = new SystemLoginUser(); loginUser.setUserId(1L); DataCondition dataCondition = new DataCondition(); - dataCondition.setTargetDeptId(2L); + dataCondition.setTargetUserId(2L); boolean check = checker.check(loginUser, dataCondition); diff --git a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/SingleDeptDataPermissionCheckerTest.java b/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/SingleDeptDataPermissionCheckerTest.java deleted file mode 100644 index 03b03ce..0000000 --- a/backend/agileboot-admin/src/test/java/com/agileboot/admin/customize/service/permission/SingleDeptDataPermissionCheckerTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.agileboot.admin.customize.service.permission; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.agileboot.admin.customize.service.permission.model.checker.SingleDeptDataPermissionChecker; -import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.infrastructure.user.web.RoleInfo; -import com.agileboot.admin.customize.service.permission.model.DataCondition; -import com.agileboot.domain.system.dept.db.SysDeptService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class SingleDeptDataPermissionCheckerTest { - - private final SysDeptService deptService = mock(SysDeptService.class); - - public SystemLoginUser loginUser = mock(SystemLoginUser.class); - - @BeforeEach - public void mockBefore() { - when(loginUser.getRoleInfo()).thenReturn(RoleInfo.EMPTY_ROLE); - } - - - @Test - void testCheckWhenParameterNull() { - SingleDeptDataPermissionChecker checker = new SingleDeptDataPermissionChecker(deptService); - - boolean check1 = checker.check(null, null); - boolean check2 = checker.check(new SystemLoginUser(), null); - boolean check3 = checker.check(null, new DataCondition()); - boolean check4 = checker.check(loginUser, new DataCondition()); - - assertFalse(check1); - assertFalse(check2); - assertFalse(check3); - assertFalse(check4); - } - - @Test - void testCheckWhenSameDeptId() { - SingleDeptDataPermissionChecker checker = new SingleDeptDataPermissionChecker(deptService); - when(loginUser.getDeptId()).thenReturn(1L); - DataCondition dataCondition = new DataCondition(); - dataCondition.setTargetDeptId(1L); - - boolean check = checker.check(loginUser, dataCondition); - - assertTrue(check); - } - - - @Test - void testCheckWhenDifferentDeptId() { - SingleDeptDataPermissionChecker checker = new SingleDeptDataPermissionChecker(deptService); - when(loginUser.getDeptId()).thenReturn(1L); - DataCondition dataCondition = new DataCondition(); - dataCondition.setTargetUserId(2L); - - boolean check = checker.check(loginUser, dataCondition); - - assertFalse(check); - } - - - - - -} diff --git a/backend/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java b/backend/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java index f693e52..ac83780 100644 --- a/backend/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java +++ b/backend/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java @@ -118,28 +118,6 @@ public enum ErrorCode implements ErrorCodeInterface { CONFIG_VALUE_IS_NOT_IN_OPTIONS(10602, "参数键值不存在列表中", "Business.CONFIG_VALUE_IS_NOT_IN_OPTIONS"), - // ------------------------------- POST -------------------------------------------- - - POST_NAME_IS_NOT_UNIQUE(10701, "岗位名称:{}, 已存在", "Business.POST_NAME_IS_NOT_UNIQUE"), - - POST_CODE_IS_NOT_UNIQUE(10702, "岗位编号:{}, 已存在", "Business.POST_CODE_IS_NOT_UNIQUE"), - - POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED(10703, "职位已分配给用户,请先取消分配再删除", "Business.POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED"), - - // ------------------------------- DEPT --------------------------------------------- - - DEPT_NAME_IS_NOT_UNIQUE(10801, "部门名称:{}, 已存在", "Business.DEPT_NAME_IS_NOT_UNIQUE"), - - DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF(10802, "父级部门不能选择自己", "Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF"), - - DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE(10803, "子部门还有正在启用的部门,暂时不能停用该部门", "Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE"), - - DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE(10804, "该部门存在下级部门不允许删除", "Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE"), - - DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE(10805, "该部门存在关联的用户不允许删除", "Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE"), - - DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED(10806, "该父级部门不存在或已停用", "Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED"), - // ------------------------------- MENU ------------------------------------------------- MENU_NAME_IS_NOT_UNIQUE(10901, "新增菜单:{} 失败,菜单名称已存在", "Business.MENU_NAME_IS_NOT_UNIQUE"), @@ -164,8 +142,6 @@ public enum ErrorCode implements ErrorCodeInterface { ROLE_KEY_IS_NOT_UNIQUE(11002, "角色标识:{}, 已存在", "Business.ROLE_KEY_IS_NOT_UNIQUE"), - ROLE_DATA_SCOPE_DUPLICATED_DEPT(11003, "重复的部门id", "Business.ROLE_DATA_SCOPE_DUPLICATED_DEPT"), - ROLE_ALREADY_ASSIGN_TO_USER(11004, "角色已分配给用户,请先取消分配,再删除角色", "Business.ROLE_ALREADY_ASSIGN_TO_USER"), ROLE_IS_NOT_AVAILABLE(11005, "角色:{} 已禁用,无法分配给用户", "Business.ROLE_IS_NOT_AVAILABLE"), @@ -180,8 +156,6 @@ public enum ErrorCode implements ErrorCodeInterface { USER_FAIL_TO_GET_USER_ID(11004, "获取用户ID失败", "Business.USER_FAIL_TO_GET_USER_ID"), - USER_FAIL_TO_GET_DEPT_ID(10504, "获取用户部门ID失败", "Business.USER_FAIL_TO_GET_DEPT_ID"), - USER_FAIL_TO_GET_ACCOUNT(10505, "获取用户账户失败", "Business.USER_FAIL_TO_GET_ACCOUNT"), USER_FAIL_TO_GET_USER_INFO(10506, "获取用户信息失败", "Business.USER_FAIL_TO_GET_USER_INFO"), @@ -204,6 +178,12 @@ public enum ErrorCode implements ErrorCodeInterface { USER_ADMIN_CAN_NOT_BE_MODIFY(10515, "管理员不允许做任何修改", "Business.USER_ADMIN_CAN_NOT_BE_MODIFY"), + USER_REGISTER_IS_CLOSED(10516, "当前系统未开启用户注册功能", "Business.USER_REGISTER_IS_CLOSED"), + + USER_REGISTER_PASSWORD_NOT_MATCH(10517, "两次输入的密码不一致", "Business.USER_REGISTER_PASSWORD_NOT_MATCH"), + + USER_PASSWORD_IS_EMPTY(10518, "密码不能为空", "Business.USER_PASSWORD_IS_EMPTY"), + ; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java index 099b2d9..36b435c 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/CollaborationRecordApplicationService.java @@ -1,6 +1,9 @@ package com.agileboot.domain.collaboration.record; +import cn.hutool.core.util.StrUtil; import com.agileboot.common.core.page.PageDTO; +import com.agileboot.common.exception.ApiException; +import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.domain.collaboration.record.command.AddCollaborationRecordCommand; import com.agileboot.domain.collaboration.record.command.CollaborationExpenditureCommand; import com.agileboot.domain.collaboration.record.command.CollaborationFileCommand; @@ -32,6 +35,8 @@ import com.agileboot.domain.collaboration.record.model.CollaborationRecordModel; import com.agileboot.domain.collaboration.record.model.CollaborationRecordModelFactory; import com.agileboot.domain.collaboration.record.query.CollaborationRecordQuery; import com.agileboot.domain.common.command.BulkOperationCommand; +import com.agileboot.infrastructure.user.AuthenticationUtils; +import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import java.math.BigDecimal; @@ -42,6 +47,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -57,6 +63,8 @@ public class CollaborationRecordApplicationService { private static final String PURCHASE_FEE = "拍单费用"; private static final String DELIVERY_FEE = "快递费用"; private static final String REMUNERATION_FEE = "稿费"; + private static final String TASK_STATUS_COMPLETED = "COMPLETED"; + private static final String TASK_STATUS_INCOMPLETE = "INCOMPLETE"; private final CollaborationRecordModelFactory recordModelFactory; private final CollaborationRecordService recordService; @@ -66,7 +74,10 @@ public class CollaborationRecordApplicationService { private final CollaborationFileService fileService; public PageDTO getRecordList(CollaborationRecordQuery query) { - Page page = recordService.page(query.toPage(), query.toQueryWrapper()); + if (hasComputedFilters(query)) { + return getComputedFilteredRecordList(query); + } + Page page = recordService.page(query.toPage(), getScopedRecordWrapper(query)); List records = page.getRecords().stream() .map(this::buildRecordDTO) .collect(Collectors.toList()); @@ -74,7 +85,7 @@ public class CollaborationRecordApplicationService { } public CollaborationRecordDetailDTO getRecordInfo(Long recordId) { - CollaborationRecordModel model = recordModelFactory.loadById(recordId); + CollaborationRecordModel model = loadRecordInScope(recordId); CollaborationRecordDetailDTO dto = new CollaborationRecordDetailDTO(model); fillDetailChildren(dto, recordId); fillRecordStats(dto, recordId); @@ -85,14 +96,16 @@ public class CollaborationRecordApplicationService { public void addRecord(AddCollaborationRecordCommand command) { CollaborationRecordModel model = recordModelFactory.create(); model.loadFromAddCommand(command); + model.setCompleteDate(getRecordCompleteDate(command.getTasks(), CollaborationTaskCommand::getReleaseDate)); model.saveRecord(); saveChildren(model.getRecordId(), command); } @Transactional(rollbackFor = Exception.class) public void updateRecord(UpdateCollaborationRecordCommand command) { - CollaborationRecordModel model = recordModelFactory.loadById(command.getRecordId()); + CollaborationRecordModel model = loadRecordInScope(command.getRecordId()); model.loadFromUpdateCommand(command); + model.setCompleteDate(getRecordCompleteDate(command.getTasks(), CollaborationTaskCommand::getReleaseDate)); model.updateRecord(); replaceChildren(command.getRecordId(), command); } @@ -103,6 +116,7 @@ public class CollaborationRecordApplicationService { if (ids == null || ids.isEmpty()) { return; } + checkAllRecordsInScope(ids); taskService.removeByRecordIds(ids); expenditureService.removeByRecordIds(ids); settlementService.removeByRecordIds(ids); @@ -124,6 +138,108 @@ public class CollaborationRecordApplicationService { return statistics; } + private QueryWrapper getScopedRecordWrapper(CollaborationRecordQuery query) { + QueryWrapper wrapper = query.toQueryWrapper(); + applyCurrentCreatorScope(wrapper); + return wrapper; + } + + private PageDTO getComputedFilteredRecordList(CollaborationRecordQuery query) { + List records = recordService.list(getScopedRecordWrapper(query)).stream() + .map(this::buildRecordDTO) + .filter(record -> matchesComputedFilters(record, query)) + .collect(Collectors.toList()); + return new PageDTO<>(pageRecords(records, query), (long) records.size()); + } + + private List pageRecords(List records, CollaborationRecordQuery query) { + Page page = query.toPage(); + int start = (int) Math.min((page.getCurrent() - 1) * page.getSize(), records.size()); + int end = (int) Math.min(start + page.getSize(), records.size()); + return records.subList(start, end); + } + + private boolean hasComputedFilters(CollaborationRecordQuery query) { + return StrUtil.isNotEmpty(query.getSettlementStatus()) || StrUtil.isNotEmpty(query.getTaskStatus()); + } + + private boolean matchesComputedFilters(CollaborationRecordDTO record, CollaborationRecordQuery query) { + return matchesSettlementStatus(record, query.getSettlementStatus()) + && matchesTaskStatus(record, query.getTaskStatus()); + } + + private boolean matchesSettlementStatus(CollaborationRecordDTO record, String status) { + if (StrUtil.isEmpty(status)) { + return true; + } + return status.equals(getRecordSettlementStatus(record)); + } + + private String getRecordSettlementStatus(CollaborationRecordDTO record) { + return SettlementStatusEnum.aggregate(Arrays.asList( + getSettlementStatusValue(record.getPurchaseSettlementStatus()), + getSettlementStatusValue(record.getDeliverySettlementStatus()), + getSettlementStatusValue(record.getRemunerationSettlementStatus()) + )); + } + + private String getSettlementStatusValue(SettlementStatusDTO status) { + return status == null ? SettlementStatusEnum.NONE.getValue() : status.getStatus(); + } + + private boolean matchesTaskStatus(CollaborationRecordDTO record, String status) { + if (StrUtil.isEmpty(status)) { + return true; + } + boolean isCompleted = isRecordCompleted(record); + if (TASK_STATUS_COMPLETED.equals(status)) { + return isCompleted; + } + return TASK_STATUS_INCOMPLETE.equals(status) && !isCompleted; + } + + private boolean isRecordCompleted(CollaborationRecordDTO record) { + Integer tasksNum = record.getTasksNum(); + Integer completedTasksNum = record.getCompletedTasksNum(); + return tasksNum != null && tasksNum > 0 && tasksNum.equals(completedTasksNum); + } + + private CollaborationRecordModel loadRecordInScope(Long recordId) { + CollaborationRecordEntity entity = recordService.getOne(buildScopedRecordIdWrapper(recordId)); + if (entity == null) { + throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, recordId, "合作记录"); + } + return new CollaborationRecordModel(entity, recordService); + } + + private QueryWrapper buildScopedRecordIdWrapper(Long recordId) { + QueryWrapper wrapper = new QueryWrapper() + .eq("record_id", recordId); + applyCurrentCreatorScope(wrapper); + return wrapper; + } + + private void checkAllRecordsInScope(Set ids) { + QueryWrapper wrapper = new QueryWrapper() + .in("record_id", ids); + applyCurrentCreatorScope(wrapper); + if (recordService.count(wrapper) != ids.size()) { + throw new ApiException(ErrorCode.Business.PERMISSION_NOT_ALLOWED_TO_OPERATE); + } + } + + private void applyCurrentCreatorScope(QueryWrapper wrapper) { + Long creatorId = getCurrentCreatorScope(); + if (creatorId != null) { + wrapper.eq("creator_id", creatorId); + } + } + + private Long getCurrentCreatorScope() { + SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); + return loginUser.isAdmin() ? null : loginUser.getUserId(); + } + private CollaborationRecordDTO buildRecordDTO(CollaborationRecordEntity entity) { CollaborationRecordDTO dto = new CollaborationRecordDTO(entity); fillRecordStats(dto, entity.getRecordId()); @@ -151,11 +267,25 @@ public class CollaborationRecordApplicationService { List settlements = settlementService.listByRecordId(recordId); dto.setTasksNum(tasks.size()); dto.setCompletedTasksNum((int) tasks.stream().filter(item -> item.getReleaseDate() != null).count()); + dto.setCompleteDate(getRecordCompleteDate(tasks, CollaborationTaskEntity::getReleaseDate)); dto.setPurchaseSettlementStatus(getStatus(dto.getPurchasePrice(), settlements, PURCHASE_FEE)); dto.setDeliverySettlementStatus(getStatus(sumExpenditure(expenditures, DELIVERY_FEE), settlements, DELIVERY_FEE)); dto.setRemunerationSettlementStatus(getStatus(dto.getRemuneration(), settlements, REMUNERATION_FEE)); } + private Date getRecordCompleteDate(List tasks, Function getReleaseDate) { + if (tasks == null || tasks.isEmpty()) { + return null; + } + if (tasks.stream().anyMatch(item -> getReleaseDate.apply(item) == null)) { + return null; + } + return tasks.stream() + .map(getReleaseDate) + .max(Date::compareTo) + .orElse(null); + } + private SettlementStatusDTO getStatus( BigDecimal expectedAmount, List settlements, String purpose) { List matched = filterSettlements(settlements, purpose); @@ -335,9 +465,11 @@ public class CollaborationRecordApplicationService { } private BigDecimal sumPurchasePrice(Date[] range) { - List records = recordService.list(new QueryWrapper() + QueryWrapper wrapper = new QueryWrapper() .ge("purchase_date", range[0]) - .le("purchase_date", range[1])); + .le("purchase_date", range[1]); + applyCurrentCreatorScope(wrapper); + List records = recordService.list(wrapper); return records.stream() .map(CollaborationRecordEntity::getPurchasePrice) .map(this::defaultAmount) @@ -345,8 +477,11 @@ public class CollaborationRecordApplicationService { } private BigDecimal sumExpenditure(Date[] range) { - List expenditures = expenditureService.list( - new QueryWrapper().ge("spend_date", range[0]).le("spend_date", range[1])); + QueryWrapper wrapper = new QueryWrapper() + .ge("spend_date", range[0]) + .le("spend_date", range[1]); + applyChildRecordScope(wrapper); + List expenditures = expenditureService.list(wrapper); return expenditures.stream() .map(CollaborationExpenditureEntity::getAmount) .map(this::defaultAmount) @@ -358,9 +493,21 @@ public class CollaborationRecordApplicationService { .ge("settle_date", range[0]) .le("settle_date", range[1]) .eq(purpose != null, "purpose", purpose); + applyChildRecordScope(wrapper); return sumSettlement(settlementService.list(wrapper)); } + private void applyChildRecordScope(QueryWrapper wrapper) { + Long creatorId = getCurrentCreatorScope(); + if (creatorId != null) { + wrapper.inSql("record_id", buildCreatorRecordSubQuery(creatorId)); + } + } + + private String buildCreatorRecordSubQuery(Long creatorId) { + return "select record_id from collaboration_record where deleted = 0 and creator_id = " + creatorId; + } + private BigDecimal sumExpenditure(List expenditures, String purpose) { return expenditures.stream() .filter(item -> purpose.equals(item.getPurpose())) diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnum.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnum.java index f36566e..b70143a 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnum.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnum.java @@ -1,5 +1,8 @@ package com.agileboot.domain.collaboration.record.enumtype; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; import lombok.Getter; /** @@ -24,4 +27,31 @@ public enum SettlementStatusEnum { this.label = label; } + public static String aggregate(Collection statuses) { + if (statuses == null || statuses.isEmpty()) { + return NONE.value; + } + List effectiveStatuses = statuses.stream() + .filter(SettlementStatusEnum::isEffectiveStatus) + .collect(Collectors.toList()); + if (effectiveStatuses.isEmpty()) { + return NONE.value; + } + if (isSameStatus(effectiveStatuses, SETTLED)) { + return SETTLED.value; + } + if (isSameStatus(effectiveStatuses, UNSETTLED)) { + return UNSETTLED.value; + } + return PARTIAL.value; + } + + private static boolean isEffectiveStatus(String status) { + return status != null && !NONE.value.equals(status); + } + + private static boolean isSameStatus(List statuses, SettlementStatusEnum expected) { + return statuses.stream().allMatch(status -> expected.value.equals(status)); + } + } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/model/CollaborationRecordModel.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/model/CollaborationRecordModel.java index 7e53f0a..995ffc2 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/model/CollaborationRecordModel.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/model/CollaborationRecordModel.java @@ -33,7 +33,7 @@ public class CollaborationRecordModel extends CollaborationRecordEntity { if (command == null) { return; } - BeanUtil.copyProperties(command, this, "recordId"); + BeanUtil.copyProperties(command, this, "recordId", "completeDate"); loadDefaultValues(); } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java index d8df66c..d93e510 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/collaboration/record/query/CollaborationRecordQuery.java @@ -23,6 +23,10 @@ public class CollaborationRecordQuery extends AbstractPageQuery configCache; - public static AbstractGuavaCacheTemplate deptCache; - public static RedisCacheTemplate captchaCache; public static RedisCacheTemplate loginUserCache; @@ -32,21 +28,17 @@ public class CacheCenter { public static RedisCacheTemplate roleCache; - public static RedisCacheTemplate postCache; - @PostConstruct public void init() { GuavaCacheService guavaCache = SpringUtil.getBean(GuavaCacheService.class); RedisCacheService redisCache = SpringUtil.getBean(RedisCacheService.class); configCache = guavaCache.configCache; - deptCache = guavaCache.deptCache; captchaCache = redisCache.captchaCache; loginUserCache = redisCache.loginUserCache; userCache = redisCache.userCache; roleCache = redisCache.roleCache; - postCache = redisCache.postCache; } } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/GuavaCacheService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/GuavaCacheService.java index 9abfbf5..cf0e1af 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/GuavaCacheService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/GuavaCacheService.java @@ -2,9 +2,7 @@ package com.agileboot.domain.common.cache; import com.agileboot.infrastructure.cache.guava.AbstractGuavaCacheTemplate; -import com.agileboot.domain.system.dept.db.SysDeptEntity; import com.agileboot.domain.system.config.db.SysConfigService; -import com.agileboot.domain.system.dept.db.SysDeptService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -19,8 +17,6 @@ public class GuavaCacheService { private final SysConfigService configService; - private final SysDeptService deptService; - public final AbstractGuavaCacheTemplate configCache = new AbstractGuavaCacheTemplate() { @Override public String getObjectFromDb(Object id) { @@ -28,12 +24,4 @@ public class GuavaCacheService { } }; - public final AbstractGuavaCacheTemplate deptCache = new AbstractGuavaCacheTemplate() { - @Override - public SysDeptEntity getObjectFromDb(Object id) { - return deptService.getById(id.toString()); - } - }; - - } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/RedisCacheService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/RedisCacheService.java index 3f893ea..a48cfbf 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/RedisCacheService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/RedisCacheService.java @@ -5,10 +5,8 @@ import com.agileboot.infrastructure.cache.RedisUtil; import com.agileboot.infrastructure.cache.redis.CacheKeyEnum; import com.agileboot.infrastructure.cache.redis.RedisCacheTemplate; import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; import com.agileboot.domain.system.user.db.SysUserEntity; -import com.agileboot.domain.system.post.db.SysPostService; import com.agileboot.domain.system.role.db.SysRoleService; import com.agileboot.domain.system.user.db.SysUserService; import java.io.Serializable; @@ -30,8 +28,6 @@ public class RedisCacheService { public RedisCacheTemplate userCache; public RedisCacheTemplate roleCache; - public RedisCacheTemplate postCache; - // public RedisCacheTemplate roleModelInfoCache; @PostConstruct @@ -66,16 +62,6 @@ public class RedisCacheService { // // }; - postCache = new RedisCacheTemplate(redisUtil, CacheKeyEnum.POST_ENTITY_KEY) { - @Override - public SysPostEntity getObjectFromDb(Object id) { - SysPostService postService = SpringUtil.getBean(SysPostService.class); - return postService.getById((Serializable) id); - } - - }; - - } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/dto/TreeSelectedDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/dto/TreeSelectedDTO.java index 23591a4..c090839 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/dto/TreeSelectedDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/common/dto/TreeSelectedDTO.java @@ -14,6 +14,5 @@ public class TreeSelectedDTO { private List checkedKeys; private List> menus; - private List> depts; } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/DeptApplicationService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/DeptApplicationService.java deleted file mode 100644 index 96e4882..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/DeptApplicationService.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.agileboot.domain.system.dept; - -import cn.hutool.core.lang.tree.Tree; -import cn.hutool.core.lang.tree.TreeUtil; -import com.agileboot.domain.system.dept.command.AddDeptCommand; -import com.agileboot.domain.system.dept.command.UpdateDeptCommand; -import com.agileboot.domain.system.dept.dto.DeptDTO; -import com.agileboot.domain.system.dept.model.DeptModel; -import com.agileboot.domain.system.dept.model.DeptModelFactory; -import com.agileboot.domain.system.dept.query.DeptQuery; -import com.agileboot.domain.system.dept.db.SysDeptEntity; -import com.agileboot.domain.system.dept.db.SysDeptService; -import com.agileboot.domain.system.role.db.SysRoleService; -import java.util.List; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -/** - * 部门服务 - * @author valarchie - */ -@Service -@RequiredArgsConstructor -public class DeptApplicationService { - - private final SysDeptService deptService; - - private final SysRoleService roleService; - - private final DeptModelFactory deptModelFactory; - - - public List getDeptList(DeptQuery query) { - List list = deptService.list(query.toQueryWrapper()); - return list.stream().map(DeptDTO::new).collect(Collectors.toList()); - } - - public DeptDTO getDeptInfo(Long id) { - SysDeptEntity byId = deptService.getById(id); - return new DeptDTO(byId); - } - - public List> getDeptTree() { - List list = deptService.list(); - - return TreeUtil.build(list, 0L, (dept, tree) -> { - tree.setId(dept.getDeptId()); - tree.setParentId(dept.getParentId()); - tree.putExtra("label", dept.getDeptName()); - }); - } - - - public void addDept(AddDeptCommand addCommand) { - DeptModel deptModel = deptModelFactory.create(); - deptModel.loadAddCommand(addCommand); - - deptModel.checkDeptNameUnique(); - deptModel.generateAncestors(); - - deptModel.insert(); - } - - public void updateDept(UpdateDeptCommand updateCommand) { - DeptModel deptModel = deptModelFactory.loadById(updateCommand.getDeptId()); - deptModel.loadUpdateCommand(updateCommand); - - deptModel.checkDeptNameUnique(); - deptModel.checkParentIdConflict(); - deptModel.checkStatusAllowChange(); - deptModel.generateAncestors(); - - deptModel.updateById(); - } - - public void removeDept(Long deptId) { - DeptModel deptModel = deptModelFactory.loadById(deptId); - - deptModel.checkHasChildDept(); - deptModel.checkDeptAssignedToUsers(); - - deptModel.deleteById(); - } - - - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/AddDeptCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/AddDeptCommand.java deleted file mode 100644 index 58f10f1..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/AddDeptCommand.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.agileboot.domain.system.dept.command; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; -import javax.validation.constraints.Size; -import lombok.Data; - -/** - * @author valarchie - */ -@Data -public class AddDeptCommand { - - /** - * 父部门ID - */ - @NotNull - @PositiveOrZero - private Long parentId; - - /** - * 部门名称 - */ - @NotBlank(message = "部门名称不能为空") - @Size(max = 30, message = "部门名称长度不能超过30个字符") - private String deptName; - - /** - * 显示顺序 - */ - @NotNull(message = "显示顺序不能为空") - private Integer orderNum; - - /** - * 负责人 - */ - private String leaderName; - - /** - * 联系电话 - */ - @Size(max = 11, message = "联系电话长度不能超过11个字符") - private String phone; - - /** - * 邮箱 - */ - @Email(message = "邮箱格式不正确") - @Size(max = 50, message = "邮箱长度不能超过50个字符") - private String email; - - - private Integer status; - - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/UpdateDeptCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/UpdateDeptCommand.java deleted file mode 100644 index a75cd13..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/command/UpdateDeptCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.agileboot.domain.system.dept.command; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @author valarchie - */ -@EqualsAndHashCode(callSuper = true) -@Data -public class UpdateDeptCommand extends AddDeptCommand { - - @NotNull - @PositiveOrZero - private Long deptId; - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptEntity.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptEntity.java deleted file mode 100644 index e3e75df..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptEntity.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.agileboot.domain.system.dept.db; - -import com.agileboot.common.core.base.BaseEntity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.io.Serializable; -import lombok.Getter; -import lombok.Setter; - -/** - *

- * 部门表 - *

- * - * @author valarchie - * @since 2022-10-02 - */ -@Getter -@Setter -@TableName("sys_dept") -@ApiModel(value = "SysDeptEntity对象", description = "部门表") -public class SysDeptEntity extends BaseEntity { - - private static final long serialVersionUID = 1L; - - @ApiModelProperty("部门id") - @TableId(value = "dept_id", type = IdType.AUTO) - private Long deptId; - - @ApiModelProperty("父部门id") - @TableField("parent_id") - private Long parentId; - - @ApiModelProperty("祖级列表") - @TableField("ancestors") - private String ancestors; - - @ApiModelProperty("部门名称") - @TableField("dept_name") - private String deptName; - - @ApiModelProperty("显示顺序") - @TableField("order_num") - private Integer orderNum; - - @TableField("leader_id") - private Long leaderId; - - @ApiModelProperty("负责人") - @TableField("leader_name") - private String leaderName; - - @ApiModelProperty("联系电话") - @TableField("phone") - private String phone; - - @ApiModelProperty("邮箱") - @TableField("email") - private String email; - - @ApiModelProperty("部门状态(0正常 1停用)") - @TableField("`status`") - private Integer status; - - - @Override - public Serializable pkVal() { - return this.deptId; - } - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptMapper.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptMapper.java deleted file mode 100644 index d6b35c5..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.agileboot.domain.system.dept.db; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - *

- * 部门表 Mapper 接口 - *

- * - * @author valarchie - * @since 2022-06-16 - */ -public interface SysDeptMapper extends BaseMapper { - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptService.java deleted file mode 100644 index 8be89d0..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptService.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.agileboot.domain.system.dept.db; - -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 部门表 服务类 - *

- * - * @author valarchie - * @since 2022-06-16 - */ -public interface SysDeptService extends IService { - - - /** - * 检测部门名称是否一致 - * - * @param deptName 部门名称 - * @param deptId 部门id - * @param parentId 父级部门id - * @return 校验结果 - */ - boolean isDeptNameDuplicated(String deptName, Long deptId, Long parentId); - - /** - * 检测部门底下是否还有正在使用中的子部门 - * @param deptId 部门id - * @param enabled 部门是否开启 - * @return 结果 - */ - boolean hasChildrenDept(Long deptId, Boolean enabled); - - /** - * 是否是目标部门的子部门 - * @param parentId 目标部门id - * @param childId 子部门id - * @return 校验结果 - */ - boolean isChildOfTheDept(Long parentId, Long childId); - - /** - * 检测该部门是否已有用户使用 - * @param deptId 部门id - * @return 校验结果 - */ - boolean isDeptAssignedToUsers(Long deptId); - - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptServiceImpl.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptServiceImpl.java deleted file mode 100644 index 55bd9fb..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/db/SysDeptServiceImpl.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.agileboot.domain.system.dept.db; - -import com.agileboot.domain.system.user.db.SysUserEntity; -import com.agileboot.domain.system.user.db.SysUserMapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -/** - *

- * 部门表 服务实现类 - *

- * - * @author valarchie - * @since 2022-06-16 - */ -@Service -@RequiredArgsConstructor -public class SysDeptServiceImpl extends ServiceImpl implements SysDeptService { - - private final SysUserMapper userMapper; - - - @Override - public boolean isDeptNameDuplicated(String deptName, Long deptId, Long parentId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("dept_name", deptName) - .ne(deptId != null, "dept_id", deptId) - .eq(parentId != null, "parent_id", parentId); - - return this.baseMapper.exists(queryWrapper); - } - - - @Override - public boolean hasChildrenDept(Long deptId, Boolean enabled) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq(enabled != null, "status", 1) - .and(o -> o.eq("parent_id", deptId).or() - .apply("FIND_IN_SET (" + deptId + " , ancestors)") - ); - return this.baseMapper.exists(queryWrapper); - } - - - @Override - public boolean isChildOfTheDept(Long parentId, Long childId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.apply("dept_id = '" + childId + "' and FIND_IN_SET ( " + parentId + " , ancestors)"); - return this.baseMapper.exists(queryWrapper); - } - - - @Override - public boolean isDeptAssignedToUsers(Long deptId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("dept_id", deptId); - return userMapper.exists(queryWrapper); - } - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/dto/DeptDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/dto/DeptDTO.java deleted file mode 100644 index fd78f43..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/dto/DeptDTO.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.agileboot.domain.system.dept.dto; - -import com.agileboot.common.enums.common.StatusEnum; -import com.agileboot.common.enums.BasicEnumUtil; -import com.agileboot.domain.system.dept.db.SysDeptEntity; -import java.util.Date; -import lombok.Data; - -/** - * @author valarchie - */ -@Data -public class DeptDTO { - - public DeptDTO(SysDeptEntity entity) { - if (entity != null) { - this.id = entity.getDeptId(); - this.parentId = entity.getParentId(); - this.deptName = entity.getDeptName(); - this.orderNum = entity.getOrderNum(); - this.leaderName = entity.getLeaderName(); - this.email = entity.getEmail(); - this.phone = entity.getPhone(); - this.status = entity.getStatus(); - this.createTime = entity.getCreateTime(); - this.statusStr = BasicEnumUtil.getDescriptionByValue(StatusEnum.class, entity.getStatus()); - } - } - - - private Long id; - - private Long parentId; - - private String deptName; - - private Integer orderNum; - - private String leaderName; - - private String phone; - - private String email; - - private Integer status; - - private String statusStr; - - private Date createTime; - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModel.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModel.java deleted file mode 100644 index edd84b8..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModel.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.agileboot.domain.system.dept.model; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.convert.Convert; -import com.agileboot.common.exception.ApiException; -import com.agileboot.common.exception.error.ErrorCode; -import com.agileboot.domain.system.dept.command.AddDeptCommand; -import com.agileboot.domain.system.dept.command.UpdateDeptCommand; -import com.agileboot.common.enums.common.StatusEnum; -import com.agileboot.common.enums.BasicEnumUtil; -import com.agileboot.domain.system.dept.db.SysDeptEntity; -import com.agileboot.domain.system.dept.db.SysDeptService; -import java.util.Objects; - -/** - * @author valarchie - */ -public class DeptModel extends SysDeptEntity { - - private final SysDeptService deptService; - - public DeptModel(SysDeptService deptService) { - this.deptService = deptService; - } - - public DeptModel(SysDeptEntity entity, SysDeptService deptService) { - if (entity != null) { - // 如果大数据量的话 可以用MapStruct优化 - BeanUtil.copyProperties(entity, this); - } - this.deptService = deptService; - } - - public void loadAddCommand(AddDeptCommand addCommand) { - this.setParentId(addCommand.getParentId()); - this.setDeptName(addCommand.getDeptName()); - this.setOrderNum(addCommand.getOrderNum()); - this.setLeaderName(addCommand.getLeaderName()); - this.setPhone(addCommand.getPhone()); - this.setEmail(addCommand.getEmail()); - this.setStatus(addCommand.getStatus()); - } - - public void loadUpdateCommand(UpdateDeptCommand updateCommand) { - loadAddCommand(updateCommand); - setStatus(Convert.toInt(updateCommand.getStatus(), 0)); - } - - public void checkDeptNameUnique() { - if (deptService.isDeptNameDuplicated(getDeptName(), getDeptId(), getParentId())) { - throw new ApiException(ErrorCode.Business.DEPT_NAME_IS_NOT_UNIQUE, getDeptName()); - } - } - - public void checkParentIdConflict() { - if (Objects.equals(getParentId(), getDeptId())) { - throw new ApiException(ErrorCode.Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF); - } - } - - public void checkHasChildDept() { - if (deptService.hasChildrenDept(getDeptId(), null)) { - throw new ApiException(ErrorCode.Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE); - } - } - - public void checkDeptAssignedToUsers() { - if (deptService.isDeptAssignedToUsers(getDeptId())) { - throw new ApiException(ErrorCode.Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE); - } - } - - public void generateAncestors() { - - // 处理 getParentId 可能为 null 的情况 - if (getParentId() == null || getParentId() == 0) { - setAncestors(String.valueOf(getParentId() == null ? 0 : getParentId())); - return; - } - - SysDeptEntity parentDept = deptService.getById(getParentId()); - - // 检查 parentDept 是否为 null 或者状态为禁用 - if (parentDept == null || StatusEnum.DISABLE.equals( - BasicEnumUtil.fromValue(StatusEnum.class, parentDept.getStatus()))) { - throw new ApiException(ErrorCode.Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED); - } - - // 处理 parentDept.getAncestors() 可能为 null 的情况 - String ancestors = parentDept.getAncestors() == null ? "" : parentDept.getAncestors(); - setAncestors(ancestors + "," + getParentId()); - } - - - /** - * DDD 有些阻抗 如果为了追求性能的话 还是得通过 数据库的方式来判断 - */ - public void checkStatusAllowChange() { - if (StatusEnum.DISABLE.getValue().equals(getStatus()) && - deptService.hasChildrenDept(getDeptId(), true)) { - throw new ApiException(ErrorCode.Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE); - } - - } - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModelFactory.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModelFactory.java deleted file mode 100644 index 8107b70..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/model/DeptModelFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.agileboot.domain.system.dept.model; - -import com.agileboot.common.exception.ApiException; -import com.agileboot.common.exception.error.ErrorCode; -import com.agileboot.domain.system.dept.command.AddDeptCommand; -import com.agileboot.domain.system.dept.db.SysDeptEntity; -import com.agileboot.domain.system.dept.db.SysDeptService; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -/** - * 部门模型工厂 - * @author valarchie - */ -@Component -@RequiredArgsConstructor -public class DeptModelFactory { - - private final SysDeptService deptService; - - public DeptModel loadById(Long deptId) { - SysDeptEntity byId = deptService.getById(deptId); - if (byId == null) { - throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, deptId, "部门"); - } - return new DeptModel(byId, deptService); - } - - public DeptModel create() { - return new DeptModel(deptService); - } - - public DeptModel loadFromAddCommand(AddDeptCommand addCommand, DeptModel model) { - model.setParentId(addCommand.getParentId()); - model.setDeptName(addCommand.getDeptName()); - model.setOrderNum(addCommand.getOrderNum()); - model.setLeaderName(addCommand.getLeaderName()); - model.setPhone(addCommand.getPhone()); - model.setEmail(addCommand.getEmail()); - return model; - } - - - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/query/DeptQuery.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/query/DeptQuery.java deleted file mode 100644 index eff5a9f..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/dept/query/DeptQuery.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.agileboot.domain.system.dept.query; - -import com.agileboot.common.core.page.AbstractQuery; -import com.agileboot.domain.system.dept.db.SysDeptEntity; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -/** - * @author valarchie - */ -@EqualsAndHashCode(callSuper = true) -@Data -@NoArgsConstructor -public class DeptQuery extends AbstractQuery { - - private Long deptId; - - private Long parentId; - - - @Override - public QueryWrapper addQueryCondition() { - // TODO parentId 这个似乎没使用 - return new QueryWrapper() -// .eq(status != null, "status", status) - .eq(parentId != null, "parent_id", parentId); -// .like(StrUtil.isNotEmpty(deptName), "dept_name", deptName); -// .and(deptId != null && isExcludeCurrentDept, o -> -// o.ne("dept_id", deptId) -// .or() -// .apply("FIND_IN_SET (dept_id , ancestors)") -// ); - } -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/db/SysOperationLogEntity.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/db/SysOperationLogEntity.java index a099ed5..dfdf82b 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/db/SysOperationLogEntity.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/db/SysOperationLogEntity.java @@ -73,14 +73,6 @@ public class SysOperationLogEntity extends Model { @TableField("operator_location") private String operatorLocation; - @ApiModelProperty("部门ID") - @TableField("dept_id") - private Long deptId; - - @ApiModelProperty("部门名称") - @TableField("dept_name") - private String deptName; - @ApiModelProperty("请求参数") @TableField("operation_param") private String operationParam; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/dto/OperationLogDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/dto/OperationLogDTO.java index 1af9e62..f1ce2c4 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/dto/OperationLogDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/log/dto/OperationLogDTO.java @@ -69,12 +69,6 @@ public class OperationLogDTO { @ExcelColumn(name = "ip地点") private String operatorLocation; - @ExcelColumn(name = "部门ID") - private Long deptId; - - @ExcelColumn(name = "部门") - private String deptName; - @ExcelColumn(name = "操作参数") private String operationParam; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/menu/MenuApplicationService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/menu/MenuApplicationService.java index 2699872..4caa925 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/menu/MenuApplicationService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/menu/MenuApplicationService.java @@ -105,7 +105,7 @@ public class MenuApplicationService { //默认为id可以不设置 config.setIdKey("menuId"); return TreeUtil.build(menus, 0L, config, (menu, tree) -> { - // 也可以使用 tree.setId(dept.getId());等一些默认值 + // 也可以使用 tree.setId(menu.getId());等一些默认值 tree.setId(menu.getMenuId()); tree.setParentId(menu.getParentId()); tree.putExtra("label", menu.getMenuName()); @@ -132,7 +132,7 @@ public class MenuApplicationService { config.setIdKey("menuId"); return TreeUtil.build(noButtonMenus, 0L, config, (menu, tree) -> { - // 也可以使用 tree.setId(dept.getId());等一些默认值 + // 也可以使用 tree.setId(menu.getId());等一些默认值 tree.setId(menu.getMenuId()); tree.setParentId(menu.getParentId()); // TODO 可以取meta中的rank来排序 diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/monitor/dto/OnlineUserDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/monitor/dto/OnlineUserDTO.java index 5f6d03d..c224af9 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/monitor/dto/OnlineUserDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/monitor/dto/OnlineUserDTO.java @@ -1,8 +1,6 @@ package com.agileboot.domain.system.monitor.dto; -import com.agileboot.domain.common.cache.CacheCenter; import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.domain.system.dept.db.SysDeptEntity; import lombok.Data; /** @@ -18,11 +16,6 @@ public class OnlineUserDTO { */ private String tokenId; - /** - * 部门名称 - */ - private String deptName; - /** * 用户名称 */ @@ -66,12 +59,6 @@ public class OnlineUserDTO { this.browser = user.getLoginInfo().getBrowser(); this.operationSystem = user.getLoginInfo().getOperationSystem(); this.loginTime = user.getLoginInfo().getLoginTime(); - - SysDeptEntity deptEntity = CacheCenter.deptCache.get(user.getDeptId() + ""); - - if (deptEntity != null) { - this.deptName = deptEntity.getDeptName(); - } } } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/PostApplicationService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/PostApplicationService.java deleted file mode 100644 index 1faf44f..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/PostApplicationService.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.agileboot.domain.system.post; - -import cn.hutool.core.util.StrUtil; -import com.agileboot.common.core.page.PageDTO; -import com.agileboot.domain.common.command.BulkOperationCommand; -import com.agileboot.domain.system.post.command.AddPostCommand; -import com.agileboot.domain.system.post.command.UpdatePostCommand; -import com.agileboot.domain.system.post.db.SysPostEntity; -import com.agileboot.domain.system.post.db.SysPostService; -import com.agileboot.domain.system.post.dto.PostDTO; -import com.agileboot.domain.system.post.model.PostModel; -import com.agileboot.domain.system.post.model.PostModelFactory; -import com.agileboot.domain.system.post.query.PostQuery; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import java.util.List; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -/** - * @author valarchie - */ -@Service -@RequiredArgsConstructor -public class PostApplicationService { - - private final PostModelFactory postModelFactory; - - private final SysPostService postService; - - public PageDTO getPostList(PostQuery query) { - Page page = postService.page(query.toPage(), query.toQueryWrapper()); - List records = page.getRecords().stream().map(PostDTO::new).collect(Collectors.toList()); - return new PageDTO<>(records, page.getTotal()); - } - - /** - * 查询满足条件的所有岗位,不分页 - * @param query 查询条件 - * @return 满足查询条件的岗位列表 - * @author Kevin Zhang - * @date 2023-10-02 - */ - public List getPostListAll(PostQuery query) { - List all = postService.list(query.toQueryWrapper()); - List records = all.stream().map(PostDTO::new).collect(Collectors.toList()); - return records; - } - - public PostDTO getPostInfo(Long postId) { - SysPostEntity byId = postService.getById(postId); - return new PostDTO(byId); - } - - public void addPost(AddPostCommand addCommand) { - PostModel postModel = postModelFactory.create(); - postModel.loadFromAddCommand(addCommand); - - postModel.checkPostNameUnique(); - postModel.checkPostCodeUnique(); - - postModel.insert(); - } - - public void updatePost(UpdatePostCommand updateCommand) { - PostModel postModel = postModelFactory.loadById(updateCommand.getPostId()); - postModel.loadFromUpdateCommand(updateCommand); - - postModel.checkPostNameUnique(); - postModel.checkPostCodeUnique(); - - postModel.updateById(); - } - - - public void deletePost(BulkOperationCommand deleteCommand) { - for (Long id : deleteCommand.getIds()) { - PostModel postModel = postModelFactory.loadById(id); - postModel.checkCanBeDelete(); - } - - postService.removeBatchByIds(deleteCommand.getIds()); - } - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/AddPostCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/AddPostCommand.java deleted file mode 100644 index da698ad..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/AddPostCommand.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.agileboot.domain.system.post.command; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; -import javax.validation.constraints.Size; -import lombok.Data; - -/** - * @author valarchie - */ -@Data -public class AddPostCommand { - - @NotBlank(message = "岗位编码不能为空") - @Size(max = 64, message = "岗位编码长度不能超过64个字符") - protected String postCode; - - /** - * 岗位名称 - */ - @NotBlank(message = "岗位名称不能为空") - @Size(max = 64, message = "岗位名称长度不能超过64个字符") - protected String postName; - - /** - * 岗位排序 - */ - @NotNull(message = "显示顺序不能为空") - protected Integer postSort; - - protected String remark; - - @PositiveOrZero - protected String status; - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/UpdatePostCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/UpdatePostCommand.java deleted file mode 100644 index f662e72..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/command/UpdatePostCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.agileboot.domain.system.post.command; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Positive; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @author valarchie - */ -@EqualsAndHashCode(callSuper = true) -@Data -public class UpdatePostCommand extends AddPostCommand { - - @NotNull(message = "岗位ID不能为空") - @Positive - private Long postId; - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostEntity.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostEntity.java deleted file mode 100644 index 4d62c8b..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostEntity.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.agileboot.domain.system.post.db; - -import com.agileboot.common.core.base.BaseEntity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.io.Serializable; -import lombok.Getter; -import lombok.Setter; - -/** - *

- * 岗位信息表 - *

- * - * @author valarchie - * @since 2022-10-02 - */ -@Getter -@Setter -@TableName("sys_post") -@ApiModel(value = "SysPostEntity对象", description = "岗位信息表") -public class SysPostEntity extends BaseEntity { - - private static final long serialVersionUID = 1L; - - @ApiModelProperty("岗位ID") - @TableId(value = "post_id", type = IdType.AUTO) - private Long postId; - - @ApiModelProperty("岗位编码") - @TableField("post_code") - private String postCode; - - @ApiModelProperty("岗位名称") - @TableField("post_name") - private String postName; - - @ApiModelProperty("显示顺序") - @TableField("post_sort") - private Integer postSort; - - @ApiModelProperty("状态(1正常 0停用)") - @TableField("`status`") - private Integer status; - - @ApiModelProperty("备注") - @TableField("remark") - private String remark; - - - @Override - public Serializable pkVal() { - return this.postId; - } - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostMapper.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostMapper.java deleted file mode 100644 index a6fd482..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.agileboot.domain.system.post.db; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - *

- * 岗位信息表 Mapper 接口 - *

- * - * @author valarchie - * @since 2022-06-16 - */ -public interface SysPostMapper extends BaseMapper { - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostService.java deleted file mode 100644 index 264fb8f..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostService.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.agileboot.domain.system.post.db; - -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 岗位信息表 服务类 - *

- * - * @author valarchie - * @since 2022-06-16 - */ -public interface SysPostService extends IService { - - /** - * 校验岗位名称 - * @param postId 职位Id - * @param postName 职位名称 - * @return 结果 - */ - boolean isPostNameDuplicated(Long postId, String postName); - - /** - * 校验岗位编码 - * @param postId 职位id - * @param postCode 职位代码 - * @return 结果 - */ - boolean isPostCodeDuplicated(Long postId, String postCode); - - - /** - * 检测职位是否分配给用户 - * - * @param postId 职位id - * @return 校验结果 - */ - boolean isAssignedToUsers(Long postId); - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostServiceImpl.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostServiceImpl.java deleted file mode 100644 index 1528693..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/db/SysPostServiceImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.agileboot.domain.system.post.db; - -import com.agileboot.domain.system.user.db.SysUserEntity; -import com.agileboot.domain.system.user.db.SysUserMapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -/** - *

- * 岗位信息表 服务实现类 - *

- * - * @author valarchie - * @since 2022-06-16 - */ -@Service -@RequiredArgsConstructor -public class SysPostServiceImpl extends ServiceImpl implements SysPostService { - - private final SysUserMapper userMapper; - - /** - * 校验岗位名称是否唯一 - * - * @param postName 岗位名称 - * @return 结果 - */ - @Override - public boolean isPostNameDuplicated(Long postId, String postName) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.ne(postId != null, "post_id", postId) - .eq("post_name", postName); - return baseMapper.exists(queryWrapper); - } - - @Override - public boolean isPostCodeDuplicated(Long postId, String postCode) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.ne(postId != null, "post_id", postId) - .eq("post_code", postCode); - return baseMapper.exists(queryWrapper); - } - - - @Override - public boolean isAssignedToUsers(Long postId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("post_id", postId); - return userMapper.exists(queryWrapper); - } - - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/dto/PostDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/dto/PostDTO.java deleted file mode 100644 index da32e3e..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/dto/PostDTO.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.agileboot.domain.system.post.dto; - -import cn.hutool.core.bean.BeanUtil; -import com.agileboot.common.annotation.ExcelColumn; -import com.agileboot.common.enums.common.StatusEnum; -import com.agileboot.common.enums.BasicEnumUtil; -import com.agileboot.domain.system.post.db.SysPostEntity; -import java.util.Date; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * @author valarchie - */ -@AllArgsConstructor -@NoArgsConstructor -@Data -public class PostDTO { - - public PostDTO(SysPostEntity entity) { - if (entity != null) { - BeanUtil.copyProperties(entity, this); - statusStr = BasicEnumUtil.getDescriptionByValue(StatusEnum.class, entity.getStatus()); - } - } - - @ExcelColumn(name = "岗位ID") - private Long postId; - - - @ExcelColumn(name = "岗位编码") - private String postCode; - - @ExcelColumn(name = "岗位名称") - private String postName; - - - @ExcelColumn(name = "岗位排序") - private Integer postSort; - - @ExcelColumn(name = "备注") - private String remark; - - private Integer status; - - @ExcelColumn(name = "状态") - private String statusStr; - - private Date createTime; - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModel.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModel.java deleted file mode 100644 index a69b4fd..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModel.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.agileboot.domain.system.post.model; - -import cn.hutool.core.bean.BeanUtil; -import com.agileboot.common.exception.ApiException; -import com.agileboot.common.exception.error.ErrorCode; -import com.agileboot.domain.system.post.command.AddPostCommand; -import com.agileboot.domain.system.post.command.UpdatePostCommand; -import com.agileboot.domain.system.post.db.SysPostEntity; -import com.agileboot.domain.system.post.db.SysPostService; -import lombok.NoArgsConstructor; - -/** - * @author valarchie - */ -@NoArgsConstructor -public class PostModel extends SysPostEntity { - - private SysPostService postService; - - public PostModel(SysPostService postService) { - this.postService = postService; - } - - public PostModel(SysPostEntity entity, SysPostService postService) { - if (entity != null) { - BeanUtil.copyProperties(entity, this); - } - this.postService = postService; - } - - public void loadFromAddCommand(AddPostCommand addCommand) { - if (addCommand != null) { - BeanUtil.copyProperties(addCommand, this, "postId"); - } - } - - - public void loadFromUpdateCommand(UpdatePostCommand command) { - if (command != null) { - loadFromAddCommand(command); - } - } - - - public void checkCanBeDelete() { - if (postService.isAssignedToUsers(this.getPostId())) { - throw new ApiException(ErrorCode.Business.POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED); - } - } - - public void checkPostNameUnique() { - if (postService.isPostNameDuplicated(getPostId(), getPostName())) { - throw new ApiException(ErrorCode.Business.POST_NAME_IS_NOT_UNIQUE, getPostName()); - } - } - - public void checkPostCodeUnique() { - if (postService.isPostCodeDuplicated(getPostId(), getPostCode())) { - throw new ApiException(ErrorCode.Business.POST_CODE_IS_NOT_UNIQUE, getPostCode()); - } - } - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModelFactory.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModelFactory.java deleted file mode 100644 index 4816d6c..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/model/PostModelFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.agileboot.domain.system.post.model; - -import com.agileboot.common.exception.ApiException; -import com.agileboot.common.exception.error.ErrorCode.Business; -import com.agileboot.domain.system.post.db.SysPostEntity; -import com.agileboot.domain.system.post.db.SysPostService; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -/** - * @author valarchie - */ -@Component -@RequiredArgsConstructor -public class PostModelFactory { - - private final SysPostService postService; - - public PostModel loadById(Long postId) { - SysPostEntity byId = postService.getById(postId); - if (byId == null) { - throw new ApiException(Business.COMMON_OBJECT_NOT_FOUND, postId, "职位"); - } - return new PostModel(byId, postService); - } - - public PostModel create() { - return new PostModel(postService); - } - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/query/PostQuery.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/query/PostQuery.java deleted file mode 100644 index 1071c48..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/post/query/PostQuery.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.agileboot.domain.system.post.query; - -import cn.hutool.core.util.StrUtil; -import com.agileboot.common.core.page.AbstractPageQuery; -import com.agileboot.domain.system.post.db.SysPostEntity; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @author valarchie - */ -@EqualsAndHashCode(callSuper = true) -@Data -public class PostQuery extends AbstractPageQuery { - - private String postCode; - private String postName; - private Integer status; - - @Override - public QueryWrapper addQueryCondition() { - QueryWrapper queryWrapper = new QueryWrapper() - .eq(status != null, "status", status) - .eq(StrUtil.isNotEmpty(postCode), "post_code", postCode) - .like(StrUtil.isNotEmpty(postName), "post_name", postName); - // 当前端没有选择排序字段时,则使用post_sort字段升序排序(在父类AbstractQuery中默认为升序) - if (StrUtil.isEmpty(this.getOrderColumn())) { - this.setOrderColumn("post_sort"); - } - this.setTimeRangeColumn("create_time"); - - return queryWrapper; - } -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/RoleApplicationService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/RoleApplicationService.java index 46db651..b081ca6 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/RoleApplicationService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/RoleApplicationService.java @@ -1,11 +1,9 @@ package com.agileboot.domain.system.role; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; import com.agileboot.common.core.page.PageDTO; import com.agileboot.domain.common.cache.CacheCenter; import com.agileboot.domain.system.role.command.AddRoleCommand; -import com.agileboot.domain.system.role.command.UpdateDataScopeCommand; import com.agileboot.domain.system.role.command.UpdateRoleCommand; import com.agileboot.domain.system.role.command.UpdateStatusCommand; import com.agileboot.domain.system.role.dto.RoleDTO; @@ -56,9 +54,6 @@ public class RoleApplicationService { public RoleDTO getRoleInfo(Long roleId) { SysRoleEntity byId = roleService.getById(roleId); RoleDTO roleDTO = new RoleDTO(byId); - List selectedDeptList = StrUtil.split(byId.getDeptIdSet(), ",") - .stream().filter(StrUtil::isNotEmpty).map(Long::new).collect(Collectors.toList()); - roleDTO.setSelectedDeptList(selectedDeptList); roleDTO.setSelectedMenuList(menuService.getMenuIdsByRoleId(roleId)); return roleDTO; } @@ -105,17 +100,6 @@ public class RoleApplicationService { roleModel.updateById(); } - public void updateDataScope(UpdateDataScopeCommand command) { - RoleModel roleModel = roleModelFactory.loadById(command.getRoleId()); - - roleModel.setDeptIds(command.getDeptIds()); - roleModel.setDataScope(command.getDataScope()); - roleModel.generateDeptIdSet(); - - roleModel.updateById(); - } - - public PageDTO getAllocatedUserList(AllocatedRoleQuery query) { Page page = userService.getUserListByRole(query); List dtoList = page.getRecords().stream().map(UserDTO::new).collect(Collectors.toList()); diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/AddRoleCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/AddRoleCommand.java index badd2b6..8e12b2b 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/AddRoleCommand.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/AddRoleCommand.java @@ -40,7 +40,6 @@ public class AddRoleCommand { private String remark; - @ExcelColumn(name = "数据范围") private String dataScope; @PositiveOrZero diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/UpdateDataScopeCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/UpdateDataScopeCommand.java deleted file mode 100644 index dcd7c30..0000000 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/command/UpdateDataScopeCommand.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.agileboot.domain.system.role.command; - -import java.util.List; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Positive; -import lombok.Data; - -/** - * @author valarchie - */ -@Data -public class UpdateDataScopeCommand { - - @NotNull - @Positive - private Long roleId; - - @NotNull - @NotEmpty - private List deptIds; - - private Integer dataScope; - - -} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleEntity.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleEntity.java index bf035df..5e67e15 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleEntity.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleEntity.java @@ -43,14 +43,10 @@ public class SysRoleEntity extends BaseEntity { @TableField("role_sort") private Integer roleSort; - @ApiModelProperty("数据范围(1:全部数据权限 2:自定数据权限 3: 本部门数据权限 4: 本部门及以下数据权限 5: 本人权限)") + @ApiModelProperty("数据范围(1:全部数据权限 5: 本人权限)") @TableField("data_scope") private Integer dataScope; - @ApiModelProperty("角色所拥有的部门数据权限") - @TableField("dept_id_set") - private String deptIdSet; - @ApiModelProperty("角色状态(1正常 0停用)") @TableField("`status`") private Integer status; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleService.java index 81b71fe..3175e13 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleService.java @@ -32,6 +32,13 @@ public interface SysRoleService extends IService { */ boolean isRoleKeyDuplicated(Long roleId, String roleKey); + /** + * 根据角色标识获取可用角色 + * @param roleKey 角色标识 + * @return 角色信息 + */ + SysRoleEntity getEnabledRoleByKey(String roleKey); + /** * 检测角色是否分配给用户 diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleServiceImpl.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleServiceImpl.java index b8a76c6..5f87828 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleServiceImpl.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/db/SysRoleServiceImpl.java @@ -3,6 +3,7 @@ package com.agileboot.domain.system.role.db; import com.agileboot.domain.system.menu.db.SysMenuEntity; import com.agileboot.domain.system.user.db.SysUserEntity; import com.agileboot.domain.system.user.db.SysUserMapper; +import com.agileboot.common.enums.common.StatusEnum; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import java.util.List; @@ -39,6 +40,14 @@ public class SysRoleServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("role_key", roleKey) + .eq("status", StatusEnum.ENABLE.getValue()); + return getOne(queryWrapper); + } + @Override public boolean isAssignedToUsers(Long roleId) { QueryWrapper queryWrapper = new QueryWrapper<>(); diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/dto/RoleDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/dto/RoleDTO.java index 881fc45..2c10626 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/dto/RoleDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/dto/RoleDTO.java @@ -45,6 +45,4 @@ public class RoleDTO { private Integer dataScope; private List selectedMenuList; - - private List selectedDeptList; } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModel.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModel.java index 7d9d718..5ed182a 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModel.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModel.java @@ -1,10 +1,10 @@ package com.agileboot.domain.system.role.model; import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.util.StrUtil; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.common.exception.error.ErrorCode.Business; +import com.agileboot.infrastructure.user.web.DataScopeEnum; import com.agileboot.domain.system.role.command.AddRoleCommand; import com.agileboot.domain.system.role.command.UpdateRoleCommand; import com.agileboot.common.enums.common.StatusEnum; @@ -14,7 +14,6 @@ import com.agileboot.domain.system.role.db.SysRoleMenuService; import com.agileboot.domain.system.role.db.SysRoleService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import lombok.Data; import lombok.EqualsAndHashCode; @@ -30,8 +29,6 @@ public class RoleModel extends SysRoleEntity { private List menuIds; - private List deptIds; - private SysRoleService roleService; private SysRoleMenuService roleMenuService; @@ -51,6 +48,7 @@ public class RoleModel extends SysRoleEntity { public void loadAddCommand(AddRoleCommand command) { if (command != null) { BeanUtil.copyProperties(command, this, "roleId"); + fillDefaultDataScope(); } } @@ -84,22 +82,12 @@ public class RoleModel extends SysRoleEntity { } } - public void generateDeptIdSet() { - if (deptIds == null) { - setDeptIdSet(""); - return; + private void fillDefaultDataScope() { + if (getDataScope() == null) { + setDataScope(DataScopeEnum.ONLY_SELF.getValue()); } - - if (deptIds.size() > new HashSet<>(deptIds).size()) { - throw new ApiException(ErrorCode.Business.ROLE_DATA_SCOPE_DUPLICATED_DEPT); - } - - String deptIdSet = StrUtil.join(",", deptIds); - setDeptIdSet(deptIdSet); } - - @Override public boolean insert() { super.insert(); diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModelFactory.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModelFactory.java index 6d05f37..c812423 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModelFactory.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/role/model/RoleModelFactory.java @@ -1,7 +1,5 @@ package com.agileboot.domain.system.role.model; -import cn.hutool.core.convert.Convert; -import cn.hutool.core.util.StrUtil; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.domain.system.role.db.SysRoleEntity; @@ -36,13 +34,9 @@ public class RoleModelFactory { queryWrapper.eq(SysRoleMenuEntity::getRoleId, roleId); List menuIds = roleMenuService.list(queryWrapper).stream().map(SysRoleMenuEntity::getMenuId) .collect(Collectors.toList()); - List deptIds = StrUtil.split(byId.getDeptIdSet(), ",").stream() - .map(Convert::toLong).collect( Collectors.toList()); - RoleModel roleModel = new RoleModel(byId, roleService, roleMenuService); roleModel.setMenuIds(menuIds); - roleModel.setDeptIds(deptIds); return roleModel; } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/UserApplicationService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/UserApplicationService.java index 6d30086..aed4e7c 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/UserApplicationService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/UserApplicationService.java @@ -1,14 +1,21 @@ package com.agileboot.domain.system.user; +import cn.hutool.core.util.StrUtil; import cn.hutool.core.convert.Convert; import com.agileboot.common.core.page.PageDTO; +import com.agileboot.common.enums.common.ConfigKeyEnum; +import com.agileboot.common.enums.common.GenderEnum; +import com.agileboot.common.enums.common.UserStatusEnum; +import com.agileboot.common.exception.ApiException; +import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.domain.common.cache.CacheCenter; +import com.agileboot.domain.common.cache.GuavaCacheService; import com.agileboot.domain.common.command.BulkOperationCommand; import com.agileboot.domain.common.dto.CurrentLoginUserDTO; -import com.agileboot.domain.system.post.dto.PostDTO; import com.agileboot.domain.system.role.dto.RoleDTO; import com.agileboot.domain.system.user.command.AddUserCommand; import com.agileboot.domain.system.user.command.ChangeStatusCommand; +import com.agileboot.domain.system.user.command.RegisterUserCommand; import com.agileboot.domain.system.user.command.ResetPasswordCommand; import com.agileboot.domain.system.user.command.UpdateProfileCommand; import com.agileboot.domain.system.user.command.UpdateUserAvatarCommand; @@ -22,12 +29,12 @@ import com.agileboot.domain.system.user.model.UserModel; import com.agileboot.domain.system.user.model.UserModelFactory; import com.agileboot.domain.system.user.query.SearchUserQuery; import com.agileboot.infrastructure.user.web.SystemLoginUser; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; import com.agileboot.domain.system.user.db.SysUserEntity; -import com.agileboot.domain.system.post.db.SysPostService; import com.agileboot.domain.system.role.db.SysRoleService; import com.agileboot.domain.system.user.db.SysUserService; +import com.agileboot.infrastructure.user.AuthenticationUtils; +import com.agileboot.infrastructure.user.web.DataScopeEnum; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import java.util.List; @@ -42,16 +49,19 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class UserApplicationService { + private static final String DEFAULT_REGISTER_ROLE_KEY = "common"; + private final SysUserService userService; private final SysRoleService roleService; - private final SysPostService postService; - private final UserModelFactory userModelFactory; + private final GuavaCacheService guavaCacheService; + public PageDTO getUserList(SearchUserQuery query) { + applyOnlySelfScope(query); Page userPage = userService.getUserList(query); List userDTOList = userPage.getRecords().stream().map(UserDTO::new).collect(Collectors.toList()); return new PageDTO<>(userDTOList, userPage.getTotal()); @@ -60,10 +70,9 @@ public class UserApplicationService { public UserProfileDTO getUserProfile(Long userId) { SysUserEntity userEntity = userService.getById(userId); - SysPostEntity postEntity = userService.getPostOfUser(userId); SysRoleEntity roleEntity = userService.getRoleOfUser(userId); - return new UserProfileDTO(userEntity, postEntity, roleEntity); + return new UserProfileDTO(userEntity, roleEntity); } @@ -102,14 +111,11 @@ public class UserApplicationService { LambdaQueryWrapper roleQuery = new LambdaQueryWrapper() .orderByAsc(SysRoleEntity::getRoleSort); List roleDtoList = roleService.list(roleQuery).stream().map(RoleDTO::new).collect(Collectors.toList()); - List postDtoList = postService.list().stream().map(PostDTO::new).collect(Collectors.toList()); detailDTO.setRoleOptions(roleDtoList); - detailDTO.setPostOptions(postDtoList); if (userEntity != null) { detailDTO.setUser(new UserDTO(userEntity)); detailDTO.setRoleId(userEntity.getRoleId()); - detailDTO.setPostId(userEntity.getPostId()); } return detailDTO; } @@ -127,6 +133,20 @@ public class UserApplicationService { model.insert(); } + public void registerUser(RegisterUserCommand command) { + checkRegisterIsOpen(); + checkRegisterPassword(command); + + UserModel model = userModelFactory.create(); + loadRegisterCommand(model, command); + + model.checkUsernameIsUnique(); + model.checkPhoneNumberIsUnique(); + model.checkEmailIsUnique(); + model.resetPassword(command.getPassword()); + model.insert(); + } + public void updateUser(UpdateUserCommand command) { UserModel model = userModelFactory.loadById(command.getUserId()); model.loadUpdateUserCommand(command); @@ -182,5 +202,58 @@ public class UserApplicationService { CacheCenter.userCache.delete(userModel.getUserId()); } + private void checkRegisterIsOpen() { + Boolean isRegisterUserOn = Convert.toBool(guavaCacheService.configCache.get(ConfigKeyEnum.REGISTER.getValue())); + if (!Boolean.TRUE.equals(isRegisterUserOn)) { + throw new ApiException(ErrorCode.Business.USER_REGISTER_IS_CLOSED); + } + } + + private void checkRegisterPassword(RegisterUserCommand command) { + if (!StrUtil.equals(command.getPassword(), command.getConfirmPassword())) { + throw new ApiException(ErrorCode.Business.USER_REGISTER_PASSWORD_NOT_MATCH); + } + } + + private void applyOnlySelfScope(SearchUserQuery query) { + SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser(); + if (loginUser == null || loginUser.getRoleInfo() == null) { + return; + } + + if (DataScopeEnum.ONLY_SELF.equals(loginUser.getRoleInfo().getDataScope())) { + query.setUserId(loginUser.getUserId()); + } + } + + private void loadRegisterCommand(UserModel model, RegisterUserCommand command) { + SysRoleEntity role = getDefaultRegisterRole(); + model.setUsername(command.getUsername()); + model.setNickname(getRegisterNickname(command)); + model.setEmail(command.getEmail()); + model.setPhoneNumber(command.getPhoneNumber()); + model.setRoleId(role.getRoleId()); + model.setStatus(UserStatusEnum.NORMAL.getValue()); + model.setUserType(0); + model.setSex(GenderEnum.UNKNOWN.getValue()); + model.setIsAdmin(false); + model.setRemark("自助注册用户"); + } + + private SysRoleEntity getDefaultRegisterRole() { + SysRoleEntity role = roleService.getEnabledRoleByKey(DEFAULT_REGISTER_ROLE_KEY); + if (role == null) { + throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, DEFAULT_REGISTER_ROLE_KEY, "普通角色"); + } + return role; + } + + private String getRegisterNickname(RegisterUserCommand command) { + if (StrUtil.isNotBlank(command.getNickname())) { + return command.getNickname(); + } + return command.getUsername(); + } + } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/AddUserCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/AddUserCommand.java index 906ada3..7955768 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/AddUserCommand.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/AddUserCommand.java @@ -9,9 +9,6 @@ import lombok.Data; @Data public class AddUserCommand { - @ExcelColumn(name = "部门ID") - private Long deptId; - @ExcelColumn(name = "用户名") private String username; @@ -39,9 +36,6 @@ public class AddUserCommand { @ExcelColumn(name = "角色ID") private Long roleId; - @ExcelColumn(name = "职位ID") - private Long postId; - @ExcelColumn(name = "备注") private String remark; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/RegisterUserCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/RegisterUserCommand.java new file mode 100644 index 0000000..23d0c6b --- /dev/null +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/RegisterUserCommand.java @@ -0,0 +1,40 @@ +package com.agileboot.domain.system.user.command; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import lombok.Data; + +/** + * 自助注册用户请求。 + * + * @author codex + */ +@Data +public class RegisterUserCommand { + + @NotBlank(message = "账号不能为空") + @Size(max = 64, message = "账号长度不能超过64个字符") + private String username; + + @Size(max = 32, message = "昵称长度不能超过32个字符") + private String nickname; + + @Email(message = "邮箱格式不正确") + @Size(max = 128, message = "邮箱长度不能超过128个字符") + private String email; + + @Size(max = 18, message = "手机号长度不能超过18个字符") + private String phoneNumber; + + @NotBlank(message = "密码不能为空") + private String password; + + @NotBlank(message = "确认密码不能为空") + private String confirmPassword; + + private String captchaCode; + + private String captchaCodeKey; + +} diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/UpdateUserPasswordCommand.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/UpdateUserPasswordCommand.java index 24f1634..1ba0ec8 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/UpdateUserPasswordCommand.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/UpdateUserPasswordCommand.java @@ -1,5 +1,6 @@ package com.agileboot.domain.system.user.command; +import javax.validation.constraints.NotBlank; import lombok.Data; /** @@ -9,7 +10,9 @@ import lombok.Data; public class UpdateUserPasswordCommand { private Long userId; + @NotBlank(message = "密码不能为空") private String newPassword; - private String oldPassword; + @NotBlank(message = "确认密码不能为空") + private String confirmPassword; } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SearchUserDO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SearchUserDO.java index d7b2af7..bde86a7 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SearchUserDO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SearchUserDO.java @@ -7,11 +7,8 @@ import lombok.EqualsAndHashCode; * 如果Entity的字段和复杂查询不匹配时 自定义类来接收 * @author valarchie */ -@EqualsAndHashCode(callSuper = true) @Data +@EqualsAndHashCode(callSuper = true) public class SearchUserDO extends SysUserEntity { - private String deptName; - private String deptLeader; - } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserEntity.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserEntity.java index e0ab5e1..c5fe68e 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserEntity.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserEntity.java @@ -32,18 +32,10 @@ public class SysUserEntity extends BaseEntity { @TableId(value = "user_id", type = IdType.AUTO) private Long userId; - @ApiModelProperty("职位id") - @TableField("post_id") - private Long postId; - @ApiModelProperty("角色id") @TableField("role_id") private Long roleId; - @ApiModelProperty("部门ID") - @TableField("dept_id") - private Long deptId; - @ApiModelProperty("用户账号") @TableField("username") private String username; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserMapper.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserMapper.java index 8c84e15..2dac2c4 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserMapper.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserMapper.java @@ -1,6 +1,5 @@ package com.agileboot.domain.system.user.db; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; @@ -35,19 +34,6 @@ public interface SysUserMapper extends BaseMapper { + " AND u.user_id = #{userId}") List getRolesByUserId(Long userId); - /** - * 查询用户所属岗位组 - * - * @param userId 用户名 - * @return 结果 - */ - @Select("SELECT p.* " - + "FROM sys_post p " - + " LEFT JOIN sys_user u ON p.post_id = u.post_id " - + "WHERE u.user_id = #{userId} " - + " AND p.deleted = 0") - List getPostsByUserId(Long userId); - /** * 根据用户ID查询权限 * @@ -71,10 +57,9 @@ public interface SysUserMapper extends BaseMapper { * @param queryWrapper 条件选择器 * @return 分页处理后的用户列表 */ - @Select("SELECT DISTINCT u.user_id, u.dept_id, u.username, u.nick_name, u.email " + @Select("SELECT DISTINCT u.user_id, u.username, u.nick_name, u.email " + " , u.phone_number, u.status, u.create_time " + "FROM sys_user u " - + " LEFT JOIN sys_dept d ON u.dept_id = d.dept_id " + " LEFT JOIN sys_role r ON r.role_id = u.role_id" + " ${ew.customSqlSegment}") Page getUserListByRole(Page page, @@ -86,9 +71,8 @@ public interface SysUserMapper extends BaseMapper { * @param queryWrapper 查询对象 * @return 用户信息集合信息 */ - @Select("SELECT u.*, d.dept_name, d.leader_name as dept_leader " + @Select("SELECT u.* " + "FROM sys_user u " - + " LEFT JOIN sys_dept d ON u.dept_id = d.dept_id " + "${ew.customSqlSegment}") Page getUserList(Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserService.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserService.java index 631d4e1..9bad777 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserService.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserService.java @@ -1,7 +1,6 @@ package com.agileboot.domain.system.user.db; import com.agileboot.common.core.page.AbstractPageQuery; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; @@ -49,13 +48,6 @@ public interface SysUserService extends IService { */ SysRoleEntity getRoleOfUser(Long userId); - /** - * 获取用户的岗位 - * @param userId 用户id - * @return 用户岗位 - */ - SysPostEntity getPostOfUser(Long userId); - /** * 获取用户的权限列表 * @param userId 用户id diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserServiceImpl.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserServiceImpl.java index f83654e..f1bdfa7 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserServiceImpl.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserServiceImpl.java @@ -1,7 +1,6 @@ package com.agileboot.domain.system.user.db; import com.agileboot.common.core.page.AbstractPageQuery; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -55,13 +54,6 @@ public class SysUserServiceImpl extends ServiceImpl list = baseMapper.getPostsByUserId(userId); - return list.isEmpty() ? null : list.get(0); - } - - @Override public Set getMenuPermissionsForUser(Long userId) { return baseMapper.getMenuPermsByUserId(userId); diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDTO.java index 5bea65f..11e602c 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDTO.java @@ -4,11 +4,9 @@ import cn.hutool.core.bean.BeanUtil; import com.agileboot.common.annotation.ExcelColumn; import com.agileboot.common.annotation.ExcelSheet; import com.agileboot.domain.common.cache.CacheCenter; -import com.agileboot.domain.system.dept.db.SysDeptEntity; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; -import com.agileboot.domain.system.user.db.SysUserEntity; import com.agileboot.domain.system.user.db.SearchUserDO; +import com.agileboot.domain.system.user.db.SysUserEntity; import java.util.Date; import lombok.Data; @@ -23,11 +21,6 @@ public class UserDTO { if (entity != null) { BeanUtil.copyProperties(entity, this); - SysDeptEntity dept = CacheCenter.deptCache.get(entity.getDeptId() + ""); - if (dept != null) { - this.deptName = dept.getDeptName(); - } - SysUserEntity creator = CacheCenter.userCache.getObjectById(entity.getCreatorId()); if (creator != null) { this.creatorName = creator.getUsername(); @@ -38,11 +31,6 @@ public class UserDTO { this.roleName = roleEntity != null ? roleEntity.getRoleName() : ""; } - if (entity.getPostId() != null) { - SysPostEntity post = CacheCenter.postCache.getObjectById(entity.getRoleId()); - this.postName = post != null ? post.getPostName() : ""; - } - } } @@ -61,24 +49,12 @@ public class UserDTO { @ExcelColumn(name = "用户ID") private Long userId; - @ExcelColumn(name = "职位ID") - private Long postId; - - @ExcelColumn(name = "职位名称") - private String postName; - @ExcelColumn(name = "角色ID") private Long roleId; @ExcelColumn(name = "角色名称") private String roleName; - @ExcelColumn(name = "部门ID") - private Long deptId; - - @ExcelColumn(name = "部门名称") - private String deptName; - @ExcelColumn(name = "用户名") private String username; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDetailDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDetailDTO.java index 3c248e2..86ef5ba 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDetailDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDetailDTO.java @@ -1,6 +1,5 @@ package com.agileboot.domain.system.user.dto; -import com.agileboot.domain.system.post.dto.PostDTO; import com.agileboot.domain.system.role.dto.RoleDTO; import java.util.List; import java.util.Set; @@ -19,13 +18,6 @@ public class UserDetailDTO { */ private List roleOptions; - /** - * 返回所有posts - */ - private List postOptions; - - private Long postId; - private Long roleId; private Set permissions; diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserProfileDTO.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserProfileDTO.java index 0fa9e18..9ce05b3 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserProfileDTO.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserProfileDTO.java @@ -1,6 +1,5 @@ package com.agileboot.domain.system.user.dto; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; import com.agileboot.domain.system.user.db.SysUserEntity; import lombok.Data; @@ -11,15 +10,11 @@ import lombok.Data; @Data public class UserProfileDTO { - public UserProfileDTO(SysUserEntity userEntity, SysPostEntity postEntity, SysRoleEntity roleEntity) { + public UserProfileDTO(SysUserEntity userEntity, SysRoleEntity roleEntity) { if (userEntity != null) { this.user = new UserDTO(userEntity); } - if (postEntity != null) { - this.postName = postEntity.getPostName(); - } - if (roleEntity != null) { this.roleName = roleEntity.getRoleName(); } @@ -27,6 +22,5 @@ public class UserProfileDTO { private UserDTO user; private String roleName; - private String postName; } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModel.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModel.java index fbf261f..4b25740 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModel.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModel.java @@ -6,8 +6,6 @@ import com.agileboot.common.config.AgileBootConfig; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.common.exception.error.ErrorCode.Business; -import com.agileboot.domain.system.dept.model.DeptModelFactory; -import com.agileboot.domain.system.post.model.PostModelFactory; import com.agileboot.domain.system.role.model.RoleModelFactory; import com.agileboot.domain.system.user.command.AddUserCommand; import com.agileboot.domain.system.user.command.UpdateProfileCommand; @@ -32,26 +30,18 @@ public class UserModel extends SysUserEntity { private SysUserService userService; - private PostModelFactory postModelFactory; - - private DeptModelFactory deptModelFactory; - private RoleModelFactory roleModelFactory; - public UserModel(SysUserEntity entity, SysUserService userService, PostModelFactory postModelFactory, - DeptModelFactory deptModelFactory, RoleModelFactory roleModelFactory) { - this(userService, postModelFactory, deptModelFactory, roleModelFactory); + public UserModel(SysUserEntity entity, SysUserService userService, RoleModelFactory roleModelFactory) { + this(userService, roleModelFactory); if (entity != null) { BeanUtil.copyProperties(entity, this); } } - public UserModel(SysUserService userService, PostModelFactory postModelFactory, - DeptModelFactory deptModelFactory, RoleModelFactory roleModelFactory) { + public UserModel(SysUserService userService, RoleModelFactory roleModelFactory) { this.userService = userService; - this.postModelFactory = postModelFactory; - this.deptModelFactory = deptModelFactory; this.roleModelFactory = roleModelFactory; } @@ -92,19 +82,9 @@ public class UserModel extends SysUserEntity { } public void checkFieldRelatedEntityExist() { - - if (getPostId() != null) { - postModelFactory.loadById(getPostId()); - } - - if (getDeptId() != null) { - deptModelFactory.loadById(getDeptId()); - } - if (getRoleId() != null) { roleModelFactory.loadById(getRoleId()); } - } @@ -123,8 +103,13 @@ public class UserModel extends SysUserEntity { public void modifyPassword(UpdateUserPasswordCommand command) { - if (!AuthenticationUtils.matchesPassword(command.getOldPassword(), getPassword())) { - throw new ApiException(ErrorCode.Business.USER_PASSWORD_IS_NOT_CORRECT); + if (command == null || StrUtil.isBlank(command.getNewPassword()) + || StrUtil.isBlank(command.getConfirmPassword())) { + throw new ApiException(ErrorCode.Business.USER_PASSWORD_IS_EMPTY); + } + + if (!StrUtil.equals(command.getNewPassword(), command.getConfirmPassword())) { + throw new ApiException(ErrorCode.Business.USER_REGISTER_PASSWORD_NOT_MATCH); } if (AuthenticationUtils.matchesPassword(command.getNewPassword(), getPassword())) { diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModelFactory.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModelFactory.java index 166b0b5..d2f42a8 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModelFactory.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModelFactory.java @@ -2,8 +2,6 @@ package com.agileboot.domain.system.user.model; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode; -import com.agileboot.domain.system.dept.model.DeptModelFactory; -import com.agileboot.domain.system.post.model.PostModelFactory; import com.agileboot.domain.system.role.model.RoleModelFactory; import com.agileboot.domain.system.user.db.SysUserEntity; import com.agileboot.domain.system.user.db.SysUserService; @@ -20,10 +18,6 @@ public class UserModelFactory { private final SysUserService userService; - private final PostModelFactory postModelFactory; - - private final DeptModelFactory deptModelFactory; - private final RoleModelFactory roleModelFactory; public UserModel loadById(Long userId) { @@ -31,11 +25,11 @@ public class UserModelFactory { if (byId == null) { throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, userId, "用户"); } - return new UserModel(byId, userService, postModelFactory, deptModelFactory, roleModelFactory); + return new UserModel(byId, userService, roleModelFactory); } public UserModel create() { - return new UserModel(userService, postModelFactory, deptModelFactory, roleModelFactory); + return new UserModel(userService, roleModelFactory); } } diff --git a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/query/SearchUserQuery.java b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/query/SearchUserQuery.java index 1bbdc3d..da1db6b 100644 --- a/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/query/SearchUserQuery.java +++ b/backend/agileboot-domain/src/main/java/com/agileboot/domain/system/user/query/SearchUserQuery.java @@ -18,7 +18,6 @@ public class SearchUserQuery extends AbstractPageQuery { protected String username; protected Integer status; protected String phoneNumber; - protected Long deptId; @Override public QueryWrapper addQueryCondition() { @@ -28,12 +27,7 @@ public class SearchUserQuery extends AbstractPageQuery { .like(StrUtil.isNotEmpty(phoneNumber), "u.phone_number", phoneNumber) .eq(userId != null, "u.user_id", userId) .eq(status != null, "u.status", status) - .eq("u.deleted", 0) - .and(deptId != null, o -> - o.eq("u.dept_id", deptId) - .or() - .apply("u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(" + deptId - + ", ancestors))")); + .eq("u.deleted", 0); // 设置排序字段 this.timeRangeColumn = "u.create_time"; diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnumTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnumTest.java new file mode 100644 index 0000000..5aa64e2 --- /dev/null +++ b/backend/agileboot-domain/src/test/java/com/agileboot/domain/collaboration/record/enumtype/SettlementStatusEnumTest.java @@ -0,0 +1,38 @@ +package com.agileboot.domain.collaboration.record.enumtype; + +import java.util.Arrays; +import java.util.Collections; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class SettlementStatusEnumTest { + + @Test + void aggregateShouldIgnoreNoneStatus() { + String status = SettlementStatusEnum.aggregate(Arrays.asList("NONE", "SETTLED")); + + Assertions.assertEquals("SETTLED", status); + } + + @Test + void aggregateShouldReturnPartialWhenStatusesAreMixed() { + String status = SettlementStatusEnum.aggregate(Arrays.asList("SETTLED", "UNSETTLED")); + + Assertions.assertEquals("PARTIAL", status); + } + + @Test + void aggregateShouldReturnNoneWhenNoEffectiveStatusExists() { + String status = SettlementStatusEnum.aggregate(Collections.singletonList("NONE")); + + Assertions.assertEquals("NONE", status); + } + + @Test + void aggregateShouldReturnNoneWhenStatusListIsEmpty() { + String status = SettlementStatusEnum.aggregate(Collections.emptyList()); + + Assertions.assertEquals("NONE", status); + } + +} diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/dept/model/DeptModelTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/dept/model/DeptModelTest.java deleted file mode 100644 index bc782c6..0000000 --- a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/dept/model/DeptModelTest.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.agileboot.domain.system.dept.model; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.agileboot.common.exception.ApiException; -import com.agileboot.common.exception.error.ErrorCode.Business; -import com.agileboot.domain.system.dept.db.SysDeptEntity; -import com.agileboot.domain.system.dept.db.SysDeptService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; - -class DeptModelTest { - - private static final Long DEPT_ID = 1L; - private static final Long PARENT_ID = 2L; - - private final SysDeptService deptService = mock(SysDeptService.class); - - private final DeptModelFactory deptModelFactory = new DeptModelFactory(deptService); - - @Test - void testCheckDeptNameUnique() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setDeptName("dept 1"); - when( - deptService.isDeptNameDuplicated(ArgumentMatchers.any(), ArgumentMatchers.any(), - ArgumentMatchers.any())).thenReturn(true); - - ApiException exception = assertThrows(ApiException.class, deptModel::checkDeptNameUnique); - Assertions.assertEquals(Business.DEPT_NAME_IS_NOT_UNIQUE, exception.getErrorCode()); - } - - - @Test - void testCheckParentIdConflict() { - DeptModel deptModel = deptModelFactory.create(); - Long sameId = 1L; - deptModel.setDeptId(sameId); - deptModel.setParentId(sameId); - - ApiException exception = assertThrows(ApiException.class, deptModel::checkParentIdConflict); - - Assertions.assertEquals(Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF, exception.getErrorCode()); - } - - - @Test - void testCheckHasChildDept() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setDeptId(DEPT_ID); - when(deptService.hasChildrenDept((DEPT_ID), eq(null))).thenReturn(true); - - ApiException exception = assertThrows(ApiException.class, deptModel::checkHasChildDept); - - Assertions.assertEquals(Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE, exception.getErrorCode()); - } - - - @Test - void testCheckDeptAssignedToUsers() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setDeptId(DEPT_ID); - when(deptService.isDeptAssignedToUsers(DEPT_ID)).thenReturn(true); - - ApiException exception = assertThrows(ApiException.class, - deptModel::checkDeptAssignedToUsers); - - Assertions.assertEquals(Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE, exception.getErrorCode()); - } - - @Test - void testGenerateAncestorsWhenParentIdZero() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setParentId(0L); - - deptModel.generateAncestors(); - - Assertions.assertEquals(deptModel.getAncestors(), deptModel.getParentId().toString()); - } - - @Test - void testGenerateAncestorsWhenParentDeptNotExist() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setParentId(PARENT_ID); - when(deptService.getById(PARENT_ID)).thenReturn(null); - - ApiException exception = assertThrows(ApiException.class, deptModel::generateAncestors); - - Assertions.assertEquals(Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED, exception.getErrorCode()); - } - - @Test - void testGenerateAncestorsWhenParentDeptDisabled() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setParentId(PARENT_ID); - SysDeptEntity parentDept = new SysDeptEntity(); - parentDept.setStatus(0); - - when(deptService.getById(PARENT_ID)).thenReturn(parentDept); - - ApiException exception = assertThrows(ApiException.class, deptModel::generateAncestors); - Assertions.assertEquals(Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED, exception.getErrorCode()); - } - - - @Test - void testGenerateAncestorsSuccessful() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setParentId(PARENT_ID); - SysDeptEntity parentDept = new SysDeptEntity(); - parentDept.setStatus(1); - parentDept.setAncestors("1,100"); - when(deptService.getById(PARENT_ID)).thenReturn(parentDept); - deptModel.generateAncestors(); - - Assertions.assertEquals("1,100,2", deptModel.getAncestors()); - } - - - @Test - void testCheckStatusAllowChangeWhenDisableButHasChildDept() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setDeptId(DEPT_ID); - deptModel.setStatus(0); - when(deptService.hasChildrenDept(DEPT_ID, true)).thenReturn(true); - - ApiException exception = assertThrows(ApiException.class, deptModel::checkStatusAllowChange); - - Assertions.assertEquals(Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE, exception.getErrorCode()); - } - - - @Test - void testCheckStatusAllowChangeWhenDisableButNoChildDept() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setDeptId(DEPT_ID); - deptModel.setStatus(0); - when(deptService.hasChildrenDept(DEPT_ID, true)).thenReturn(false); - - Assertions.assertDoesNotThrow(deptModel::checkStatusAllowChange); - } - - - @Test - void testCheckStatusAllowChangeWhenEnableAndHasChildDept() { - DeptModel deptModel = deptModelFactory.create(); - deptModel.setDeptId(DEPT_ID); - deptModel.setStatus(1); - when(deptService.hasChildrenDept(DEPT_ID, true)).thenReturn(true); - Assertions.assertDoesNotThrow(deptModel::checkStatusAllowChange); - } - -} diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/post/model/PostModelTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/post/model/PostModelTest.java deleted file mode 100644 index 40f2642..0000000 --- a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/post/model/PostModelTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.agileboot.domain.system.post.model; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.agileboot.common.exception.ApiException; -import com.agileboot.common.exception.error.ErrorCode.Business; -import com.agileboot.domain.system.post.db.SysPostService; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -class PostModelTest { - - private final SysPostService postService = mock(SysPostService.class); - - private final PostModelFactory postModelFactory = new PostModelFactory(postService); - - private static final long POST_ID = 1L; - - @AfterEach - public void clean() { - Mockito.reset(postService); - } - - @Test - void testCheckCanBeDeleteWhenFailed() { - PostModel postModel = postModelFactory.create(); - postModel.setPostId(POST_ID); - - when(postService.isAssignedToUsers(POST_ID)).thenReturn(true); - - ApiException exception = assertThrows(ApiException.class, postModel::checkCanBeDelete); - Assertions.assertEquals(Business.POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED, exception.getErrorCode()); - } - - @Test - void testCheckCanBeDeleteWhenSuccessful() { - PostModel postModel = postModelFactory.create(); - postModel.setPostId(POST_ID); - - when(postService.isAssignedToUsers(POST_ID)).thenReturn(true); - - ApiException exception = assertThrows(ApiException.class, postModel::checkCanBeDelete); - Assertions.assertEquals(Business.POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED, exception.getErrorCode()); - } - - - @Test - void testCheckPostNameUnique() { - PostModel postWithSameName = postModelFactory.create(); - postWithSameName.setPostId(POST_ID); - postWithSameName.setPostName("post 1"); - PostModel postWithNewName = postModelFactory.create(); - postWithNewName.setPostName("post 2"); - postWithNewName.setPostId(POST_ID); - - when(postService.isPostNameDuplicated(POST_ID, eq("post 1"))).thenReturn(true); - when(postService.isPostNameDuplicated(POST_ID, eq("post 2"))).thenReturn(false); - - ApiException exception = assertThrows(ApiException.class, postWithSameName::checkPostNameUnique); - Assertions.assertEquals(Business.POST_NAME_IS_NOT_UNIQUE, exception.getErrorCode()); - Assertions.assertDoesNotThrow(postWithNewName::checkPostNameUnique); - } - - @Test - void testCheckPostCodeUnique() { - PostModel postWithSameCode = postModelFactory.create(); - postWithSameCode.setPostId(POST_ID); - postWithSameCode.setPostCode("code 1"); - PostModel postWithNewCode = postModelFactory.create(); - postWithNewCode.setPostId(POST_ID); - postWithNewCode.setPostCode("code 2"); - - when(postService.isPostCodeDuplicated(POST_ID, "code 1")).thenReturn(true); - when(postService.isPostCodeDuplicated(POST_ID, "code 2")).thenReturn(false); - - ApiException exception = assertThrows(ApiException.class, postWithSameCode::checkPostCodeUnique); - Assertions.assertEquals(Business.POST_CODE_IS_NOT_UNIQUE, exception.getErrorCode()); - Assertions.assertDoesNotThrow(postWithNewCode::checkPostCodeUnique); - } - -} diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/role/model/RoleModelTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/role/model/RoleModelTest.java index 0f81f9a..5ecd383 100644 --- a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/role/model/RoleModelTest.java +++ b/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/role/model/RoleModelTest.java @@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import cn.hutool.core.collection.ListUtil; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode.Business; import com.agileboot.domain.system.role.db.SysRoleMenuService; @@ -69,36 +68,4 @@ class RoleModelTest { Assertions.assertDoesNotThrow(roleWithNewKey::checkRoleKeyUnique); } - @Test - void testGenerateDeptIdSetWhenNull() { - RoleModel roleModel = roleModelFactory.create(); - roleModel.setDeptIds(null); - roleModel.generateDeptIdSet(); - - Assertions.assertEquals("", roleModel.getDeptIdSet()); - } - - - @Test - void testGenerateDeptIdSetWhenDuplicated() { - RoleModel roleModel = roleModelFactory.create(); - roleModel.setDeptIds(ListUtil.of(1L,1L,2L,3L)); - - ApiException exception = assertThrows(ApiException.class, roleModel::generateDeptIdSet); - - Assertions.assertEquals(Business.ROLE_DATA_SCOPE_DUPLICATED_DEPT, exception.getErrorCode()); - } - - @Test - void testGenerateDeptIdSetWhenSuccessful() { - RoleModel roleModel = roleModelFactory.create(); - roleModel.setDeptIds(ListUtil.of(1L,2L,3L)); - roleModel.generateDeptIdSet(); - - Assertions.assertEquals("1,2,3", roleModel.getDeptIdSet()); - } - - - - } diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/user/model/UserModelTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/user/model/UserModelTest.java index 347c313..6d11e06 100644 --- a/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/user/model/UserModelTest.java +++ b/backend/agileboot-domain/src/test/java/com/agileboot/domain/system/user/model/UserModelTest.java @@ -6,8 +6,6 @@ import static org.mockito.Mockito.when; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode.Business; -import com.agileboot.domain.system.dept.model.DeptModelFactory; -import com.agileboot.domain.system.post.model.PostModelFactory; import com.agileboot.domain.system.role.model.RoleModelFactory; import com.agileboot.domain.system.user.command.UpdateUserPasswordCommand; import com.agileboot.infrastructure.user.AuthenticationUtils; @@ -19,12 +17,9 @@ import org.junit.jupiter.api.Test; class UserModelTest { private final SysUserService userService = mock(SysUserService.class); - private final PostModelFactory postModelFactory = mock(PostModelFactory.class); - private final DeptModelFactory deptModelFactory = mock(DeptModelFactory.class); private final RoleModelFactory roleModelFactory = mock(RoleModelFactory.class); - private final UserModelFactory userModelFactory = new UserModelFactory(userService, postModelFactory, - deptModelFactory, roleModelFactory); + private final UserModelFactory userModelFactory = new UserModelFactory(userService, roleModelFactory); private static final long USER_ID = 1L; private static final long ADMIN_USER_ID = 1L; @@ -121,9 +116,9 @@ class UserModelTest { UserModel userModel = userModelFactory.create(); userModel.setPassword("$2a$10$rb1wRoEIkLbIknREEN1LH.FGs4g0oOS5t6l5LQ793nRaFO.SPHDHy"); UpdateUserPasswordCommand passwordCommand = new UpdateUserPasswordCommand(); - passwordCommand.setOldPassword("admin123"); String newPassword = "admin456"; passwordCommand.setNewPassword(newPassword); + passwordCommand.setConfirmPassword(newPassword); userModel.modifyPassword(passwordCommand); @@ -131,16 +126,25 @@ class UserModelTest { } @Test - void testModifyPasswordWhenPasswordWrong() { + void testModifyPasswordWhenConfirmPasswordNotMatch() { UserModel userModel = userModelFactory.create(); userModel.setPassword("$2a$10$rb1wRoEIkLbIknREEN1LH.FGs4g0oOS5t6l5LQ793nRaFO.SPHDHy"); UpdateUserPasswordCommand passwordCommand = new UpdateUserPasswordCommand(); - passwordCommand.setOldPassword("admin999"); - String newPassword = "admin456"; - passwordCommand.setNewPassword(newPassword); + passwordCommand.setNewPassword("admin456"); + passwordCommand.setConfirmPassword("admin789"); ApiException exception = assertThrows(ApiException.class, () -> userModel.modifyPassword(passwordCommand)); - Assertions.assertEquals(Business.USER_PASSWORD_IS_NOT_CORRECT, exception.getErrorCode()); + Assertions.assertEquals(Business.USER_REGISTER_PASSWORD_NOT_MATCH, exception.getErrorCode()); + } + + @Test + void testModifyPasswordWhenPasswordIsEmpty() { + UserModel userModel = userModelFactory.create(); + UpdateUserPasswordCommand passwordCommand = new UpdateUserPasswordCommand(); + passwordCommand.setConfirmPassword("admin456"); + + ApiException exception = assertThrows(ApiException.class, () -> userModel.modifyPassword(passwordCommand)); + Assertions.assertEquals(Business.USER_PASSWORD_IS_EMPTY, exception.getErrorCode()); } @Test @@ -148,9 +152,9 @@ class UserModelTest { UserModel userModel = userModelFactory.create(); userModel.setPassword("$2a$10$rb1wRoEIkLbIknREEN1LH.FGs4g0oOS5t6l5LQ793nRaFO.SPHDHy"); UpdateUserPasswordCommand passwordCommand = new UpdateUserPasswordCommand(); - passwordCommand.setOldPassword("admin123"); String newPassword = "admin123"; passwordCommand.setNewPassword(newPassword); + passwordCommand.setConfirmPassword(newPassword); ApiException exception = assertThrows(ApiException.class, () -> userModel.modifyPassword(passwordCommand)); Assertions.assertEquals(Business.USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD, exception.getErrorCode()); diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysDeptServiceImplTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysDeptServiceImplTest.java deleted file mode 100644 index 9b31ead..0000000 --- a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysDeptServiceImplTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.agileboot.integrationTest.db; - -import com.agileboot.integrationTest.IntegrationTestApplication; -import com.agileboot.domain.system.dept.db.SysDeptService; -import javax.annotation.Resource; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.Rollback; -import org.springframework.test.context.junit4.SpringRunner; - -@SpringBootTest(classes = IntegrationTestApplication.class) -@RunWith(SpringRunner.class) -class SysDeptServiceImplTest { - - @Resource - SysDeptService deptService; - - @Test - @Rollback - void testIsDeptNameDuplicated() { - boolean addWithSame = deptService.isDeptNameDuplicated("AgileBoot科技", null, null); - boolean updateWithSame = deptService.isDeptNameDuplicated("AgileBoot科技", 1L, null); - boolean addSameInParent = deptService.isDeptNameDuplicated("深圳总公司", null, 1L); - - Assertions.assertTrue(addWithSame); - Assertions.assertFalse(updateWithSame); - Assertions.assertTrue(addSameInParent); - } - - - @Test - @Rollback - void testHasChildDept() { - boolean hasChild = deptService.hasChildrenDept(3L, null); - boolean hasDisableChild = deptService.hasChildrenDept(3L, false); - - Assertions.assertTrue(hasChild); - Assertions.assertTrue(hasDisableChild); - } - - - @Test - @Rollback - void testIsChildOfTheDept() { - boolean isIndirectChild = deptService.isChildOfTheDept(1L, 10L); - boolean isDirectChild = deptService.isChildOfTheDept(3L, 10L); - boolean isNotChild = deptService.isChildOfTheDept(5L, 10L); - - Assertions.assertTrue(isIndirectChild); - Assertions.assertTrue(isDirectChild); - Assertions.assertFalse(isNotChild); - } - - - @Test - @Rollback - void testIsDeptAssignedToUsers() { - boolean notAssigned = deptService.isDeptAssignedToUsers(1L); - boolean isAssigned = deptService.isDeptAssignedToUsers(4L); - - Assertions.assertFalse(notAssigned); - Assertions.assertTrue(isAssigned); - } - - -} diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysMenuServiceImplTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysMenuServiceImplTest.java index d741b8d..dcbbad2 100644 --- a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysMenuServiceImplTest.java +++ b/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysMenuServiceImplTest.java @@ -1,6 +1,5 @@ package com.agileboot.integrationTest.db; -import cn.hutool.core.collection.CollUtil; import com.agileboot.integrationTest.IntegrationTestApplication; import com.agileboot.domain.system.menu.db.SysMenuEntity; import com.agileboot.domain.system.menu.db.SysMenuService; @@ -17,25 +16,28 @@ import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) class SysMenuServiceImplTest { + private static final int COMMON_ROLE_COLLABORATION_MENU_COUNT = 7; + @Resource SysMenuService menuService; @Test @Rollback void testGetMenuListByUserId() { - List menusMissingLastMenu = menuService.getMenuListByUserId(2L); - List allMenus = menuService.list(); + List registerUserMenus = menuService.getMenuListByUserId(2L); - Assertions.assertEquals(allMenus.size(), menusMissingLastMenu.size() + 1); + Assertions.assertEquals(COMMON_ROLE_COLLABORATION_MENU_COUNT, registerUserMenus.size()); + Assertions.assertTrue(registerUserMenus.stream().allMatch(menu -> menu.getMenuId() >= 3000L)); } @Test @Rollback void testGetMenuIdsByRoleId() { - List menusMissingLastMenu = menuService.getMenuIdsByRoleId(2L); - List allMenus = menuService.list(); + List registerUserMenuIds = menuService.getMenuIdsByRoleId(2L); - Assertions.assertEquals(allMenus.size(), menusMissingLastMenu.size() + 1); + Assertions.assertEquals(COMMON_ROLE_COLLABORATION_MENU_COUNT, registerUserMenuIds.size()); + Assertions.assertTrue(registerUserMenuIds.contains(3000L)); + Assertions.assertTrue(registerUserMenuIds.contains(3006L)); } @Test @@ -63,11 +65,8 @@ class SysMenuServiceImplTest { @Test @Rollback void testIsMenuAssignToRole() { - List allMenus = menuService.list(); - - boolean isAssignToRole = menuService.isMenuAssignToRoles(CollUtil.getFirst(allMenus).getMenuId()); - // role2 默认不给最后一个权限 所以最后一个菜单无权限 - boolean isNotAssignToRole = menuService.isMenuAssignToRoles(CollUtil.getLast(allMenus).getMenuId()); + boolean isAssignToRole = menuService.isMenuAssignToRoles(3000L); + boolean isNotAssignToRole = menuService.isMenuAssignToRoles(1L); Assertions.assertFalse(isNotAssignToRole); Assertions.assertTrue(isAssignToRole); diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysPostServiceImplTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysPostServiceImplTest.java deleted file mode 100644 index 4bca6c5..0000000 --- a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysPostServiceImplTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.agileboot.integrationTest.db; - -import com.agileboot.integrationTest.IntegrationTestApplication; -import com.agileboot.domain.system.post.db.SysPostService; -import javax.annotation.Resource; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.Rollback; -import org.springframework.test.context.junit4.SpringRunner; - -@SpringBootTest(classes = IntegrationTestApplication.class) -@RunWith(SpringRunner.class) -class SysPostServiceImplTest { - - @Resource - SysPostService postService; - - @Test - @Rollback - void testIsPostNameDuplicated() { - boolean addWithSame = postService.isPostNameDuplicated(null, "董事长"); - boolean updateWithSame = postService.isPostNameDuplicated(1L, "董事长"); - boolean addWithoutSame = postService.isPostNameDuplicated(null, "董事长1"); - - Assertions.assertTrue(addWithSame); - Assertions.assertFalse(updateWithSame); - Assertions.assertFalse(addWithoutSame); - } - - - @Test - @Rollback - void testIsPostCodeDuplicated() { - boolean addWithSame = postService.isPostCodeDuplicated(null, "ceo"); - boolean updateWithSame = postService.isPostCodeDuplicated(1L, "ceo"); - boolean addWithoutSame = postService.isPostCodeDuplicated(null, "ceo1"); - - Assertions.assertTrue(addWithSame); - Assertions.assertFalse(updateWithSame); - Assertions.assertFalse(addWithoutSame); - } - - - @Test - @Rollback - void testIsAssignedToUsers() { - boolean assignedPost = postService.isAssignedToUsers(1L); - boolean unassignedPost = postService.isAssignedToUsers(3L); - - Assertions.assertTrue(assignedPost); - Assertions.assertFalse(unassignedPost); - } - - -} diff --git a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysUserServiceImplTest.java b/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysUserServiceImplTest.java index 9a72488..30dcc74 100644 --- a/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysUserServiceImplTest.java +++ b/backend/agileboot-domain/src/test/java/com/agileboot/integrationTest/db/SysUserServiceImplTest.java @@ -4,17 +4,12 @@ import com.agileboot.domain.system.role.query.AllocatedRoleQuery; import com.agileboot.domain.system.role.query.UnallocatedRoleQuery; import com.agileboot.domain.system.user.query.SearchUserQuery; import com.agileboot.integrationTest.IntegrationTestApplication; -import com.agileboot.domain.system.menu.db.SysMenuEntity; -import com.agileboot.domain.system.post.db.SysPostEntity; import com.agileboot.domain.system.role.db.SysRoleEntity; import com.agileboot.domain.system.user.db.SysUserEntity; import com.agileboot.domain.system.user.db.SearchUserDO; -import com.agileboot.domain.system.menu.db.SysMenuService; import com.agileboot.domain.system.user.db.SysUserService; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import javax.annotation.Resource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -27,10 +22,10 @@ import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) class SysUserServiceImplTest { + private static final int COMMON_ROLE_COLLABORATION_PERMISSION_COUNT = 6; + @Resource SysUserService userService; - @Resource - SysMenuService menuService; @Test @Rollback @@ -76,24 +71,14 @@ class SysUserServiceImplTest { Assertions.assertEquals("admin", roleOfUser.getRoleKey()); } - @Test - @Rollback - void testGetPostOfUser() { - SysPostEntity postOfUser = userService.getPostOfUser(1L); - - Assertions.assertEquals(1L, postOfUser.getPostId()); - Assertions.assertEquals("董事长", postOfUser.getPostName()); - Assertions.assertEquals("ceo", postOfUser.getPostCode()); - } - @Test @Rollback void testGetMenuPermissionsForUsers() { Set permissionByUser = userService.getMenuPermissionsForUser(2L); - List allMenus = menuService.list(); - Set allPermissions = allMenus.stream().map(SysMenuEntity::getPermission).collect(Collectors.toSet()); - Assertions.assertEquals(allPermissions.size() - 1, permissionByUser.size()); + Assertions.assertEquals(COMMON_ROLE_COLLABORATION_PERMISSION_COUNT, permissionByUser.size()); + Assertions.assertTrue(permissionByUser.contains("collaboration:record:list")); + Assertions.assertTrue(permissionByUser.contains("collaboration:record:remove")); } @Test @@ -103,7 +88,6 @@ class SysUserServiceImplTest { Assertions.assertEquals(1L, admin.getUserId()); Assertions.assertEquals(1L, admin.getRoleId()); - Assertions.assertEquals(1L, admin.getPostId()); } @Test diff --git a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/redis/CacheKeyEnum.java b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/redis/CacheKeyEnum.java index 98c1025..ec183dc 100644 --- a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/redis/CacheKeyEnum.java +++ b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/redis/CacheKeyEnum.java @@ -15,7 +15,6 @@ public enum CacheKeyEnum { RATE_LIMIT_KEY("rate_limit:", 60, TimeUnit.SECONDS), USER_ENTITY_KEY("user_entity:", 60, TimeUnit.MINUTES), ROLE_ENTITY_KEY("role_entity:", 60, TimeUnit.MINUTES), - POST_ENTITY_KEY("post_entity:", 60, TimeUnit.MINUTES), ROLE_MODEL_INFO_KEY("role_model_info:", 60, TimeUnit.MINUTES), ; diff --git a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/MySqlFunction.java b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/MySqlFunction.java deleted file mode 100644 index 5e3b4a6..0000000 --- a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/MySqlFunction.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.agileboot.infrastructure.mybatisplus; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; - -import java.util.List; - -/** - * 由于H2不支持大部分Mysql的函数 所以要自己实现 - * 在H2的初始化 h2sql/agileboot_schema.sql加上这句 - * CREATE ALIAS FIND_IN_SET FOR "com.agileboot.infrastructure.mybatisplus.MySqlFunction.find_in_set"; - * - * @author valarchie - */ -public class MySqlFunction { - - private MySqlFunction() { - } - - public static boolean findInSet(String target, String setString) { - if (setString == null) { - return false; - } - - List split = StrUtil.split(setString, ","); - - return CollUtil.contains(split, target); - } - -} diff --git a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/DataScopeEnum.java b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/DataScopeEnum.java index b969550..8c2fa9f 100644 --- a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/DataScopeEnum.java +++ b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/DataScopeEnum.java @@ -12,9 +12,6 @@ public enum DataScopeEnum implements BasicEnum { * 数据权限范围 */ ALL(1, "所有数据权限"), - CUSTOM_DEFINE(2, "自定义数据权限"), - SINGLE_DEPT(3, "本部门数据权限"), - DEPT_TREE(4, "本部门以及子孙部门数据权限"), ONLY_SELF(5, "仅本人数据权限"); private final int value; diff --git a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/RoleInfo.java b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/RoleInfo.java index 7afa9c5..b5c67bf 100644 --- a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/RoleInfo.java +++ b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/RoleInfo.java @@ -22,12 +22,11 @@ public class RoleInfo { public static final Set ADMIN_PERMISSIONS = SetUtils.hashSet(ALL_PERMISSIONS); - public RoleInfo(Long roleId, String roleKey, DataScopeEnum dataScope, Set deptIdSet, - Set menuPermissions, Set menuIds) { + public RoleInfo(Long roleId, String roleKey, DataScopeEnum dataScope, Set menuPermissions, + Set menuIds) { this.roleId = roleId; this.roleKey = roleKey; this.dataScope = dataScope; - this.deptIdSet = deptIdSet; this.menuPermissions = menuPermissions != null ? menuPermissions : SetUtils.emptySet(); this.menuIds = menuIds != null ? menuIds : SetUtils.emptySet(); } @@ -36,7 +35,6 @@ public class RoleInfo { private Long roleId; private String roleName; private DataScopeEnum dataScope; - private Set deptIdSet; private String roleKey; private Set menuPermissions; private Set menuIds; diff --git a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/SystemLoginUser.java b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/SystemLoginUser.java index f97488a..93c9ccd 100644 --- a/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/SystemLoginUser.java +++ b/backend/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/user/web/SystemLoginUser.java @@ -16,8 +16,6 @@ public class SystemLoginUser extends BaseLoginUser { private boolean isAdmin; - private Long deptId; - private RoleInfo roleInfo; /** @@ -26,14 +24,12 @@ public class SystemLoginUser extends BaseLoginUser { private Long autoRefreshCacheTime; - public SystemLoginUser(Long userId, Boolean isAdmin, String username, String password, RoleInfo roleInfo, - Long deptId) { + public SystemLoginUser(Long userId, Boolean isAdmin, String username, String password, RoleInfo roleInfo) { this.userId = userId; this.isAdmin = isAdmin; this.username = username; this.password = password; this.roleInfo = roleInfo; - this.deptId = deptId; } public RoleInfo getRoleInfo() { @@ -44,9 +40,4 @@ public class SystemLoginUser extends BaseLoginUser { return getRoleInfo().getRoleId(); } - public Long getDeptId() { - return deptId; - } - - } diff --git a/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_data.sql b/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_data.sql index faa25f9..b3b5b5a 100644 --- a/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_data.sql +++ b/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_data.sql @@ -27,18 +27,7 @@ INSERT INTO `sys_config` VALUES ('5', '账号自助-是否开启用户注册功 -- ---------------------------- --- Records of sys_dept -- ---------------------------- -INSERT INTO `sys_dept` VALUES ('1', '0', '0', 'AgileBoot科技', '0', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('2', '1', '0,1', '深圳总公司', '1', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('3', '1', '0,1', '长沙分公司', '2', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('4', '2', '0,1,2', '研发部门', '1', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('5', '2', '0,1,2', '市场部门', '2', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('6', '2', '0,1,2', '测试部门', '3', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('7', '2', '0,1,2', '财务部门', '4', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('8', '2', '0,1,2', '运维部门', '5', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('9', '3', '0,1,3', '市场部门', '1', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_dept` VALUES ('10', '3', '0,1,3', '财务部门', '2', null, 'valarchie', '15888888888', 'valarchie@163.com', '0', null, '2022-05-21 08:30:54', null, null, '0'); @@ -56,8 +45,6 @@ INSERT INTO sys_menu VALUES (4, 'AgileBoot官网', 3, 'AgileBootguanwangIframeRo INSERT INTO sys_menu VALUES (5, '用户管理', 1, 'SystemUser', 1, '/system/user/index', 0, 'system:user:list', '{"title":"用户管理","icon":"ep:user-filled","showParent":1}', 1, '用户管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:13', 0); INSERT INTO sys_menu VALUES (6, '角色管理', 1, 'SystemRole', 1, '/system/role/index', 0, 'system:role:list', '{"title":"角色管理","icon":"ep:user","showParent":1}', 1, '角色管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:23', 0); INSERT INTO sys_menu VALUES (7, '菜单管理', 1, 'MenuManagement', 1, '/system/menu/index', 0, 'system:menu:list', '{"title":"菜单管理","icon":"ep:menu","showParent":1}', 1, '菜单管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:41', 0); -INSERT INTO sys_menu VALUES (8, '部门管理', 1, 'Department', 1, '/system/dept/index', 0, 'system:dept:list', '{"title":"部门管理","icon":"fa-solid:code-branch","showParent":1}', 1, '部门管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:35', 0); -INSERT INTO sys_menu VALUES (9, '岗位管理', 1, 'Post', 1, '/system/post/index', 0, 'system:post:list', '{"title":"岗位管理","icon":"ep:postcard","showParent":1}', 1, '岗位管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:11', 0); INSERT INTO sys_menu VALUES (10, '参数设置', 1, 'Config', 1, '/system/config/index', 0, 'system:config:list', '{"title":"参数设置","icon":"ep:setting","showParent":1}', 1, '参数设置菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:03', 0); INSERT INTO sys_menu VALUES (11, '通知公告', 1, 'SystemNotice', 1, '/system/notice/index', 0, 'system:notice:list', '{"title":"通知公告","icon":"ep:notification","showParent":1}', 1, '通知公告菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:56', 0); INSERT INTO sys_menu VALUES (12, '日志管理', 1, 'LogManagement', 1, '/system/logd', 0, '', '{"title":"日志管理","icon":"ep:document","showParent":1}', 1, '日志管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:47', 0); @@ -84,15 +71,6 @@ INSERT INTO sys_menu VALUES (32, '菜单查询', 0, ' ', 7, '', 1, 'system:menu: INSERT INTO sys_menu VALUES (33, '菜单新增', 0, ' ', 7, '', 1, 'system:menu:add', '{"title":"菜单新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu VALUES (34, '菜单修改', 0, ' ', 7, '', 1, 'system:menu:edit', '{"title":"菜单修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu VALUES (35, '菜单删除', 0, ' ', 7, '', 1, 'system:menu:remove', '{"title":"菜单删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (36, '部门查询', 0, ' ', 8, '', 1, 'system:dept:query', '{"title":"部门查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (37, '部门新增', 0, ' ', 8, '', 1, 'system:dept:add', '{"title":"部门新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (38, '部门修改', 0, ' ', 8, '', 1, 'system:dept:edit', '{"title":"部门修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (39, '部门删除', 0, ' ', 8, '', 1, 'system:dept:remove', '{"title":"部门删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (40, '岗位查询', 0, ' ', 9, '', 1, 'system:post:query', '{"title":"岗位查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (41, '岗位新增', 0, ' ', 9, '', 1, 'system:post:add', '{"title":"岗位新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (42, '岗位修改', 0, ' ', 9, '', 1, 'system:post:edit', '{"title":"岗位修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (43, '岗位删除', 0, ' ', 9, '', 1, 'system:post:remove', '{"title":"岗位删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu VALUES (44, '岗位导出', 0, ' ', 9, '', 1, 'system:post:export', '{"title":"岗位导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu VALUES (45, '参数查询', 0, ' ', 10, '', 1, 'system:config:query', '{"title":"参数查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu VALUES (46, '参数新增', 0, ' ', 10, '', 1, 'system:config:add', '{"title":"参数新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu VALUES (47, '参数修改', 0, ' ', 10, '', 1, 'system:config:edit', '{"title":"参数修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); @@ -114,6 +92,13 @@ INSERT INTO sys_menu VALUES (62, '单条强退', 0, ' ', 13, '', 1, 'monitor:o INSERT INTO sys_menu VALUES (63, 'AgileBoot Github地址', 4, 'https://github.com/valarchie/AgileBoot-Back-End', 0, '/external', 0, '', '{"title":"AgileBoot Github地址","icon":"fa-solid:external-link-alt","showParent":1,"rank":9}', 1, 'Agileboot github地址', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:12:13', 0); INSERT INTO sys_menu VALUES (64, '首页', 2, '', 0, '/global', 0, '121212', '{"title":"首页","showParent":1,"rank":3}', 1, '', 1, '2023-07-24 22:36:03', 1, '2023-07-24 22:38:37', 1); INSERT INTO sys_menu VALUES (65, '个人中心', 1, 'PersonalCenter', 2053, '/system/user/profile', 0, '434sdf', '{"title":"个人中心","showParent":1,"rank":3}', 1, '', 1, '2023-07-24 22:36:55', null, null, 1); +INSERT INTO sys_menu VALUES (3000, '合作管理', 2, '', 0, '/collaboration', 0, '', '{"title":"合作管理","icon":"ep:connection","showParent":1,"rank":4}', 1, '合作管理目录', 0, now(), null, null, 0); +INSERT INTO sys_menu VALUES (3001, '合作记录', 1, 'CollaborationRecord', 3000, '/collaboration/record/index', 0, 'collaboration:record:list', '{"title":"合作记录","icon":"ep:notebook","showParent":1}', 1, '合作记录菜单', 0, now(), null, null, 0); +INSERT INTO sys_menu VALUES (3002, '月度统计', 1, 'CollaborationStatistics', 3000, '/collaboration/statistics/index', 0, 'collaboration:record:statistics', '{"title":"月度统计","icon":"ep:data-analysis","showParent":1}', 1, '月度统计菜单', 0, now(), null, null, 0); +INSERT INTO sys_menu VALUES (3003, '合作查询', 0, ' ', 3001, '', 1, 'collaboration:record:query', '{"title":"合作查询"}', 1, '', 0, now(), null, null, 0); +INSERT INTO sys_menu VALUES (3004, '合作新增', 0, ' ', 3001, '', 1, 'collaboration:record:add', '{"title":"合作新增"}', 1, '', 0, now(), null, null, 0); +INSERT INTO sys_menu VALUES (3005, '合作修改', 0, ' ', 3001, '', 1, 'collaboration:record:edit', '{"title":"合作修改"}', 1, '', 0, now(), null, null, 0); +INSERT INTO sys_menu VALUES (3006, '合作删除', 0, ' ', 3001, '', 1, 'collaboration:record:remove', '{"title":"合作删除"}', 1, '', 0, now(), null, null, 0); -- ---------------------------- @@ -130,88 +115,28 @@ INSERT INTO `sys_notice` VALUES ('2', '维护通知:2018-07-01 AgileBoot系统 -- ---------------------------- --- Records of sys_post -- ---------------------------- -INSERT INTO `sys_post` VALUES ('1', 'ceo', '董事长', '1', '1', '', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_post` VALUES ('2', 'se', '项目经理', '2', '1', '', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_post` VALUES ('3', 'hr', '人力资源', '3', '1', '', null, '2022-05-21 08:30:54', null, null, '0'); -INSERT INTO `sys_post` VALUES ('4', 'user', '普通员工', '5', '0', '', null, '2022-05-21 08:30:54', null, null, '0'); -- ---------------------------- -- Records of sys_role -- ---------------------------- -INSERT INTO `sys_role` VALUES ('1', '超级管理员', 'admin', '1', '1', '', '1', null, '2022-05-21 08:30:54', null, null, '超级管理员', '0'); -INSERT INTO `sys_role` VALUES ('2', '普通角色', 'common', '3', '2', '', '1', null, '2022-05-21 08:30:54', null, null, '普通角色', '0'); -INSERT INTO `sys_role` VALUES ('3', '闲置角色', 'unused', '4', '2', '', '0', null, '2022-05-21 08:30:54', null, null, '未使用的角色', '0'); +INSERT INTO `sys_role` VALUES ('1', '超级管理员', 'admin', '1', '1', '1', null, '2022-05-21 08:30:54', null, null, '超级管理员', '0'); +INSERT INTO `sys_role` VALUES ('2', '普通用户', 'common', '3', '5', '1', null, '2022-05-21 08:30:54', null, null, '自助注册用户默认角色,默认允许使用合作管理', '0'); +INSERT INTO `sys_role` VALUES ('3', '闲置角色', 'unused', '4', '5', '0', null, '2022-05-21 08:30:54', null, null, '未使用的角色', '0'); -- ---------------------------- -- Records of sys_role_menu -- ---------------------------- -INSERT INTO `sys_role_menu` VALUES ('2', '1'); -INSERT INTO `sys_role_menu` VALUES ('2', '2'); -INSERT INTO `sys_role_menu` VALUES ('2', '3'); -INSERT INTO `sys_role_menu` VALUES ('2', '4'); -INSERT INTO `sys_role_menu` VALUES ('2', '5'); -INSERT INTO `sys_role_menu` VALUES ('2', '6'); -INSERT INTO `sys_role_menu` VALUES ('2', '7'); -INSERT INTO `sys_role_menu` VALUES ('2', '8'); -INSERT INTO `sys_role_menu` VALUES ('2', '9'); -INSERT INTO `sys_role_menu` VALUES ('2', '10'); -INSERT INTO `sys_role_menu` VALUES ('2', '11'); -INSERT INTO `sys_role_menu` VALUES ('2', '12'); -INSERT INTO `sys_role_menu` VALUES ('2', '13'); -INSERT INTO `sys_role_menu` VALUES ('2', '14'); -INSERT INTO `sys_role_menu` VALUES ('2', '15'); -INSERT INTO `sys_role_menu` VALUES ('2', '16'); -INSERT INTO `sys_role_menu` VALUES ('2', '17'); -INSERT INTO `sys_role_menu` VALUES ('2', '18'); -INSERT INTO `sys_role_menu` VALUES ('2', '19'); -INSERT INTO `sys_role_menu` VALUES ('2', '20'); -INSERT INTO `sys_role_menu` VALUES ('2', '21'); -INSERT INTO `sys_role_menu` VALUES ('2', '22'); -INSERT INTO `sys_role_menu` VALUES ('2', '23'); -INSERT INTO `sys_role_menu` VALUES ('2', '24'); -INSERT INTO `sys_role_menu` VALUES ('2', '25'); -INSERT INTO `sys_role_menu` VALUES ('2', '26'); -INSERT INTO `sys_role_menu` VALUES ('2', '27'); -INSERT INTO `sys_role_menu` VALUES ('2', '28'); -INSERT INTO `sys_role_menu` VALUES ('2', '29'); -INSERT INTO `sys_role_menu` VALUES ('2', '30'); -INSERT INTO `sys_role_menu` VALUES ('2', '31'); -INSERT INTO `sys_role_menu` VALUES ('2', '32'); -INSERT INTO `sys_role_menu` VALUES ('2', '33'); -INSERT INTO `sys_role_menu` VALUES ('2', '34'); -INSERT INTO `sys_role_menu` VALUES ('2', '35'); -INSERT INTO `sys_role_menu` VALUES ('2', '36'); -INSERT INTO `sys_role_menu` VALUES ('2', '37'); -INSERT INTO `sys_role_menu` VALUES ('2', '38'); -INSERT INTO `sys_role_menu` VALUES ('2', '39'); -INSERT INTO `sys_role_menu` VALUES ('2', '40'); -INSERT INTO `sys_role_menu` VALUES ('2', '41'); -INSERT INTO `sys_role_menu` VALUES ('2', '42'); -INSERT INTO `sys_role_menu` VALUES ('2', '43'); -INSERT INTO `sys_role_menu` VALUES ('2', '44'); -INSERT INTO `sys_role_menu` VALUES ('2', '45'); -INSERT INTO `sys_role_menu` VALUES ('2', '46'); -INSERT INTO `sys_role_menu` VALUES ('2', '47'); -INSERT INTO `sys_role_menu` VALUES ('2', '48'); -INSERT INTO `sys_role_menu` VALUES ('2', '49'); -INSERT INTO `sys_role_menu` VALUES ('2', '50'); -INSERT INTO `sys_role_menu` VALUES ('2', '51'); -INSERT INTO `sys_role_menu` VALUES ('2', '52'); -INSERT INTO `sys_role_menu` VALUES ('2', '53'); -INSERT INTO `sys_role_menu` VALUES ('2', '54'); -INSERT INTO `sys_role_menu` VALUES ('2', '55'); -INSERT INTO `sys_role_menu` VALUES ('2', '56'); -INSERT INTO `sys_role_menu` VALUES ('2', '57'); -INSERT INTO `sys_role_menu` VALUES ('2', '58'); -INSERT INTO `sys_role_menu` VALUES ('2', '59'); -INSERT INTO `sys_role_menu` VALUES ('2', '60'); -INSERT INTO `sys_role_menu` VALUES ('2', '61'); --- roleId = 2的权限 特地少一个 方便测试 +INSERT INTO `sys_role_menu` VALUES ('2', '3000'); +INSERT INTO `sys_role_menu` VALUES ('2', '3001'); +INSERT INTO `sys_role_menu` VALUES ('2', '3002'); +INSERT INTO `sys_role_menu` VALUES ('2', '3003'); +INSERT INTO `sys_role_menu` VALUES ('2', '3004'); +INSERT INTO `sys_role_menu` VALUES ('2', '3005'); +INSERT INTO `sys_role_menu` VALUES ('2', '3006'); INSERT INTO `sys_role_menu` VALUES ('3', '1'); @@ -220,6 +145,6 @@ INSERT INTO `sys_role_menu` VALUES ('3', '1'); -- ---------------------------- -- Records of sys_user -- ---------------------------- -INSERT INTO `sys_user` VALUES ('1', '1', '1', '4', 'admin', 'valarchie1', '0', 'agileboot@163.com', '15888888889', '0', '', '$2a$10$rb1wRoEIkLbIknREEN1LH.FGs4g0oOS5t6l5LQ793nRaFO.SPHDHy', '1', '127.0.0.1', '2022-10-06 17:00:06', 1, null, '2022-05-21 08:30:54', '1', '2022-10-06 17:00:06', '管理员', '0'); -INSERT INTO `sys_user` VALUES ('2', '2', '2', '5', 'ag1', 'valarchie2', '0', 'agileboot1@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '1', '127.0.0.1', '2022-05-21 08:30:54', 0, null, '2022-05-21 08:30:54', null, null, '测试员1', '0'); -INSERT INTO `sys_user` VALUES ('3', '2', '0', '5', 'ag2', 'valarchie3', '0', 'agileboot2@qq.com', '15666666667', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '1', '127.0.0.1', '2022-05-21 08:30:54', 0, null, '2022-05-21 08:30:54', null, null, '测试员2', '0'); +INSERT INTO `sys_user` VALUES ('1', '1', 'admin', 'valarchie1', '0', 'agileboot@163.com', '15888888889', '0', '', '$2a$10$rb1wRoEIkLbIknREEN1LH.FGs4g0oOS5t6l5LQ793nRaFO.SPHDHy', '1', '127.0.0.1', '2022-10-06 17:00:06', 1, null, '2022-05-21 08:30:54', '1', '2022-10-06 17:00:06', '管理员', '0'); +INSERT INTO `sys_user` VALUES ('2', '2', 'ag1', 'valarchie2', '0', 'agileboot1@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '1', '127.0.0.1', '2022-05-21 08:30:54', 0, null, '2022-05-21 08:30:54', null, null, '测试员1', '0'); +INSERT INTO `sys_user` VALUES ('3', '0', 'ag2', 'valarchie3', '0', 'agileboot2@qq.com', '15666666667', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '1', '127.0.0.1', '2022-05-21 08:30:54', 0, null, '2022-05-21 08:30:54', null, null, '测试员2', '0'); diff --git a/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_schema.sql b/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_schema.sql index 8311bac..ad384a2 100644 --- a/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_schema.sql +++ b/backend/agileboot-infrastructure/src/main/resources/h2sql/agileboot_schema.sql @@ -17,26 +17,6 @@ create table sys_config deleted int default 0 not null comment '逻辑删除' ); -create sequence if not exists sys_dept_seq start with 11 increment by 1; -create table sys_dept -( - dept_id int default next value for sys_dept_seq, - parent_id bigint default 0 not null comment '父部门id', - ancestors text not null comment '祖级列表', - dept_name varchar(64) default '' not null comment '部门名称', - order_num int default 0 not null comment '显示顺序', - leader_id bigint null, - leader_name varchar(64) null comment '负责人', - phone varchar(16) null comment '联系电话', - email varchar(128) null comment '邮箱', - status smallint default 0 not null comment '部门状态(0正常 1停用)', - creator_id bigint null comment '创建者ID', - create_time datetime null comment '创建时间', - updater_id bigint null comment '更新者ID', - update_time datetime null comment '更新时间', - deleted tinyint default 0 not null comment '逻辑删除' -); - create sequence if not exists sys_login_info_seq start with 1 increment by 1; create table sys_login_info ( @@ -52,7 +32,7 @@ create table sys_login_info deleted tinyint default 0 not null comment '逻辑删除' ); -create sequence if not exists sys_menu_seq start with 63 increment by 1; +create sequence if not exists sys_menu_seq start with 3007 increment by 1; create table sys_menu ( menu_id bigint auto_increment comment '菜单ID' @@ -104,8 +84,6 @@ create table sys_operation_log username varchar(32) default '' null comment '操作人员', operator_ip varchar(128) default '' null comment '操作人员ip', operator_location varchar(256) default '' null comment '操作地点', - dept_id bigint default 0 null comment '部门ID', - dept_name varchar(64) null comment '部门名称', operation_param varchar(2048) default '' null comment '请求参数', operation_result varchar(2048) default '' null comment '返回参数', status smallint default 1 not null comment '操作状态(1正常 0异常)', @@ -114,22 +92,6 @@ create table sys_operation_log deleted tinyint default 0 not null comment '逻辑删除' ); -create sequence if not exists sys_post_seq start with 5 increment by 1; -create table sys_post -( - post_id bigint default next value for sys_post_seq, - post_code varchar(64) not null comment '岗位编码', - post_name varchar(64) not null comment '岗位名称', - post_sort int not null comment '显示顺序', - status smallint not null comment '状态(1正常 0停用)', - remark varchar(512) null comment '备注', - creator_id bigint null, - create_time datetime null comment '创建时间', - updater_id bigint null, - update_time datetime null comment '更新时间', - deleted tinyint default 0 not null comment '逻辑删除' -); - create sequence if not exists sys_role_seq start with 4 increment by 1; create table sys_role ( @@ -137,8 +99,7 @@ create table sys_role role_name varchar(32) not null comment '角色名称', role_key varchar(128) not null comment '角色权限字符串', role_sort int not null comment '显示顺序', - data_scope smallint default 1 null comment '数据范围(1:全部数据权限 2:自定数据权限 3: 本部门数据权限 4: 本部门及以下数据权限 5: 本人权限)', - dept_id_set varchar(1024) default '' null comment '角色所拥有的部门数据权限', + data_scope smallint default 1 null comment '数据范围(1:全部数据权限 5: 本人权限)', status smallint not null comment '角色状态(1正常 0停用)', creator_id bigint null comment '创建者ID', create_time datetime null comment '创建时间', @@ -158,9 +119,7 @@ create sequence if not exists sys_user_seq start with 4 increment by 1; create table sys_user ( user_id bigint default next value for sys_user_seq, - post_id bigint null comment '职位id', role_id bigint null comment '角色id', - dept_id bigint null comment '部门ID', username varchar(64) not null comment '用户账号', nickname varchar(32) not null comment '用户昵称', user_type smallint default 0 null comment '用户类型(00系统用户)', @@ -180,5 +139,3 @@ create table sys_user remark varchar(512) null comment '备注', deleted tinyint default 0 not null comment '删除标志(0代表存在 1代表删除)' ); - -CREATE ALIAS FIND_IN_SET FOR "com.agileboot.infrastructure.mybatisplus.MySqlFunction.findInSet"; diff --git a/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_data.sql b/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_data.sql index 92b4486..22fdc95 100644 --- a/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_data.sql +++ b/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_data.sql @@ -7,16 +7,6 @@ INSERT INTO app.sys_config (config_id, config_name, config_key, config_options, INSERT INTO app.sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', '["true","false"]', 'true', false, null, 1, '2022-10-05 22:18:57', '2022-05-21 08:30:55', '是否开启注册用户功能(true开启,false关闭)', 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (1, 0, '0', 'AgileBoot科技', 0, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (2, 1, '0,1', '深圳总公司', 1, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (3, 1, '0,1', '长沙分公司', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, 2, '0,1,2', '研发部门', 1, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (5, 2, '0,1,2', '市场部门', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 0, null, '2022-05-21 08:30:54', 1, '2023-07-20 22:46:41', 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (6, 2, '0,1,2', '测试部门', 3, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (7, 2, '0,1,2', '财务部门', 4, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (8, 2, '0,1,2', '运维部门', 5, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (9, 3, '0,1,3', '市场部!', 1, null, 'valarchie!!', '15888188888', 'valarc1hie@163.com', 0, null, '2022-05-21 08:30:54', 1, '2023-07-20 22:33:31', 0); -INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (10, 3, '0,1,3', '财务部门', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 0, null, '2022-05-21 08:30:54', null, null, 0); INSERT INTO app.sys_login_info (info_id, username, ip_address, login_location, browser, operation_system, status, msg, login_time, deleted) VALUES (415, 'admin', '127.0.0.1', '内网IP', 'Chrome 11', 'Mac OS X', 1, '登录成功', '2023-06-29 22:49:37', 0); @@ -31,8 +21,6 @@ INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (5, '用户管理', 1, 'SystemUser', 1, '/system/user/index', false, 'system:user:list', '{"title":"用户管理","icon":"ep:user-filled","showParent":true}', 1, '用户管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:13', 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (6, '角色管理', 1, 'SystemRole', 1, '/system/role/index', false, 'system:role:list', '{"title":"角色管理","icon":"ep:user","showParent":true}', 1, '角色管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:23', 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (7, '菜单管理', 1, 'MenuManagement', 1, '/system/menu/index', false, 'system:menu:list', '{"title":"菜单管理","icon":"ep:menu","showParent":true}', 1, '菜单管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:41', 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (8, '部门管理', 1, 'Department', 1, '/system/dept/index', false, 'system:dept:list', '{"title":"部门管理","icon":"fa-solid:code-branch","showParent":true}', 1, '部门管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:35', 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (9, '岗位管理', 1, 'Post', 1, '/system/post/index', false, 'system:post:list', '{"title":"岗位管理","icon":"ep:postcard","showParent":true}', 1, '岗位管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:11', 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (10, '参数设置', 1, 'Config', 1, '/system/config/index', false, 'system:config:list', '{"title":"参数设置","icon":"ep:setting","showParent":true}', 1, '参数设置菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:03', 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (11, '通知公告', 1, 'SystemNotice', 1, '/system/notice/index', false, 'system:notice:list', '{"title":"通知公告","icon":"ep:notification","showParent":true}', 1, '通知公告菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:56', 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (12, '日志管理', 1, 'LogManagement', 1, '/system/logd', false, '', '{"title":"日志管理","icon":"ep:document","showParent":true}', 1, '日志管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:47', 0); @@ -59,15 +47,6 @@ INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (33, '菜单新增', 0, ' ', 7, '', true, 'system:menu:add', '{"title":"菜单新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (34, '菜单修改', 0, ' ', 7, '', true, 'system:menu:edit', '{"title":"菜单修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (35, '菜单删除', 0, ' ', 7, '', true, 'system:menu:remove', '{"title":"菜单删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (36, '部门查询', 0, ' ', 8, '', true, 'system:dept:query', '{"title":"部门查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (37, '部门新增', 0, ' ', 8, '', true, 'system:dept:add', '{"title":"部门新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (38, '部门修改', 0, ' ', 8, '', true, 'system:dept:edit', '{"title":"部门修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (39, '部门删除', 0, ' ', 8, '', true, 'system:dept:remove', '{"title":"部门删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (40, '岗位查询', 0, ' ', 9, '', true, 'system:post:query', '{"title":"岗位查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (41, '岗位新增', 0, ' ', 9, '', true, 'system:post:add', '{"title":"岗位新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (42, '岗位修改', 0, ' ', 9, '', true, 'system:post:edit', '{"title":"岗位修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (43, '岗位删除', 0, ' ', 9, '', true, 'system:post:remove', '{"title":"岗位删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (44, '岗位导出', 0, ' ', 9, '', true, 'system:post:export', '{"title":"岗位导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (45, '参数查询', 0, ' ', 10, '', true, 'system:config:query', '{"title":"参数查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (46, '参数新增', 0, ' ', 10, '', true, 'system:config:add', '{"title":"参数新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (47, '参数修改', 0, ' ', 10, '', true, 'system:config:edit', '{"title":"参数修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); @@ -89,6 +68,13 @@ INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (63, 'AgileBoot Github地址', 4, 'https://github.com/valarchie/AgileBoot-Back-End', 0, '/external', false, '', '{"title":"AgileBoot Github地址","icon":"fa-solid:external-link-alt","showParent":true,"rank":9}', 1, 'Agileboot github地址', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:12:13', 0); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (64, '首页', 2, '', 0, '/global', false, '121212', '{"title":"首页","showParent":true,"rank":3}', 1, '', 1, '2023-07-24 22:36:03', 1, '2023-07-24 22:38:37', 1); INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (65, '个人中心', 1, 'PersonalCenter', 2053, '/system/user/profile', false, '434sdf', '{"title":"个人中心","showParent":true,"rank":3}', 1, '', 1, '2023-07-24 22:36:55', null, null, 1); +INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3000, '合作管理', 2, '', 0, '/collaboration', false, '', '{"title":"合作管理","icon":"ep:connection","showParent":true,"rank":4}', 1, '合作管理目录', 0, now(), null, null, 0); +INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3001, '合作记录', 1, 'CollaborationRecord', 3000, '/collaboration/record/index', false, 'collaboration:record:list', '{"title":"合作记录","icon":"ep:notebook","showParent":true}', 1, '合作记录菜单', 0, now(), null, null, 0); +INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3002, '月度统计', 1, 'CollaborationStatistics', 3000, '/collaboration/statistics/index', false, 'collaboration:record:statistics', '{"title":"月度统计","icon":"ep:data-analysis","showParent":true}', 1, '月度统计菜单', 0, now(), null, null, 0); +INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3003, '合作查询', 0, ' ', 3001, '', true, 'collaboration:record:query', '{"title":"合作查询"}', 1, '', 0, now(), null, null, 0); +INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3004, '合作新增', 0, ' ', 3001, '', true, 'collaboration:record:add', '{"title":"合作新增"}', 1, '', 0, now(), null, null, 0); +INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3005, '合作修改', 0, ' ', 3001, '', true, 'collaboration:record:edit', '{"title":"合作修改"}', 1, '', 0, now(), null, null, 0); +INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3006, '合作删除', 0, ' ', 3001, '', true, 'collaboration:record:remove', '{"title":"合作删除"}', 1, '', 0, now(), null, null, 0); @@ -97,99 +83,37 @@ INSERT INTO app.sys_notice (notice_id, notice_title, notice_type, notice_conten -INSERT INTO app.sys_operation_log (operation_id, business_type, request_method, request_module, request_url, called_method, operator_type, user_id, username, operator_ip, operator_location, dept_id, dept_name, operation_param, operation_result, status, error_stack, operation_time, deleted) VALUES (561, 1, 2, '菜单管理', '/system/menus', 'it.upos.builder.admin.controller.system.SysMenuController.add()', 1, 0, 'admin', '127.0.0.1', '内网IP', 0, null, '{"menuName":"","permission":"","parentId":2035,"path":"","isButton":false,"routerName":"","meta":{"showParent":true,"rank":0},"status":1},', '', 1, '', '2023-07-22 17:06:57', 0); -INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (1, 'ceo', '董事长', 1, 1, '', null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (2, 'se', '项目经理', 2, 1, '', null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3, 'hr', '人力资源', 3, 1, '', null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, 'user', '普通员工', 5, 0, '', null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, '超级管理员', 'admin', 1, 1, '', 1, null, '2022-05-21 08:30:54', null, null, '超级管理员', 0); -INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, '普通角色', 'common', 3, 2, '', 1, null, '2022-05-21 08:30:54', null, null, '普通角色', 0); -INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, '闲置角色', 'unused', 4, 2, '', 0, null, '2022-05-21 08:30:54', null, null, '未使用的角色', 0); +INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, '超级管理员', 'admin', 1, 1, 1, null, '2022-05-21 08:30:54', null, null, '超级管理员', 0); +INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, '普通用户', 'common', 3, 5, 1, null, '2022-05-21 08:30:54', null, null, '自助注册用户默认角色,默认允许使用合作管理', 0); +INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, '闲置角色', 'unused', 4, 5, 0, null, '2022-05-21 08:30:54', null, null, '未使用的角色', 0); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 1); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 2); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 4); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 5); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 6); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 7); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 8); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 9); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 10); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 11); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 12); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 13); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 14); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 15); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 16); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 17); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 18); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 19); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 20); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 21); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 22); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 23); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 24); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 25); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 26); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 27); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 28); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 29); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 30); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 31); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 32); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 33); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 34); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 35); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 36); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 37); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 38); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 39); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 40); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 41); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 42); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 43); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 44); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 45); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 46); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 47); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 48); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 49); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 50); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 51); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 52); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 53); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 54); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 55); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 56); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 57); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 58); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 59); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 60); -INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 61); +INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3000); +INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3001); +INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3002); +INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3003); +INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3004); +INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3005); +INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3006); INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (3, 1); INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (111, 1); -INSERT INTO app.sys_user (user_id, post_id, role_id, dept_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, 1, 1, 4, 'admin', 'valarchie1', 0, 'agileboot@163.com', '15888888883', 0, '/profile/avatar/20230725164110_blob_6b7a989b1cdd4dd396665d2cfd2addc5.png', '$2a$10$o55UFZAtyWnDpRV6dvQe8.c/MjlFacC49ASj2usNXm9BY74SYI/uG', 1, '127.0.0.1', '2023-08-14 23:07:03', true, null, '2022-05-21 08:30:54', 1, '2023-08-14 23:07:03', '管理员', 0); -INSERT INTO app.sys_user (user_id, post_id, role_id, dept_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, 2, 2, 5, 'ag1', 'valarchie2', 0, 'agileboot1@qq.com', '15666666666', 1, '/profile/avatar/20230725114818_avatar_b5bf400732bb43369b4df58802049b22.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 1, '127.0.0.1', '2022-05-21 08:30:54', false, null, '2022-05-21 08:30:54', null, null, '测试员1', 0); -INSERT INTO app.sys_user (user_id, post_id, role_id, dept_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, 2, 0, 5, 'ag2', 'valarchie3', 0, 'agileboot2@qq.com', '15666666667', 1, '/profile/avatar/20230725114818_avatar_b5bf400732bb43369b4df58802049b22.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 1, '127.0.0.1', '2022-05-21 08:30:54', false, null, '2022-05-21 08:30:54', null, null, '测试员2', 0); +INSERT INTO app.sys_user (user_id, role_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, 1, 'admin', 'valarchie1', 0, 'agileboot@163.com', '15888888883', 0, '/profile/avatar/20230725164110_blob_6b7a989b1cdd4dd396665d2cfd2addc5.png', '$2a$10$o55UFZAtyWnDpRV6dvQe8.c/MjlFacC49ASj2usNXm9BY74SYI/uG', 1, '127.0.0.1', '2023-08-14 23:07:03', true, null, '2022-05-21 08:30:54', 1, '2023-08-14 23:07:03', '管理员', 0); +INSERT INTO app.sys_user (user_id, role_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, 2, 'ag1', 'valarchie2', 0, 'agileboot1@qq.com', '15666666666', 1, '/profile/avatar/20230725114818_avatar_b5bf400732bb43369b4df58802049b22.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 1, '127.0.0.1', '2022-05-21 08:30:54', false, null, '2022-05-21 08:30:54', null, null, '测试员1', 0); +INSERT INTO app.sys_user (user_id, role_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, 0, 'ag2', 'valarchie3', 0, 'agileboot2@qq.com', '15666666667', 1, '/profile/avatar/20230725114818_avatar_b5bf400732bb43369b4df58802049b22.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 1, '127.0.0.1', '2022-05-21 08:30:54', false, null, '2022-05-21 08:30:54', null, null, '测试员2', 0); -- 序列更新 select setval('app.sys_config_config_id_seq',COALESCE(max(config_id),1)) from app.sys_config; -select setval('app.sys_dept_dept_id_seq',COALESCE(max(dept_id),1)) from app.sys_dept; select setval('app.sys_login_info_info_id_seq',COALESCE(max(info_id),1)) from app.sys_login_info; select setval('app.sys_menu_menu_id_seq',COALESCE(max(menu_id),1)) from app.sys_menu; select setval('app.sys_notice_notice_id_seq',COALESCE(max(notice_id),1)) from app.sys_notice; -select setval('app.sys_operation_log_operation_id_seq',COALESCE(max(operation_id),1)) from app.sys_operation_log; -select setval('app.sys_post_post_id_seq',COALESCE(max(post_id),1)) from app.sys_post; select setval('app.sys_role_role_id_seq',COALESCE(max(role_id),1)) from app.sys_role; -select setval('app.sys_user_user_id_seq',COALESCE(max(user_id),1)) from app.sys_user; \ No newline at end of file +select setval('app.sys_user_user_id_seq',COALESCE(max(user_id),1)) from app.sys_user; diff --git a/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_schema.sql b/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_schema.sql index bfc9258..cacac18 100644 --- a/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_schema.sql +++ b/backend/agileboot-infrastructure/src/main/resources/pgsql/agileboot_schema.sql @@ -14,25 +14,6 @@ CREATE TABLE app.sys_config ( deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除 ); --- 创建表 sys_dept 部门表 -CREATE TABLE app.sys_dept ( - dept_id serial8 PRIMARY KEY NOT NULL, -- 部门id - parent_id int8 NOT NULL DEFAULT 0, -- 父部门id - ancestors TEXT NOT NULL, -- 祖级列表 - dept_name VARCHAR(64) NOT NULL DEFAULT '', -- 部门名称 - order_num INT NOT NULL DEFAULT 0, -- 显示顺序 - leader_id int8, -- 负责人 - leader_name VARCHAR(64), -- 负责人姓名 - phone VARCHAR(16), -- 联系电话 - email VARCHAR(128), -- 邮箱 - status SMALLINT NOT NULL DEFAULT 0, -- 部门状态(0停用 1启用) - creator_id int8, -- 创建者ID - create_time TIMESTAMPTZ, -- 创建时间 - updater_id int8, -- 更新者ID - update_time TIMESTAMPTZ, -- 更新时间 - deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除 -); - -- 创建表 sys_login_info 系统访问记录 CREATE TABLE app.sys_login_info ( info_id serial8 PRIMARY KEY NOT NULL, -- 访问ID @@ -76,8 +57,6 @@ CREATE TABLE app.sys_operation_log ( username VARCHAR(32), -- 操作人员 operator_ip VARCHAR(128), -- 操作人员ip operator_location VARCHAR(256), -- 操作地点 - dept_id int8, -- 部门ID - dept_name VARCHAR(64), -- 部门名称 operation_param VARCHAR(2048), -- 请求参数 operation_result VARCHAR(2048), -- 返回参数 status int2 NOT NULL DEFAULT 1, -- 操作状态(1正常 0异常) @@ -86,22 +65,6 @@ CREATE TABLE app.sys_operation_log ( deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除 ); --- 创建表 sys_post 岗位信息表 -CREATE TABLE app.sys_post ( - post_id serial8 PRIMARY KEY NOT NULL, -- 岗位ID - post_code VARCHAR(64) NOT NULL, -- 岗位编码 - post_name VARCHAR(64) NOT NULL, -- 岗位名称 - post_sort INT NOT NULL, -- 显示顺序 - status int2 NOT NULL, -- 状态(1正常 0停用) - remark VARCHAR(512), -- 备注 - creator_id int8, -- 创建者ID - create_time TIMESTAMPTZ, -- 创建时间 - updater_id int8, -- 更新者ID - update_time TIMESTAMPTZ, -- 更新时间 - deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除 -); - - -- 创建表 sys_menu 菜单权限表 CREATE TABLE app.sys_menu ( menu_id serial8 PRIMARY KEY NOT NULL, -- 菜单ID @@ -128,8 +91,7 @@ CREATE TABLE app.sys_role ( role_name VARCHAR(32) NOT NULL, -- 角色名称 role_key VARCHAR(128) NOT NULL, -- 角色权限字符串 role_sort INT NOT NULL, -- 显示顺序 - data_scope int2, -- 数据范围 - dept_id_set VARCHAR(1024) DEFAULT '', -- 角色所拥有的部门数据权限 + data_scope int2, -- 数据范围(1:全部数据权限 5: 本人权限) status int2 NOT NULL, -- 角色状态(1正常 0停用) creator_id int8, -- 创建者ID create_time TIMESTAMPTZ, -- 创建时间 @@ -150,9 +112,7 @@ CREATE TABLE app.sys_role_menu ( -- 创建表 sys_user 用户信息表 CREATE TABLE app.sys_user ( user_id serial8 PRIMARY KEY NOT NULL, -- 用户ID - post_id int8, -- 职位id role_id int8, -- 角色id - dept_id int8, -- 部门ID username VARCHAR(64) NOT NULL, -- 用户账号 nickname VARCHAR(32) NOT NULL, -- 用户昵称 user_type int2 DEFAULT 0, -- 用户类型(00系统用户) diff --git a/backend/agileboot-infrastructure/src/test/java/com/agileboot/infrastructure/mybatisplus/MySqlFunctionTest.java b/backend/agileboot-infrastructure/src/test/java/com/agileboot/infrastructure/mybatisplus/MySqlFunctionTest.java deleted file mode 100644 index dc817f6..0000000 --- a/backend/agileboot-infrastructure/src/test/java/com/agileboot/infrastructure/mybatisplus/MySqlFunctionTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.agileboot.infrastructure.mybatisplus; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -class MySqlFunctionTest { - - @Test - void find_in_set() { - String searchStr = ",2,4,5,9"; - - Assertions.assertTrue(MySqlFunction.findInSet("2", searchStr)); - Assertions.assertTrue(MySqlFunction.findInSet("5", searchStr)); - Assertions.assertTrue(MySqlFunction.findInSet("9", searchStr)); - } - -} diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml deleted file mode 100644 index 9268e7b..0000000 --- a/backend/docker-compose.yml +++ /dev/null @@ -1,38 +0,0 @@ -services: - mysql: - image: mysql:8.0 - container_name: todo-mysql-server - restart: always - command: - - --character-set-server=utf8mb4 - - --collation-server=utf8mb4_unicode_ci - environment: - MYSQL_ROOT_PASSWORD: root123 - MYSQL_DATABASE: todo_agileboot_pure - ports: - - "33061:3306" - volumes: - - todo_mysql_data:/var/lib/mysql - - ./sql/agileboot.sql:/docker-entrypoint-initdb.d/01-agileboot.sql:ro - networks: - - todo-db-network - - redis: - image: redis:7.2-alpine - container_name: todo-redis-server - restart: always - command: redis-server --requirepass redis123 - ports: - - "63791:6379" - volumes: - - todo_redis_data:/data - networks: - - todo-db-network - -volumes: - todo_mysql_data: - todo_redis_data: - -networks: - todo-db-network: - driver: bridge diff --git a/backend/sql/agileboot.sql b/backend/sql/agileboot.sql index a53883b..336b949 100644 --- a/backend/sql/agileboot.sql +++ b/backend/sql/agileboot.sql @@ -29,38 +29,6 @@ INSERT INTO sys_config (config_id, config_name, config_key, config_options, con INSERT INTO sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (4, '账号自助-验证码开关', 'sys.account.captchaOnOff', '["true","false"]', 'false', 0, null, 1, '2023-07-20 14:39:36', '2022-05-21 08:30:55', '是否开启验证码功能(true开启,false关闭)', 0); INSERT INTO sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', '["true","false"]', 'true', 0, null, 1, '2022-10-05 22:18:57', '2022-05-21 08:30:55', '是否开启注册用户功能(true开启,false关闭)', 0); -create table sys_dept -( - dept_id bigint auto_increment comment '部门id' - primary key, - parent_id bigint default 0 not null comment '父部门id', - ancestors text not null comment '祖级列表', - dept_name varchar(64) default '' not null comment '部门名称', - order_num int default 0 not null comment '显示顺序', - leader_id bigint null, - leader_name varchar(64) null comment '负责人', - phone varchar(16) null comment '联系电话', - email varchar(128) null comment '邮箱', - status smallint default 0 not null comment '部门状态(0停用 1启用)', - creator_id bigint null comment '创建者ID', - create_time datetime null comment '创建时间', - updater_id bigint null comment '更新者ID', - update_time datetime null comment '更新时间', - deleted tinyint(1) default 0 not null comment '逻辑删除' -) - comment '部门表'; - -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (1, 0, '0', 'AgileBoot科技', 0, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (2, 1, '0,1', '深圳总公司', 1, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (3, 1, '0,1', '长沙分公司', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, 2, '0,1,2', '研发部门', 1, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (5, 2, '0,1,2', '市场部门', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 0, null, '2022-05-21 08:30:54', 1, '2023-07-20 22:46:41', 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (6, 2, '0,1,2', '测试部门', 3, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (7, 2, '0,1,2', '财务部门', 4, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (8, 2, '0,1,2', '运维部门', 5, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (9, 3, '0,1,3', '市场部!', 1, null, 'valarchie!!', '15888188888', 'valarc1hie@163.com', 0, null, '2022-05-21 08:30:54', 1, '2023-07-20 22:33:31', 0); -INSERT INTO sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (10, 3, '0,1,3', '财务部门', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 0, null, '2022-05-21 08:30:54', null, null, 0); - create table sys_login_info ( info_id bigint auto_increment comment '访问ID' @@ -109,8 +77,6 @@ INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, pa INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, '用户管理', 1, 'SystemUser', 1, '/system/user/index', 0, 'system:user:list', '{"title":"用户管理","icon":"ep:user-filled","showParent":true}', 1, '用户管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:13', 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (5, '角色管理', 1, 'SystemRole', 1, '/system/role/index', 0, 'system:role:list', '{"title":"角色管理","icon":"ep:user","showParent":true}', 1, '角色管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:23', 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (6, '菜单管理', 1, 'MenuManagement', 1, '/system/menu/index', 0, 'system:menu:list', '{"title":"菜单管理","icon":"ep:menu","showParent":true}', 1, '菜单管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:41', 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (7, '部门管理', 1, 'Department', 1, '/system/dept/index', 0, 'system:dept:list', '{"title":"部门管理","icon":"fa-solid:code-branch","showParent":true}', 1, '部门管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:35', 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (8, '岗位管理', 1, 'Post', 1, '/system/post/index', 0, 'system:post:list', '{"title":"岗位管理","icon":"ep:postcard","showParent":true}', 1, '岗位管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:11', 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (9, '参数设置', 1, 'Config', 1, '/system/config/index', 0, 'system:config:list', '{"title":"参数设置","icon":"ep:setting","showParent":true}', 1, '参数设置菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:03', 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (10, '通知公告', 1, 'SystemNotice', 1, '/system/notice/index', 0, 'system:notice:list', '{"title":"通知公告","icon":"ep:notification","showParent":true}', 1, '通知公告菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:56', 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (11, '日志管理', 1, 'LogManagement', 1, '/system/logd', 0, '', '{"title":"日志管理","icon":"ep:document","showParent":true}', 1, '日志管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:47', 0); @@ -137,15 +103,6 @@ INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, pa INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (32, '菜单新增', 0, ' ', 7, '', 1, 'system:menu:add', '{"title":"菜单新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (33, '菜单修改', 0, ' ', 7, '', 1, 'system:menu:edit', '{"title":"菜单修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (34, '菜单删除', 0, ' ', 7, '', 1, 'system:menu:remove', '{"title":"菜单删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (35, '部门查询', 0, ' ', 8, '', 1, 'system:dept:query', '{"title":"部门查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (36, '部门新增', 0, ' ', 8, '', 1, 'system:dept:add', '{"title":"部门新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (37, '部门修改', 0, ' ', 8, '', 1, 'system:dept:edit', '{"title":"部门修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (38, '部门删除', 0, ' ', 8, '', 1, 'system:dept:remove', '{"title":"部门删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (39, '岗位查询', 0, ' ', 9, '', 1, 'system:post:query', '{"title":"岗位查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (40, '岗位新增', 0, ' ', 9, '', 1, 'system:post:add', '{"title":"岗位新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (41, '岗位修改', 0, ' ', 9, '', 1, 'system:post:edit', '{"title":"岗位修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (42, '岗位删除', 0, ' ', 9, '', 1, 'system:post:remove', '{"title":"岗位删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (43, '岗位导出', 0, ' ', 9, '', 1, 'system:post:export', '{"title":"岗位导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (44, '参数查询', 0, ' ', 10, '', 1, 'system:config:query', '{"title":"参数查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (45, '参数新增', 0, ' ', 10, '', 1, 'system:config:add', '{"title":"参数新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); INSERT INTO sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (46, '参数修改', 0, ' ', 10, '', 1, 'system:config:edit', '{"title":"参数修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0); @@ -201,8 +158,6 @@ create table sys_operation_log username varchar(32) default '' null comment '操作人员', operator_ip varchar(128) default '' null comment '操作人员ip', operator_location varchar(256) default '' null comment '操作地点', - dept_id bigint default 0 null comment '部门ID', - dept_name varchar(64) null comment '部门名称', operation_param varchar(2048) default '' null comment '请求参数', operation_result varchar(2048) default '' null comment '返回参数', status smallint default 1 not null comment '操作状态(1正常 0异常)', @@ -212,29 +167,6 @@ create table sys_operation_log ) comment '操作日志记录'; -INSERT INTO sys_operation_log (operation_id, business_type, request_method, request_module, request_url, called_method, operator_type, user_id, username, operator_ip, operator_location, dept_id, dept_name, operation_param, operation_result, status, error_stack, operation_time, deleted) VALUES (561, 1, 2, '菜单管理', '/system/menus', 'com.agileboot.admin.controller.system.SysMenuController.add()', 1, 0, 'admin', '127.0.0.1', '内网IP', 0, null, '{"menuName":"","permission":"","parentId":2035,"path":"","isButton":false,"routerName":"","meta":{"showParent":true,"rank":0},"status":1},', '', 1, '', '2023-07-22 17:06:57', 0); - -create table sys_post -( - post_id bigint auto_increment comment '岗位ID' - primary key, - post_code varchar(64) not null comment '岗位编码', - post_name varchar(64) not null comment '岗位名称', - post_sort int not null comment '显示顺序', - status smallint not null comment '状态(1正常 0停用)', - remark varchar(512) null comment '备注', - creator_id bigint null, - create_time datetime null comment '创建时间', - updater_id bigint null, - update_time datetime null comment '更新时间', - deleted tinyint(1) default 0 not null comment '逻辑删除' -) - comment '岗位信息表'; - -INSERT INTO sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (1, 'ceo', '董事长', 1, 1, '', null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (2, 'se', '项目经理', 2, 1, '', null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3, 'hr', '人力资源', 3, 1, '', null, '2022-05-21 08:30:54', null, null, 0); -INSERT INTO sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, 'user', '普通员工', 5, 0, '', null, '2022-05-21 08:30:54', null, null, 0); create table sys_role ( @@ -243,8 +175,7 @@ create table sys_role role_name varchar(32) not null comment '角色名称', role_key varchar(128) not null comment '角色权限字符串', role_sort int not null comment '显示顺序', - data_scope smallint default 1 null comment '数据范围(1:全部数据权限 2:自定数据权限 3: 本部门数据权限 4: 本部门及以下数据权限 5: 本人权限)', - dept_id_set varchar(1024) default '' null comment '角色所拥有的部门数据权限', + data_scope smallint default 1 null comment '数据范围(1:全部数据权限 5: 本人权限)', status smallint not null comment '角色状态(1正常 0停用)', creator_id bigint null comment '创建者ID', create_time datetime null comment '创建时间', @@ -255,9 +186,9 @@ create table sys_role ) comment '角色信息表'; -INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, '超级管理员', 'admin', 1, 1, '', 1, null, '2022-05-21 08:30:54', null, null, '超级管理员', 0); -INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, '普通角色', 'common', 3, 2, '', 1, null, '2022-05-21 08:30:54', null, null, '普通角色', 0); -INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, '闲置角色', 'unused', 4, 2, '', 0, null, '2022-05-21 08:30:54', null, null, '未使用的角色', 0); +INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, '超级管理员', 'admin', 1, 1, 1, null, '2022-05-21 08:30:54', null, null, '超级管理员', 0); +INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, '普通用户', 'common', 3, 5, 1, null, '2022-05-21 08:30:54', null, null, '自助注册用户默认角色,默认允许使用合作管理', 0); +INSERT INTO sys_role (role_id, role_name, role_key, role_sort, data_scope, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, '闲置角色', 'unused', 4, 5, 0, null, '2022-05-21 08:30:54', null, null, '未使用的角色', 0); create table sys_role_menu ( @@ -267,67 +198,6 @@ create table sys_role_menu ) comment '角色和菜单关联表'; -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 1); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 2); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 3); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 4); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 5); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 6); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 7); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 8); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 9); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 10); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 11); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 12); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 13); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 14); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 15); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 16); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 17); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 18); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 19); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 20); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 21); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 22); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 23); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 24); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 25); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 26); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 27); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 28); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 29); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 30); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 31); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 32); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 33); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 34); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 35); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 36); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 37); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 38); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 39); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 40); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 41); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 42); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 43); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 44); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 45); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 46); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 47); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 48); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 49); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 50); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 51); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 52); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 53); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 54); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 55); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 56); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 57); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 58); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 59); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 60); -INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 61); INSERT INTO sys_role_menu (role_id, menu_id) VALUES (3, 1); INSERT INTO sys_role_menu (role_id, menu_id) VALUES (111, 1); @@ -335,9 +205,7 @@ create table sys_user ( user_id bigint auto_increment comment '用户ID' primary key, - post_id bigint null comment '职位id', role_id bigint null comment '角色id', - dept_id bigint null comment '部门ID', username varchar(64) not null comment '用户账号', nickname varchar(32) not null comment '用户昵称', user_type smallint default 0 null comment '用户类型(00系统用户)', @@ -355,11 +223,13 @@ create table sys_user updater_id bigint null comment '更新者ID', update_time datetime null comment '更新时间', remark varchar(512) null comment '备注', - deleted tinyint(1) default 0 not null comment '删除标志(0代表存在 1代表删除)' + deleted tinyint(1) default 0 not null comment '删除标志(0代表存在 1代表删除)', + constraint uk_sys_user_username + unique (username) ) comment '用户信息表'; -INSERT INTO sys_user (user_id, post_id, role_id, dept_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, 1, 1, 4, 'admin', 'valarchie1', 0, 'agileboot@163.com', '15888888883', 0, '/profile/avatar/20230725164110_blob_6b7a989b1cdd4dd396665d2cfd2addc5.png', '$2a$10$o55UFZAtyWnDpRV6dvQe8.c/MjlFacC49ASj2usNXm9BY74SYI/uG', 1, '127.0.0.1', '2023-08-14 23:07:03', 1, null, '2022-05-21 08:30:54', 1, '2023-08-14 23:07:03', '管理员', 0); +INSERT INTO sys_user (user_id, role_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, 1, 'admin', 'valarchie1', 0, 'agileboot@163.com', '15888888883', 0, '/profile/avatar/20230725164110_blob_6b7a989b1cdd4dd396665d2cfd2addc5.png', '$2a$10$o55UFZAtyWnDpRV6dvQe8.c/MjlFacC49ASj2usNXm9BY74SYI/uG', 1, '127.0.0.1', '2023-08-14 23:07:03', 1, null, '2022-05-21 08:30:54', 1, '2023-08-14 23:07:03', '管理员', 0); create table collaboration_record ( @@ -385,6 +255,7 @@ create table collaboration_record updater_id bigint null comment '更新者ID', update_time datetime null comment '更新时间', deleted tinyint(1) default 0 not null comment '逻辑删除', + index idx_collaboration_record_creator_id (creator_id), index idx_collaboration_record_platform (cooperation_platform), index idx_collaboration_record_deadline (deadline), index idx_collaboration_record_purchase_date (purchase_date) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5f25343 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,102 @@ +services: + mysql: + image: mysql:8.0 + container_name: todo-mysql-server + restart: always + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --default-authentication-plugin=mysql_native_password + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123} + MYSQL_DATABASE: ${MYSQL_DATABASE:-todo_agileboot_pure} + MYSQL_USER: ${MYSQL_APP_USERNAME:-todo_app} + MYSQL_PASSWORD: ${MYSQL_APP_PASSWORD:-todo_app123} + ports: + - "${MYSQL_PORT:-3306}:3306" + volumes: + - todo_mysql_data:/var/lib/mysql + - ./backend/sql/agileboot.sql:/docker-entrypoint-initdb.d/01-agileboot.sql:ro + healthcheck: + test: ["CMD-SHELL", "mysqladmin ping -h localhost -uroot -p$${MYSQL_ROOT_PASSWORD} --silent"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 30s + networks: + - todo-network + + redis: + image: redis:7.2-alpine + container_name: todo-redis-server + restart: always + command: redis-server --requirepass ${REDIS_PASSWORD:-redis123} + environment: + REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} + ports: + - "${REDIS_PORT:-6379}:6379" + volumes: + - todo_redis_data:/data + healthcheck: + test: ["CMD-SHELL", "redis-cli -a $${REDIS_PASSWORD} ping | grep PONG"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 10s + networks: + - todo-network + + app: + profiles: + - prod + build: + context: ./backend + dockerfile: Dockerfile + image: simple-todo-backend:latest + container_name: todo-backend + restart: always + depends_on: + mysql: + condition: service_healthy + redis: + condition: service_healthy + environment: + SPRING_PROFILES_ACTIVE: basic,prod + MYSQL_HOST: mysql + MYSQL_PORT: 3306 + MYSQL_DATABASE: ${MYSQL_DATABASE:-todo_agileboot_pure} + MYSQL_USERNAME: ${MYSQL_APP_USERNAME:-todo_app} + MYSQL_PASSWORD: ${MYSQL_APP_PASSWORD:-todo_app123} + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} + JAVA_OPTS: ${JAVA_OPTS:-} + ports: + - "${APP_PORT:-8080}:8080" + networks: + - todo-network + + web: + profiles: + - prod + build: + context: ./frontend + dockerfile: web/Dockerfile + image: simple-todo-web:latest + container_name: todo-web + restart: always + depends_on: + app: + condition: service_started + ports: + - "${WEB_PORT:-80}:80" + networks: + - todo-network + +volumes: + todo_mysql_data: + todo_redis_data: + +networks: + todo-network: + driver: bridge diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..69170ed --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,20 @@ +node_modules +*/node_modules +.pnpm-store + +app/dist +app/deploy_versions +app/.temp +app/.rn_temp +app/.swc + +web/dist +web/dist-ssr +web/report.html +web/.eslintcache +web/tests/**/coverage + +*.local +*.log +.DS_Store +.idea diff --git a/frontend/.env.example b/frontend/.env.example deleted file mode 100644 index 59a3469..0000000 --- a/frontend/.env.example +++ /dev/null @@ -1,15 +0,0 @@ -# Shared frontend env reference. Copy values into each app-specific .env file. - -# Web (Vite) -VITE_PORT=8848 -VITE_PUBLIC_PATH=./ -VITE_ROUTER_HISTORY="hash" -VITE_CDN=false -VITE_COMPRESSION="none" -VITE_HIDE_HOME=false -VITE_APP_BASE_API=/dev-api - -# App (Taro) -TARO_APP_ID= -TARO_APP_API_BASE= - diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..df47caf --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,52 @@ +# Frontend + +This workspace contains: + +- `web`: Vite + Vue 3 admin frontend. +- `app`: Taro + Vue 3 app frontend. + +## Environment Files + +Frontend environment variables are maintained in each app directory. + +### Web + +Web env files live in `frontend/web`: + +- `.env`: default Vite values. +- `.env.development`: local development values. +- `.env.production`: production build values. +- `.env.staging`: staging build values. + +Common variables: + +```env +VITE_PORT=8848 +VITE_PUBLIC_PATH=./ +VITE_ROUTER_HISTORY="hash" +VITE_CDN=false +VITE_COMPRESSION="none" +VITE_APP_BASE_API=/dev-api +``` + +For Docker Compose production deployment, `frontend/web/.env.production` uses +`VITE_APP_BASE_API=/prod-api`. The web container's Nginx config proxies +`/prod-api` to the backend container. + +### App + +App env files live in `frontend/app`: + +- `.env.development`: local development values. +- `.env.production`: production build values. +- `.env.test`: test build values. + +Common variables: + +```env +TARO_APP_ID= +TARO_APP_API_BASE= +``` + +When `TARO_APP_API_BASE` is empty, the app HTTP client falls back to +`http://localhost:8080`. diff --git a/frontend/app/config/index.ts b/frontend/app/config/index.ts index 28aab20..b27b191 100644 --- a/frontend/app/config/index.ts +++ b/frontend/app/config/index.ts @@ -1,10 +1,12 @@ import { defineConfig, type UserConfigExport } from '@tarojs/cli' +import path from 'path' import devConfig from './dev' import prodConfig from './prod' -// https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数 export default defineConfig<'vite'>(async merge => { + const themeVariablesPath = path.resolve(__dirname, '..', 'src/theme/variables.scss').replace(/\\/g, '/') + const baseConfig: UserConfigExport<'vite'> = { projectName: 'app', date: '2026-5-6', @@ -17,11 +19,17 @@ export default defineConfig<'vite'>(async merge => { }, sourceRoot: 'src', outputRoot: 'dist', + alias: { + '@': path.resolve(__dirname, '..', 'src') + }, plugins: [ - "@tarojs/plugin-generator" + '@tarojs/plugin-generator' ], defineConstants: { }, + sass: { + data: `@use "${themeVariablesPath}" as *;\n` + }, copy: { patterns: [ ], @@ -39,9 +47,9 @@ export default defineConfig<'vite'>(async merge => { } }, cssModules: { - enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true + enable: false, config: { - namingPattern: 'module', // 转换模式,取值为 global/module + namingPattern: 'module', generateScopedName: '[name]__[local]___[hash:base64:5]' } } @@ -62,9 +70,9 @@ export default defineConfig<'vite'>(async merge => { config: {} }, cssModules: { - enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true + enable: false, config: { - namingPattern: 'module', // 转换模式,取值为 global/module + namingPattern: 'module', generateScopedName: '[name]__[local]___[hash:base64:5]' } } @@ -74,17 +82,15 @@ export default defineConfig<'vite'>(async merge => { appName: 'taroDemo', postcss: { cssModules: { - enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true + enable: false } } } } - if (process.env.NODE_ENV === 'development') { - // 本地开发构建配置(不混淆压缩) return merge({}, baseConfig, devConfig) } - // 生产构建配置(默认开启压缩混淆等) + return merge({}, baseConfig, prodConfig) }) diff --git a/frontend/app/package.json b/frontend/app/package.json index 6e87dc4..95d8925 100644 --- a/frontend/app/package.json +++ b/frontend/app/package.json @@ -21,15 +21,15 @@ "build:qq": "taro build --type qq", "build:jd": "taro build --type jd", "build:harmony-hybrid": "taro build --type harmony-hybrid", - "dev:weapp": "pnpm build:weapp -- --watch", - "dev:swan": "pnpm build:swan -- --watch", - "dev:alipay": "pnpm build:alipay -- --watch", - "dev:tt": "pnpm build:tt -- --watch", - "dev:h5": "pnpm build:h5 -- --watch", - "dev:rn": "pnpm build:rn -- --watch", - "dev:qq": "pnpm build:qq -- --watch", - "dev:jd": "pnpm build:jd -- --watch", - "dev:harmony-hybrid": "pnpm build:harmony-hybrid -- --watch", + "dev:weapp": "pnpm build:weapp --watch", + "dev:swan": "pnpm build:swan --watch", + "dev:alipay": "pnpm build:alipay --watch", + "dev:tt": "pnpm build:tt --watch", + "dev:h5": "pnpm build:h5 --watch", + "dev:rn": "pnpm build:rn --watch", + "dev:qq": "pnpm build:qq --watch", + "dev:jd": "pnpm build:jd --watch", + "dev:harmony-hybrid": "pnpm build:harmony-hybrid --watch", "lint": "eslint --ignore-path ../.eslintignore \"{src,config}/**/*.{vue,js,ts,tsx}\" && pnpm --dir .. exec stylelint \"app/src/**/*.{vue,css,scss}\" --config ./stylelint.config.cjs --ignore-path ./.stylelintignore", "typecheck": "tsc --noEmit" }, @@ -40,39 +40,43 @@ "author": "", "dependencies": { "@babel/runtime": "^7.24.4", + "@qiun/ucharts": "2.5.0-20230101", "@tarojs/components": "4.2.0", "@tarojs/helper": "4.2.0", - "@tarojs/plugin-platform-weapp": "4.2.0", + "@tarojs/plugin-framework-vue3": "4.2.0", "@tarojs/plugin-platform-alipay": "4.2.0", - "@tarojs/plugin-platform-tt": "4.2.0", - "@tarojs/plugin-platform-swan": "4.2.0", - "@tarojs/plugin-platform-jd": "4.2.0", - "@tarojs/plugin-platform-qq": "4.2.0", "@tarojs/plugin-platform-h5": "4.2.0", "@tarojs/plugin-platform-harmony-hybrid": "4.2.0", + "@tarojs/plugin-platform-jd": "4.2.0", + "@tarojs/plugin-platform-qq": "4.2.0", + "@tarojs/plugin-platform-swan": "4.2.0", + "@tarojs/plugin-platform-tt": "4.2.0", + "@tarojs/plugin-platform-weapp": "4.2.0", "@tarojs/runtime": "4.2.0", "@tarojs/shared": "4.2.0", "@tarojs/taro": "4.2.0", - "@tarojs/plugin-framework-vue3": "4.2.0", - "vue": "^3.0.0" + "pinia": "^2.3.1", + "taro-ui-vue3": "1.0.0-alpha.21", + "vue": "^3.0.0", + "wxmp-rsa": "^2.1.0" }, "devDependencies": { - "@tarojs/plugin-generator": "4.2.0", "@babel/core": "^7.24.4", "@babel/plugin-transform-class-properties": "7.25.9", "@tarojs/cli": "4.2.0", + "@tarojs/plugin-generator": "4.2.0", "@tarojs/vite-runner": "4.2.0", - "babel-preset-taro": "4.2.0", - "eslint-config-taro": "4.2.0", - "eslint": "^8.57.0", - "terser": "^5.30.4", - "vite": "^4.2.0", + "@types/minimatch": "^5", "@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue-jsx": "^3.1.0", + "babel-preset-taro": "4.2.0", + "eslint": "^8.57.0", + "eslint-config-taro": "4.2.0", "eslint-plugin-vue": "^9.17.0", - "sass": "^1.75.0", - "typescript": "^5.4.5", "postcss": "^8.5.6", - "@types/minimatch": "^5" + "sass": "^1.75.0", + "terser": "^5.30.4", + "typescript": "^5.4.5", + "vite": "^4.2.0" } } diff --git a/frontend/app/project.config.json b/frontend/app/project.config.json index 0326e6d..a95a66e 100644 --- a/frontend/app/project.config.json +++ b/frontend/app/project.config.json @@ -4,7 +4,7 @@ "description": "simple app", "appid": "touristappid", "setting": { - "urlCheck": true, + "urlCheck": false, "es6": false, "enhance": false, "compileHotReLoad": false, diff --git a/frontend/app/src/api/auth.ts b/frontend/app/src/api/auth.ts new file mode 100644 index 0000000..18fdf9c --- /dev/null +++ b/frontend/app/src/api/auth.ts @@ -0,0 +1,41 @@ +import { request } from '@/utils/http' +import type { CaptchaDTO, ConfigDTO, CurrentLoginUserDTO, TokenDTO } from './types' + +export interface LoginCommand { + username: string + password: string + captchaCode?: string + captchaCodeKey?: string +} + +export interface RegisterCommand extends LoginCommand { + nickname?: string + confirmPassword: string + email?: string + phoneNumber?: string +} + +export function getConfigApi() { + return request({ method: 'GET', url: '/app/getConfig' }) +} + +export function getCaptchaApi() { + return request({ method: 'GET', url: '/app/captchaImage', showLoading: false }) +} + +export function loginApi(data: LoginCommand) { + return request({ method: 'POST', url: '/app/login', data }) +} + +export function registerApi(data: RegisterCommand) { + return request({ method: 'POST', url: '/app/register', data }) +} + +export function getLoginUserInfoApi() { + return request({ method: 'GET', url: '/app/getLoginUserInfo' }) +} + +export function logoutApi() { + return request({ method: 'POST', url: '/logout', showLoading: false }) +} + diff --git a/frontend/app/src/api/collaboration.ts b/frontend/app/src/api/collaboration.ts new file mode 100644 index 0000000..2931cc1 --- /dev/null +++ b/frontend/app/src/api/collaboration.ts @@ -0,0 +1,165 @@ +import { request, uploadFile } from '@/utils/http' +import type { PageDTO } from './types' + +export type SettlementStatusValue = 'NONE' | 'SETTLED' | 'UNSETTLED' | 'PARTIAL' +export type TaskStatusValue = 'COMPLETED' | 'INCOMPLETE' +export type CollaborationFileType = 'GOODS_IMAGE' | 'ATTACHMENT' + +export interface SettlementStatusDTO { + status: SettlementStatusValue + label: string +} + +export interface CollaborationRecordQuery { + pageNum?: number + pageSize?: number + brand?: string + goods?: string + cooperationPlatform?: string + settlementStatus?: SettlementStatusValue + taskStatus?: TaskStatusValue +} + +export interface CollaborationTaskCommand { + releaseDate?: string +} + +export interface CollaborationExpenditureCommand { + spendDate?: string + amount?: number + purpose?: string +} + +export interface CollaborationSettlementCommand { + settleDate?: string + method?: string + income?: number + purpose?: string +} + +export interface CollaborationFileCommand { + fileType: CollaborationFileType + url: string + fileName?: string + newFileName?: string + originalFilename?: string +} + +export interface AddCollaborationRecordCommand { + brand: string + goods: string + cooperationPlatform?: string + imageReturnNum: number + retainedMethod?: string + cooperatedMethod?: string + purchaseMethod?: string + purchasePrice?: number + purchaseDate?: string + purchasePlatform?: string + deadline?: string + remuneration?: number + completeDate?: string + requirements?: string + remark?: string + tasks: CollaborationTaskCommand[] + expenditures: CollaborationExpenditureCommand[] + settlements: CollaborationSettlementCommand[] + files: CollaborationFileCommand[] +} + +export interface UpdateCollaborationRecordCommand extends AddCollaborationRecordCommand { + recordId: number +} + +export interface CollaborationRecordDTO extends AddCollaborationRecordCommand { + recordId: number + tasksNum: number + completedTasksNum: number + purchaseSettlementStatus: SettlementStatusDTO + deliverySettlementStatus: SettlementStatusDTO + remunerationSettlementStatus: SettlementStatusDTO + createTime: string +} + +export interface CollaborationRecordDetailDTO extends CollaborationRecordDTO { + tasks: Array + expenditures: Array + settlements: Array + files: Array +} + +export interface CollaborationOptionDTO { + type: string + label: string + values: string[] +} + +export interface CollaborationMonthlyStatisticsDTO { + month: number + purchasePrice: number + expenditureAmount: number + settledRemuneration: number + settledTotal: number +} + +export interface UploadFileDTO { + url: string + fileName: string + newFileName: string + originalFilename: string +} + +export function getCollaborationRecordListApi(params: CollaborationRecordQuery) { + return request>({ + method: 'GET', + url: '/app/collaboration/record/list', + params + }) +} + +export function getCollaborationRecordInfoApi(recordId: number) { + return request({ + method: 'GET', + url: `/app/collaboration/record/${recordId}` + }) +} + +export function addCollaborationRecordApi(data: AddCollaborationRecordCommand) { + return request({ method: 'POST', url: '/app/collaboration/record', data }) +} + +export function updateCollaborationRecordApi(data: UpdateCollaborationRecordCommand) { + return request({ method: 'PUT', url: '/app/collaboration/record', data }) +} + +export function deleteCollaborationRecordApi(recordId: number) { + return request({ + method: 'DELETE', + url: '/app/collaboration/record', + params: { ids: recordId } + }) +} + +export function getCollaborationOptionsApi() { + return request({ + method: 'GET', + url: '/app/collaboration/record/options' + }) +} + +export function getCollaborationMonthlyStatisticsApi(year: number) { + return request({ + method: 'GET', + url: '/app/collaboration/record/monthly-statistics', + params: { year } + }) +} + +export function uploadCollaborationFileApi(filePath: string, fileName?: string) { + return uploadFile({ + url: '/file/upload', + filePath, + fileName + }) +} + diff --git a/frontend/app/src/api/profile.ts b/frontend/app/src/api/profile.ts new file mode 100644 index 0000000..e9552df --- /dev/null +++ b/frontend/app/src/api/profile.ts @@ -0,0 +1,32 @@ +import { request } from '@/utils/http' +import type { UserInfoDTO } from './types' + +export interface UserProfileDTO { + user: UserInfoDTO + roleName?: string +} + +export interface UpdateProfileCommand { + nickName?: string + phoneNumber?: string + email?: string + sex?: number +} + +export interface UpdatePasswordCommand { + newPassword: string + confirmPassword: string +} + +export function getProfileApi() { + return request({ method: 'GET', url: '/app/user/profile' }) +} + +export function updateProfileApi(data: UpdateProfileCommand) { + return request({ method: 'PUT', url: '/app/user/profile', data }) +} + +export function updatePasswordApi(data: UpdatePasswordCommand) { + return request({ method: 'PUT', url: '/app/user/profile/password', data }) +} + diff --git a/frontend/app/src/api/types.ts b/frontend/app/src/api/types.ts new file mode 100644 index 0000000..8877522 --- /dev/null +++ b/frontend/app/src/api/types.ts @@ -0,0 +1,52 @@ +export interface ResponseData { + code: number + msg: string + data: T +} + +export interface PageDTO { + rows: T[] + total: number +} + +export interface DictionaryData { + label: string + value: number + cssTag: string +} + +export interface ConfigDTO { + isCaptchaOn: boolean + isRegisterUserOn?: boolean + dictionary: Record +} + +export interface CaptchaDTO { + isCaptchaOn: boolean + captchaCodeKey?: string + captchaCodeImg?: string +} + +export interface UserInfoDTO { + avatar?: string + email?: string + nickname?: string + phoneNumber?: string + roleName?: string + sex?: number + status?: number + userId?: number + username?: string +} + +export interface CurrentLoginUserDTO { + userInfo: UserInfoDTO + roleKey: string + permissions: string[] +} + +export interface TokenDTO { + token: string + currentUser: CurrentLoginUserDTO +} + diff --git a/frontend/app/src/app.config.ts b/frontend/app/src/app.config.ts index 15c683b..34ce483 100644 --- a/frontend/app/src/app.config.ts +++ b/frontend/app/src/app.config.ts @@ -1,11 +1,43 @@ +import { themeTokens } from '@/theme/tokens' + export default defineAppConfig({ pages: [ - 'pages/index/index' + 'pages/login/index', + 'pages/collaboration/records/index', + 'pages/collaboration/statistics/index', + 'pages/profile/index', + 'pages/profile/info/index', + 'pages/profile/password/index', + 'pages/collaboration/detail/index', + 'pages/collaboration/form/index' ], window: { backgroundTextStyle: 'light', - navigationBarBackgroundColor: '#fff', - navigationBarTitleText: 'WeChat', - navigationBarTextStyle: 'black' + navigationBarBackgroundColor: themeTokens.color.page, + navigationBarTitleText: '合作管理', + navigationBarTextStyle: 'black', + navigationStyle: 'custom' + }, + tabBar: { + custom: true, + color: themeTokens.color.textSecondary, + selectedColor: themeTokens.color.primary, + backgroundColor: themeTokens.color.page, + borderStyle: 'black', + list: [ + { + pagePath: 'pages/collaboration/records/index', + text: '合作记录' + }, + { + pagePath: 'pages/collaboration/statistics/index', + text: '月度统计' + }, + { + pagePath: 'pages/profile/index', + text: '我的' + } + ] } }) + diff --git a/frontend/app/src/app.scss b/frontend/app/src/app.scss index e69de29..a380b22 100644 --- a/frontend/app/src/app.scss +++ b/frontend/app/src/app.scss @@ -0,0 +1,197 @@ +@import "./theme/variables"; +@import "taro-ui-vue3/dist/style/index.scss"; + +page { + min-height: 100%; + color: $text-primary; + background: $bg-page; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} + +html, +body, +#app { + min-height: 100%; + color: $text-primary; + background: $bg-page; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} + +view, +text, +input, +textarea, +button { + box-sizing: border-box; +} + +.at-input { + margin-left: 0; +} + +.at-input__input { + padding-right: 0; +} + +.at-list__item { + padding-right: 0; + padding-left: 0; +} + +.at-list__item::after { + left: 0; +} + +.page { + box-sizing: border-box; + padding: $space-xl $space-xl $page-bottom-space; +} + +.panel { + padding: $space-xl; + margin-bottom: $space-lg; + background: $bg-page !important; + border: 1px solid $border-color; + border-radius: $radius-md; +} + +.section-title { + margin-bottom: $space-md; + font-size: $font-title; + font-weight: 600; + color: $text-primary; +} + +.muted { + color: $text-secondary; +} + +.row { + display: flex; + gap: 16px; + align-items: center; +} + +.space-between { + display: flex; + align-items: center; + justify-content: space-between; +} + +.field { + margin-bottom: $space-md; +} + +.label { + display: block; + margin-bottom: $space-xs; + font-size: $font-md; + color: $text-regular; +} + +.input, +.textarea, +.picker { + box-sizing: border-box; + display: block; + width: 100%; + min-height: $control-height; + padding: $space-sm $space-lg; + font-size: $font-lg; + line-height: $line-height-control; + color: $text-primary; + background: $bg-page !important; + border: 1px solid $border-color-strong; + border-radius: $radius-md; +} + +.textarea { + min-height: $control-height; +} + +.button-row { + display: flex; + gap: 16px; + margin-top: $space-lg; +} + +.btn, +.btn.at-button { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + flex: 1; + width: 100%; + height: $control-height; + font-size: $font-lg; + line-height: $control-height; + color: $text-primary; + background: $bg-soft; + border: 0; + border-radius: $radius-md; +} + +.btn-primary, +.btn-primary.at-button { + color: $color-white; + background: $color-primary; + border-color: transparent; +} + +.btn-danger, +.btn-danger.at-button { + color: $color-white; + background: $color-danger; + border-color: transparent; +} + +.btn-plain, +.btn-plain.at-button { + color: $color-primary; + background: $color-primary-light; + border-color: transparent; +} + +.tag { + display: inline-flex; + padding: $space-xxs $space-sm; + font-size: $font-sm; + color: $color-primary; + background: $color-primary-light; + border-radius: $radius-sm; +} + +.tag.at-tag { + border: 0; +} + +.record-meta-tag.at-tag { + color: $text-primary; + background: $bg-soft; +} + +.settlement-tag-danger.at-tag, +.settlement-tag-danger { + color: $color-danger; + background: $color-danger-light; +} + +.settlement-tag-warning.at-tag, +.settlement-tag-warning { + color: $color-warning; + background: $color-warning-light; +} + +.settlement-tag-success.at-tag, +.settlement-tag-success { + color: $color-success; + background: $color-success-light; +} + +.empty { + padding: 80px 0; + font-size: $font-xl; + color: $text-placeholder; + text-align: center; +} diff --git a/frontend/app/src/app.ts b/frontend/app/src/app.ts index eb8671a..b021273 100644 --- a/frontend/app/src/app.ts +++ b/frontend/app/src/app.ts @@ -1,15 +1,18 @@ - + import { createApp } from 'vue' +import { createPinia } from 'pinia' +import { createUI } from 'taro-ui-vue3' import './app.scss' - - const App = createApp({ onShow () { - console.log('App onShow.') }, // 入口组件不需要实现 render 方法,即使实现了也会被 taro 所覆盖 }) +App.use(createPinia()) +App.use(createUI()) + export default App + diff --git a/frontend/app/src/components/AppNavbar.vue b/frontend/app/src/components/AppNavbar.vue new file mode 100644 index 0000000..9e45e1d --- /dev/null +++ b/frontend/app/src/components/AppNavbar.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/frontend/app/src/components/ThemePicker.vue b/frontend/app/src/components/ThemePicker.vue new file mode 100644 index 0000000..cfdbd87 --- /dev/null +++ b/frontend/app/src/components/ThemePicker.vue @@ -0,0 +1,352 @@ + + + + + diff --git a/frontend/app/src/components/themePickerLock.ts b/frontend/app/src/components/themePickerLock.ts new file mode 100644 index 0000000..0c45639 --- /dev/null +++ b/frontend/app/src/components/themePickerLock.ts @@ -0,0 +1,25 @@ +import Taro, { usePageScroll } from '@tarojs/taro' +import { computed, ref, watch } from 'vue' + +const lockedPickerCount = ref(0) +const lockedRootBaseStyle = 'position: fixed; right: 0; left: 0; width: 100%; height: 100vh; overflow: hidden;' +const isThemePickerPageLocked = computed(() => lockedPickerCount.value > 0) + +export function lockThemePickerPageScroll() { + lockedPickerCount.value += 1 +} + +export function unlockThemePickerPageScroll() { + lockedPickerCount.value = Math.max(lockedPickerCount.value - 1, 0) +} + +export function useThemePickerLockedRootStyle() { + const scrollTop = ref(0) + usePageScroll(event => { + if (!isThemePickerPageLocked.value) scrollTop.value = event.scrollTop + }) + watch(isThemePickerPageLocked, isLocked => { + if (!isLocked) Taro.pageScrollTo({ scrollTop: scrollTop.value, duration: 0 }) + }, { flush: 'post' }) + return computed(() => isThemePickerPageLocked.value ? `${lockedRootBaseStyle} top: -${scrollTop.value}px;` : '') +} diff --git a/frontend/app/src/custom-tab-bar/index.vue b/frontend/app/src/custom-tab-bar/index.vue new file mode 100644 index 0000000..77e6eb4 --- /dev/null +++ b/frontend/app/src/custom-tab-bar/index.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/frontend/app/src/pages/collaboration/detail/index.config.ts b/frontend/app/src/pages/collaboration/detail/index.config.ts new file mode 100644 index 0000000..196f119 --- /dev/null +++ b/frontend/app/src/pages/collaboration/detail/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '记录详情' +}) + diff --git a/frontend/app/src/pages/collaboration/detail/index.vue b/frontend/app/src/pages/collaboration/detail/index.vue new file mode 100644 index 0000000..45f3b63 --- /dev/null +++ b/frontend/app/src/pages/collaboration/detail/index.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/frontend/app/src/pages/collaboration/form/components/PickableFormItem.vue b/frontend/app/src/pages/collaboration/form/components/PickableFormItem.vue new file mode 100644 index 0000000..84aa03d --- /dev/null +++ b/frontend/app/src/pages/collaboration/form/components/PickableFormItem.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/frontend/app/src/pages/collaboration/form/index.config.ts b/frontend/app/src/pages/collaboration/form/index.config.ts new file mode 100644 index 0000000..befebd7 --- /dev/null +++ b/frontend/app/src/pages/collaboration/form/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '编辑合作记录' +}) + diff --git a/frontend/app/src/pages/collaboration/form/index.vue b/frontend/app/src/pages/collaboration/form/index.vue new file mode 100644 index 0000000..dd07077 --- /dev/null +++ b/frontend/app/src/pages/collaboration/form/index.vue @@ -0,0 +1,1112 @@ + + + + + diff --git a/frontend/app/src/pages/collaboration/records/index.config.ts b/frontend/app/src/pages/collaboration/records/index.config.ts new file mode 100644 index 0000000..5321fb5 --- /dev/null +++ b/frontend/app/src/pages/collaboration/records/index.config.ts @@ -0,0 +1,5 @@ +export default definePageConfig({ + navigationBarTitleText: '合作记录', + enablePullDownRefresh: true +}) + diff --git a/frontend/app/src/pages/collaboration/records/index.vue b/frontend/app/src/pages/collaboration/records/index.vue new file mode 100644 index 0000000..5cb29fa --- /dev/null +++ b/frontend/app/src/pages/collaboration/records/index.vue @@ -0,0 +1,620 @@ + + + + + diff --git a/frontend/app/src/pages/collaboration/statistics/index.config.ts b/frontend/app/src/pages/collaboration/statistics/index.config.ts new file mode 100644 index 0000000..ec5bc54 --- /dev/null +++ b/frontend/app/src/pages/collaboration/statistics/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '月度统计' +}) + diff --git a/frontend/app/src/pages/collaboration/statistics/index.vue b/frontend/app/src/pages/collaboration/statistics/index.vue new file mode 100644 index 0000000..b7f5e39 --- /dev/null +++ b/frontend/app/src/pages/collaboration/statistics/index.vue @@ -0,0 +1,380 @@ + + + + + diff --git a/frontend/app/src/pages/index/index.config.ts b/frontend/app/src/pages/index/index.config.ts deleted file mode 100644 index 12abc5f..0000000 --- a/frontend/app/src/pages/index/index.config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default definePageConfig({ - navigationBarTitleText: '首页' -}) diff --git a/frontend/app/src/pages/index/index.scss b/frontend/app/src/pages/index/index.scss deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/app/src/pages/index/index.vue b/frontend/app/src/pages/index/index.vue deleted file mode 100644 index 0be9787..0000000 --- a/frontend/app/src/pages/index/index.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/frontend/app/src/pages/login/index.config.ts b/frontend/app/src/pages/login/index.config.ts new file mode 100644 index 0000000..447e1ae --- /dev/null +++ b/frontend/app/src/pages/login/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '登录注册' +}) + diff --git a/frontend/app/src/pages/login/index.vue b/frontend/app/src/pages/login/index.vue new file mode 100644 index 0000000..3fcc905 --- /dev/null +++ b/frontend/app/src/pages/login/index.vue @@ -0,0 +1,318 @@ + + + + + diff --git a/frontend/app/src/pages/profile/index.config.ts b/frontend/app/src/pages/profile/index.config.ts new file mode 100644 index 0000000..e57b80d --- /dev/null +++ b/frontend/app/src/pages/profile/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '我的' +}) + diff --git a/frontend/app/src/pages/profile/index.vue b/frontend/app/src/pages/profile/index.vue new file mode 100644 index 0000000..099c502 --- /dev/null +++ b/frontend/app/src/pages/profile/index.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/frontend/app/src/pages/profile/info/index.config.ts b/frontend/app/src/pages/profile/info/index.config.ts new file mode 100644 index 0000000..cf1a2db --- /dev/null +++ b/frontend/app/src/pages/profile/info/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '用户信息' +}) + diff --git a/frontend/app/src/pages/profile/info/index.vue b/frontend/app/src/pages/profile/info/index.vue new file mode 100644 index 0000000..357bfdb --- /dev/null +++ b/frontend/app/src/pages/profile/info/index.vue @@ -0,0 +1,88 @@ + + + + + + + + diff --git a/frontend/app/src/pages/profile/password/index.config.ts b/frontend/app/src/pages/profile/password/index.config.ts new file mode 100644 index 0000000..a75927c --- /dev/null +++ b/frontend/app/src/pages/profile/password/index.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '修改密码' +}) + diff --git a/frontend/app/src/pages/profile/password/index.vue b/frontend/app/src/pages/profile/password/index.vue new file mode 100644 index 0000000..52378db --- /dev/null +++ b/frontend/app/src/pages/profile/password/index.vue @@ -0,0 +1,98 @@ + + + + + + + + diff --git a/frontend/app/src/stores/user.ts b/frontend/app/src/stores/user.ts new file mode 100644 index 0000000..f277435 --- /dev/null +++ b/frontend/app/src/stores/user.ts @@ -0,0 +1,31 @@ +import { defineStore } from 'pinia' +import type { ConfigDTO, TokenDTO, UserInfoDTO } from '@/api/types' +import { clearLoginSession, getCurrentUser, getToken, setCurrentUser, setLoginSession } from '@/utils/auth' + +export const useUserStore = defineStore('user', { + state: () => ({ + token: getToken(), + currentUser: getCurrentUser(), + config: undefined as ConfigDTO | undefined + }), + actions: { + setSession(data: TokenDTO) { + setLoginSession(data) + this.token = data.token + this.currentUser = data.currentUser.userInfo + }, + setConfig(config: ConfigDTO) { + this.config = config + }, + setUser(user: UserInfoDTO) { + setCurrentUser(user) + this.currentUser = user + }, + clearSession() { + clearLoginSession() + this.token = '' + this.currentUser = {} + } + } +}) + diff --git a/frontend/app/src/theme/tokens.ts b/frontend/app/src/theme/tokens.ts new file mode 100644 index 0000000..fadc40c --- /dev/null +++ b/frontend/app/src/theme/tokens.ts @@ -0,0 +1,13 @@ +export const themeTokens = { + color: { + primary: '#000', + primaryLight: '#f5f5f5', + danger: '#d20f39', + success: '#40a02b', + warning: '#df8e1d', + info: '#1e66f5', + page: '#fff', + textSecondary: '#737373', + textDisabled: '#a3a3a3' + } +} as const diff --git a/frontend/app/src/theme/variables.scss b/frontend/app/src/theme/variables.scss new file mode 100644 index 0000000..3f4a4b0 --- /dev/null +++ b/frontend/app/src/theme/variables.scss @@ -0,0 +1,90 @@ +$color-brand: #000; +$color-brand-light: #f5f5f5; +$color-brand-dark: #111; +$color-success: #40a02b; +$color-error: #d20f39; +$color-warning: #df8e1d; +$color-info: #1e66f5; +$color-white: #fff; +$color-grey-0: #111; +$color-grey-1: #737373; +$color-grey-2: #737373; +$color-grey-3: #a3a3a3; +$color-grey-4: #e5e5e5; +$color-grey-5: #f5f5f5; +$color-grey-6: #fafafa; +$color-text-base: $color-brand; +$color-text-title: $color-brand; +$color-text-paragraph: $color-grey-0; +$color-text-secondary: $color-grey-1; +$color-text-placeholder: $color-grey-1; +$color-text-disabled: $color-grey-3; +$color-text-base-inverse: $color-white; +$color-link: $color-brand; +$color-link-hover: $color-grey-0; +$color-link-active: $color-brand; +$color-link-disabled: $color-grey-3; +$color-bg: $color-white; +$color-bg-base: $color-white; +$color-bg-light: $color-brand-light; +$color-bg-grey: $color-grey-5; +$color-border-base: #d4d4d4; +$color-border-grey: $color-grey-3; +$border-radius-sm: 6px; +$border-radius-md: 8px; +$border-radius-lg: 12px; +$font-size-xs: 20px; +$font-size-sm: 22px; +$font-size-base: 24px; +$font-size-lg: 26px; +$font-size-xl: 28px; +$font-size-xxl: 32px; +$at-button-border-color-primary: transparent; +$at-button-bg: $color-brand; +$at-fab-bg-color: $color-brand; +$at-fab-bg-color-active: $color-brand-dark; +$at-tag-color-active: $color-brand; +$at-tabs-color-active: $color-brand; +$at-progress-bar-bg-color: $color-brand-light; +$color-primary: $color-brand; +$color-primary-light: $color-brand-light; +$color-primary-border: $color-border-grey; +$color-danger: $color-error; +$color-danger-light: #f9e2e7; +$color-success-light: #e5f4e1; +$color-warning-light: #fbedd8; +$color-info-light: #e6edfe; +$text-primary: $color-text-base; +$text-regular: $color-text-paragraph; +$text-secondary: $color-text-secondary; +$text-placeholder: $color-text-placeholder; +$text-disabled: $color-text-disabled; +$bg-page: $color-bg; +$bg-muted: $color-bg-grey; +$bg-soft: $color-grey-4; +$bg-subtle: $color-grey-6; +$border-color: $color-border-base; +$border-color-strong: $color-border-grey; +$border-color-light: $color-grey-4; +$radius-sm: $border-radius-sm; +$radius-md: $border-radius-md; +$radius-tab: 4px; +$space-xxs: 4px; +$space-xs: 8px; +$space-sm: 12px; +$space-md: 18px; +$space-lg: 20px; +$space-xl: 24px; +$font-xs: $font-size-xs; +$font-sm: $font-size-sm; +$font-md: $font-size-base; +$font-lg: $font-size-lg; +$font-xl: $font-size-xl; +$font-title: $font-size-xxl; +$font-profile-title: 42px; +$tabbar-height: 108px; +$control-height: 64px; +$line-height-control: 40px; +$page-bottom-space: 132px; + + diff --git a/frontend/app/src/utils/auth.ts b/frontend/app/src/utils/auth.ts new file mode 100644 index 0000000..00de3ca --- /dev/null +++ b/frontend/app/src/utils/auth.ts @@ -0,0 +1,37 @@ +import Taro from '@tarojs/taro' +import type { TokenDTO, UserInfoDTO } from '@/api/types' + +const tokenKey = 'simple-todo-app-token' +const userKey = 'simple-todo-app-user' + +export function getToken() { + return Taro.getStorageSync(tokenKey) || '' +} + +export function getCurrentUser() { + return Taro.getStorageSync(userKey) || {} +} + +export function isLoggedIn() { + return Boolean(getToken()) +} + +export function setLoginSession(data: TokenDTO) { + Taro.setStorageSync(tokenKey, data.token) + Taro.setStorageSync(userKey, data.currentUser.userInfo) +} + +export function setCurrentUser(user: UserInfoDTO) { + Taro.setStorageSync(userKey, user) +} + +export function clearLoginSession() { + Taro.removeStorageSync(tokenKey) + Taro.removeStorageSync(userKey) +} + +export function redirectToLogin() { + clearLoginSession() + Taro.reLaunch({ url: '/pages/login/index' }) +} + diff --git a/frontend/app/src/utils/crypt.ts b/frontend/app/src/utils/crypt.ts new file mode 100644 index 0000000..4d595e0 --- /dev/null +++ b/frontend/app/src/utils/crypt.ts @@ -0,0 +1,15 @@ +import WxmpRsa from 'wxmp-rsa' + +const publicKey = + 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCh6HkK+rCM37FAzCHVythTc6pxvr551K07CRhdX/NjCddHAuQMOd/57R5fiIwgVNEfCsD1cIyS6A8IWj4DtJLR2t29JehPpqiFSJ4hNtDcLNxNJiYRcCQvyMQeyQIPE5Ljc35c72YwDtQAsIJChsauyLrc+E6HC3gn1JDm18HNXwIDAQAB' + +export function rsaEncrypt(text: string) { + const encryptor = new WxmpRsa() + encryptor.setPublicKey(publicKey) + const encrypted = encryptor.encrypt(text) + if (encrypted === false) { + throw new Error('Password encryption failed') + } + return encrypted +} + diff --git a/frontend/app/src/utils/http.ts b/frontend/app/src/utils/http.ts new file mode 100644 index 0000000..7a84aeb --- /dev/null +++ b/frontend/app/src/utils/http.ts @@ -0,0 +1,140 @@ +import Taro from '@tarojs/taro' +import { getToken, redirectToLogin } from './auth' +import type { ResponseData } from '@/api/types' + +type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' + +interface RequestOptions { + method: RequestMethod + url: string + data?: unknown + params?: object + showLoading?: boolean +} + +interface UploadOptions { + url: string + filePath: string + fileName?: string + name?: string + formData?: Record + showLoading?: boolean +} + +const baseURL = process.env.TARO_APP_API_BASE || 'http://localhost:8080' + +export async function request(options: RequestOptions) { + if (options.showLoading !== false) { + Taro.showLoading({ title: '加载中', mask: true }) + } + try { + return await sendRequest(options) + } finally { + if (options.showLoading !== false) { + Taro.hideLoading() + } + } +} + +async function sendRequest(options: RequestOptions) { + const response = await Taro.request>({ + url: buildUrl(options.url, options.params), + method: options.method, + data: options.data, + header: buildHeaders() + }) + return handleResponse(response.data) +} + +export async function uploadFile(options: UploadOptions) { + if (options.showLoading !== false) { + Taro.showLoading({ title: '上传中', mask: true }) + } + try { + return await sendUpload(options) + } finally { + if (options.showLoading !== false) { + Taro.hideLoading() + } + } +} + +async function sendUpload(options: UploadOptions) { + const response = await Taro.uploadFile({ + url: buildUrl(options.url), + filePath: options.filePath, + name: options.name || 'file', + fileName: options.fileName, + formData: options.formData, + header: buildUploadHeaders() + }) + validateUploadStatus(response.statusCode, response.data) + return handleResponse(parseUploadData(response.data)) +} + +function validateUploadStatus(statusCode: number, data: string) { + if (statusCode >= 200 && statusCode < 300) return + const message = getUploadErrorMessage(data) || `上传失败(${statusCode})` + throw new Error(message) +} + +function buildUrl(url: string, params?: object) { + const target = `${baseURL}${url}` + const query = new URLSearchParams() + Object.entries(params || {}).forEach(([key, value]) => appendQuery(query, key, value)) + const queryString = query.toString() + return queryString ? `${target}?${queryString}` : target +} + +function appendQuery(query: URLSearchParams, key: string, value: unknown) { + if (value === undefined || value === null || value === '') return + query.append(key, String(value)) +} + +function buildHeaders() { + return { ...buildUploadHeaders(), 'Content-Type': 'application/json' } +} + +function buildUploadHeaders() { + const token = getToken() + const headers: Record = { + Accept: 'application/json, text/plain, */*' + } + if (token) { + headers.Authorization = `Bearer ${token}` + } + return headers +} + +function parseUploadData(data: string | object) { + if (typeof data !== 'string') return data as ResponseData + try { + return JSON.parse(data) as ResponseData + } catch { + throw new Error(getUploadErrorMessage(data) || '服务器返回数据结构有误') + } +} + +function getUploadErrorMessage(data: string) { + try { + return (JSON.parse(data) as { msg?: string }).msg || '' + } catch { + return data.slice(0, 60) + } +} + +function handleResponse(data: ResponseData) { + if (!data || data.code === undefined) { + throw new Error('服务器返回数据结构有误') + } + if (data.code === 106) { + redirectToLogin() + throw new Error(data.msg || '登录状态已过期') + } + if (data.code !== 0) { + Taro.showToast({ title: data.msg || '请求失败', icon: 'none' }) + throw new Error(data.msg || '请求失败') + } + return data +} + diff --git a/frontend/app/types/global.d.ts b/frontend/app/types/global.d.ts index 2678969..2ca2cc5 100644 --- a/frontend/app/types/global.d.ts +++ b/frontend/app/types/global.d.ts @@ -23,9 +23,22 @@ declare namespace NodeJS { * @see https://taro-docs.jd.com/docs/next/env-mode-config#特殊环境变量-taro_app_id */ TARO_APP_ID: string + TARO_APP_API_BASE: string } } declare module '@tarojs/components' { export * from '@tarojs/components/types/index.vue3' } + +declare module '@qiun/ucharts' { + interface UChartsOptions { + [key: string]: unknown + } + + export default class UCharts { + constructor(options: UChartsOptions) + updateData(data: UChartsOptions): void + showToolTip(event: unknown, options?: UChartsOptions): void + } +} diff --git a/frontend/app/types/wxmp-rsa.d.ts b/frontend/app/types/wxmp-rsa.d.ts new file mode 100644 index 0000000..eb41fc8 --- /dev/null +++ b/frontend/app/types/wxmp-rsa.d.ts @@ -0,0 +1,6 @@ +declare module 'wxmp-rsa' { + export default class WxmpRsa { + setPublicKey(publicKey: string): void + encrypt(text: string): string | false + } +} diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 504e864..25f219a 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: '@babel/runtime': specifier: ^7.24.4 version: 7.29.2 + '@qiun/ucharts': + specifier: 2.5.0-20230101 + version: 2.5.0-20230101 '@tarojs/components': specifier: 4.2.0 version: 4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)) @@ -98,9 +101,18 @@ importers: '@tarojs/taro': specifier: 4.2.0 version: 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(@tarojs/helper@4.2.0)(@tarojs/shared@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)) + pinia: + specifier: ^2.3.1 + version: 2.3.1(typescript@5.9.3)(vue@3.5.34(typescript@5.9.3)) + taro-ui-vue3: + specifier: 1.0.0-alpha.21 + version: 1.0.0-alpha.21(@tarojs/components@4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(@tarojs/taro@4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(@tarojs/helper@4.2.0)(@tarojs/shared@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(vue@3.5.34(typescript@5.9.3)) vue: specifier: ^3.0.0 version: 3.5.34(typescript@5.9.3) + wxmp-rsa: + specifier: ^2.1.0 + version: 2.1.0 devDependencies: '@babel/core': specifier: ^7.24.4 @@ -194,7 +206,7 @@ importers: version: 2.3.6(vue@3.5.34(typescript@5.0.4)) js-cookie: specifier: ^3.0.5 - version: 3.0.5 + version: 3.0.7 jsencrypt: specifier: ^3.3.2 version: 3.5.4 @@ -225,6 +237,9 @@ importers: sortablejs: specifier: ^1.15.0 version: 1.15.7 + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 typeit: specifier: ^8.7.1 version: 8.8.7 @@ -1549,6 +1564,9 @@ packages: vue: optional: true + '@qiun/ucharts@2.5.0-20230101': + resolution: {integrity: sha512-C7ccBgfPuGF6dxTRuMW0NPPMSCf1k/kh3I9zkRVBc5PaivudX/rPL+jd2Wty6gn5ya5L3Ob+YmYe09V5xw66Cw==} + '@rnx-kit/babel-preset-metro-react-native@1.1.8': resolution: {integrity: sha512-8DotuBK1ZgV0H/tmCmtW/3ofA7JR/8aPqSu9lKnuqwBfq4bxz+w1sMyfFl89m4teWlkhgyczWBGD6NCLqTgi9A==} peerDependencies: @@ -4229,9 +4247,9 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} - js-cookie@3.0.5: - resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} - engines: {node: '>=14'} + js-cookie@3.0.7: + resolution: {integrity: sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==} + engines: {node: '>=20'} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5989,6 +6007,13 @@ packages: resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==} engines: {node: '>= 0.8.0'} + taro-ui-vue3@1.0.0-alpha.21: + resolution: {integrity: sha512-3//e9gnd8VhG9913ifVZP1wwlE9i1iJwwaYkHhSFgD1RhZomHqN+nRBuzNmV+aYZzjpAYqLSpt0v7CHaIyQwdA==} + peerDependencies: + '@tarojs/components': ^3.2.1 + '@tarojs/taro': ^3.2.1 + vue: ^3.0.10 + terser-webpack-plugin@5.5.0: resolution: {integrity: sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==} engines: {node: '>= 10.13.0'} @@ -6449,6 +6474,9 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + wxmp-rsa@2.1.0: + resolution: {integrity: sha512-VbWMJ+vf8t7G93sjkqjCn5yGy/Si3M8uD6OFebqjJWJ1R0WCyle7X6SNia7WWG6Qe1F2/OWxhbcSGA6ebUBwIA==} + xlsx@0.18.5: resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} engines: {node: '>=0.8'} @@ -7780,6 +7808,8 @@ snapshots: echarts: 5.6.0 vue: 3.5.34(typescript@5.0.4) + '@qiun/ucharts@2.5.0-20230101': {} + '@rnx-kit/babel-preset-metro-react-native@1.1.8(@babel/core@7.29.0)(@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0))(@babel/runtime@7.29.2)': dependencies: '@babel/core': 7.29.0 @@ -11168,7 +11198,7 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 - js-cookie@3.0.5: {} + js-cookie@3.0.7: {} js-tokens@4.0.0: {} @@ -11700,6 +11730,16 @@ snapshots: transitivePeerDependencies: - '@vue/composition-api' + pinia@2.3.1(typescript@5.9.3)(vue@3.5.34(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.34(typescript@5.9.3) + vue-demi: 0.14.10(vue@3.5.34(typescript@5.9.3)) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@vue/composition-api' + pinkie-promise@2.0.1: dependencies: pinkie: 2.0.4 @@ -12943,6 +12983,14 @@ snapshots: to-buffer: 1.2.2 xtend: 4.0.2 + taro-ui-vue3@1.0.0-alpha.21(@tarojs/components@4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(@tarojs/taro@4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(@tarojs/helper@4.2.0)(@tarojs/shared@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(vue@3.5.34(typescript@5.9.3)): + dependencies: + '@tarojs/components': 4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)) + '@tarojs/taro': 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)))(@tarojs/helper@4.2.0)(@tarojs/shared@4.2.0)(postcss@8.5.14)(rollup@3.30.0)(vue@3.5.34(typescript@5.9.3))(webpack@5.106.2(@swc/core@1.3.96)) + dayjs: 1.11.20 + lodash-es: 4.18.1 + vue: 3.5.34(typescript@5.9.3) + terser-webpack-plugin@5.5.0(@swc/core@1.3.96)(webpack@5.106.2(@swc/core@1.3.96)): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -13244,6 +13292,10 @@ snapshots: dependencies: vue: 3.5.34(typescript@5.0.4) + vue-demi@0.14.10(vue@3.5.34(typescript@5.9.3)): + dependencies: + vue: 3.5.34(typescript@5.9.3) + vue-eslint-parser@9.4.3(eslint@8.57.1): dependencies: debug: 4.4.3 @@ -13451,6 +13503,8 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + wxmp-rsa@2.1.0: {} + xlsx@0.18.5: dependencies: adler-32: 1.3.1 diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml index 1411e21..8c8ddd3 100644 --- a/frontend/pnpm-workspace.yaml +++ b/frontend/pnpm-workspace.yaml @@ -2,12 +2,12 @@ packages: - "web" - "app" allowBuilds: - '@parcel/watcher': set this to true or false - '@swc/core': set this to true or false - '@tarojs/binding': set this to true or false - '@tarojs/cli': set this to true or false - core-js: set this to true or false - core-js-pure: set this to true or false - esbuild: set this to true or false - typeit: set this to true or false - vue-demi: set this to true or false + '@parcel/watcher': true + '@swc/core': true + '@tarojs/binding': true + '@tarojs/cli': true + core-js: true + core-js-pure: true + esbuild: true + typeit: true + vue-demi: true diff --git a/frontend/web/.env b/frontend/web/.env index 396bd5d..3bc9ce4 100644 --- a/frontend/web/.env +++ b/frontend/web/.env @@ -1,4 +1,2 @@ # Web default environment VITE_PORT = 8848 -VITE_HIDE_HOME = false - diff --git a/frontend/web/Dockerfile b/frontend/web/Dockerfile index 5163975..440e04f 100644 --- a/frontend/web/Dockerfile +++ b/frontend/web/Dockerfile @@ -1,20 +1,23 @@ -FROM node:16-alpine as build-stage +FROM node:22-alpine AS build-stage WORKDIR /app RUN corepack enable -RUN corepack prepare pnpm@7.32.1 --activate +RUN corepack prepare pnpm@11.1.3 --activate RUN npm config set registry https://registry.npmmirror.com -COPY .npmrc package.json pnpm-lock.yaml ./ -RUN pnpm install --frozen-lockfile +COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.base.json ./ +COPY web/package.json web/package.json +RUN pnpm install --frozen-lockfile --filter @simple-template/web... -COPY . . +COPY web web +WORKDIR /app/web RUN pnpm build -FROM nginx:stable-alpine as production-stage +FROM nginx:stable-alpine AS production-stage -COPY --from=build-stage /app/dist /usr/share/nginx/html +COPY --from=build-stage /app/web/dist /usr/share/nginx/html +COPY web/nginx/default.conf /etc/nginx/conf.d/default.conf EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file +CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/web/build/index.ts b/frontend/web/build/index.ts index fbf08a3..fd14587 100644 --- a/frontend/web/build/index.ts +++ b/frontend/web/build/index.ts @@ -6,7 +6,6 @@ const wrapperEnv = (envConfigs: Recordable): ViteEnv => { VITE_PUBLIC_PATH: "", VITE_ROUTER_HISTORY: "", VITE_CDN: false, - VITE_HIDE_HOME: "false", VITE_COMPRESSION: "none", VITE_APP_BASE_API: "" }; diff --git a/frontend/web/nginx/default.conf b/frontend/web/nginx/default.conf new file mode 100644 index 0000000..38d2ea3 --- /dev/null +++ b/frontend/web/nginx/default.conf @@ -0,0 +1,20 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + location /prod-api/ { + proxy_pass http://app:8080/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/frontend/web/package.json b/frontend/web/package.json index ca8a05c..60ed4f2 100644 --- a/frontend/web/package.json +++ b/frontend/web/package.json @@ -50,6 +50,7 @@ "qs": "^6.11.2", "responsive-storage": "^2.2.0", "sortablejs": "^1.15.0", + "tippy.js": "^6.3.7", "typeit": "^8.7.1", "vue": "^3.3.4", "vue-router": "^4.2.2", diff --git a/frontend/web/src/api/common/login.ts b/frontend/web/src/api/common/login.ts index 138b297..4b26843 100644 --- a/frontend/web/src/api/common/login.ts +++ b/frontend/web/src/api/common/login.ts @@ -11,6 +11,8 @@ export type CaptchaDTO = { export type ConfigDTO = { /** 验证码开关 */ isCaptchaOn: boolean; + /** 注册开关 */ + isRegisterUserOn?: boolean; /** 系统字典配置(下拉选项之类的) */ dictionary: Record>; }; @@ -26,6 +28,25 @@ export type LoginByPasswordDTO = { captchaCodeKey: string; }; +export type RegisterUserCommand = { + /** 用户名 */ + username: string; + /** 昵称 */ + nickname?: string; + /** 密码 */ + password: string; + /** 确认密码 */ + confirmPassword: string; + /** 邮箱 */ + email?: string; + /** 手机号 */ + phoneNumber?: string; + /** 验证码 */ + captchaCode: string; + /** 验证码对应的缓存key */ + captchaCodeKey: string; +}; + /** * 后端token实现 */ @@ -50,15 +71,11 @@ export interface CurrentUserInfoDTO { createTime?: Date; creatorId?: number; creatorName?: string; - deptId?: number; - deptName?: string; email?: string; loginDate?: Date; loginIp?: string; nickName?: string; phoneNumber?: string; - postId?: number; - postName?: string; remark?: string; roleId?: number; roleName?: string; @@ -93,6 +110,11 @@ export const loginByPassword = (data: LoginByPasswordDTO) => { return http.request>("post", "/login", { data }); }; +/** 注册接口 */ +export const registerUser = (data: RegisterUserCommand) => { + return http.request>("post", "/register", { data }); +}; + /** 获取当前登录用户接口 */ export const getLoginUserInfo = () => { return http.request>("get", "/getLoginUserInfo"); diff --git a/frontend/web/src/api/system/dept.ts b/frontend/web/src/api/system/dept.ts deleted file mode 100644 index a5b8dc0..0000000 --- a/frontend/web/src/api/system/dept.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { http } from "@/utils/http"; - -export interface DeptQuery extends BaseQuery { - // TODO 目前不需要这个参数 - deptId?: number; - parentId?: number; -} - -/** - * DeptDTO - */ -export interface DeptDTO { - createTime?: Date; - id?: number; - deptName?: string; - email?: string; - leaderName?: string; - orderNum?: number; - parentId?: number; - phone?: string; - status?: number; - statusStr?: string; -} - -/** - * AddDeptCommand - */ -export interface DeptRequest { - deptName: string; - email?: string; - leaderName?: string; - orderNum: number; - parentId: number; - phone?: string; - status: number; -} - -export interface DeptTreeDTO { - id: number; - parentId: number; - label: string; - children: [DeptTreeDTO]; -} - -/** 获取部门列表 */ -export const getDeptListApi = (params?: DeptQuery) => { - return http.request>>("get", "/system/depts", { - params - }); -}; - -/** 新增部门 */ -export const addDeptApi = (data: DeptRequest) => { - console.log(data); - return http.request>("post", "/system/dept", { - data - }); -}; - -/** 部门详情 */ -export const getDeptInfoApi = (deptId: string) => { - return http.request>("get", `/system/dept/${deptId}`); -}; - -/** 修改部门 */ -export const updateDeptApi = (deptId: string, data: DeptRequest) => { - return http.request>("put", `/system/dept/${deptId}`, { - data - }); -}; - -/** 删除部门 */ -export const deleteDeptApi = (deptId: string) => { - return http.request>("delete", `/system/dept/${deptId}`); -}; - -/** 获取部门树级结构 */ -export const getDeptTree = () => { - return http.request>( - "get", - "/system/depts/dropdown" - ); -}; diff --git a/frontend/web/src/api/system/log.ts b/frontend/web/src/api/system/log.ts index d6b00ce..18395c8 100644 --- a/frontend/web/src/api/system/log.ts +++ b/frontend/web/src/api/system/log.ts @@ -11,8 +11,6 @@ export interface OperationLogDTO { businessType?: number; businessTypeStr?: string; calledMethod?: string; - deptId?: number; - deptName?: string; errorStack?: string; operationId?: number; operationParam?: string; diff --git a/frontend/web/src/api/system/monitor.ts b/frontend/web/src/api/system/monitor.ts index 53ddfd8..06498c3 100644 --- a/frontend/web/src/api/system/monitor.ts +++ b/frontend/web/src/api/system/monitor.ts @@ -7,7 +7,6 @@ export interface OnlineUserQuery { export interface OnlineUserInfo { browser?: string; - deptName?: string; ipAddress?: string; loginLocation?: string; loginTime?: number; diff --git a/frontend/web/src/api/system/post.ts b/frontend/web/src/api/system/post.ts deleted file mode 100644 index 914e55f..0000000 --- a/frontend/web/src/api/system/post.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { http } from "@/utils/http"; - -export interface PostListCommand extends BasePageQuery { - postCode?: string; - postName?: string; - status?: number; -} - -export interface PostPageResponse { - createTime: string; - postCode: string; - postId: number; - postName: string; - postSort: number; - remark: string; - status: number; - statusStr: string; -} - -export function getPostListApi(params: PostListCommand) { - return http.request>>( - "get", - "/system/post/list", - { - params - } - ); -} - -export const exportPostExcelApi = ( - params: PostListCommand, - fileName: string -) => { - return http.download("/system/post/excel", fileName, { - params - }); -}; - -export const deletePostApi = (data: Array) => { - return http.request>("delete", "/system/post", { - params: { - // 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功 - ids: data.toString() - } - }); -}; - -export interface AddPostCommand { - postCode: string; - postName: string; - postSort: number; - remark?: string; - status?: string; -} - -export const addPostApi = (data: AddPostCommand) => { - return http.request>("post", "/system/post", { - data - }); -}; - -export interface UpdatePostCommand extends AddPostCommand { - postId: number; -} - -export const updatePostApi = (data: UpdatePostCommand) => { - return http.request>("put", "/system/post", { - data - }); -}; diff --git a/frontend/web/src/api/system/role.ts b/frontend/web/src/api/system/role.ts index 41771a9..867a8fc 100644 --- a/frontend/web/src/api/system/role.ts +++ b/frontend/web/src/api/system/role.ts @@ -15,7 +15,6 @@ export interface RoleDTO { roleKey: string; roleName: string; roleSort: number; - selectedDeptList: number[]; selectedMenuList: number[]; status: number; } diff --git a/frontend/web/src/api/system/user.ts b/frontend/web/src/api/system/user.ts index aeaaf59..bc9e571 100644 --- a/frontend/web/src/api/system/user.ts +++ b/frontend/web/src/api/system/user.ts @@ -1,7 +1,6 @@ import { http } from "@/utils/http"; export interface UserQuery extends BasePageQuery { - deptId?: number; phoneNumber?: string; status?: number; userId?: number; @@ -16,14 +15,11 @@ export interface UserDTO { createTime?: Date; creatorId?: number; creatorName?: string; - deptId?: number; - deptName?: string; email?: string; loginDate?: Date; loginIp?: string; nickname?: string; phoneNumber?: string; - postId?: number; remark?: string; roleId?: number; roleName?: string; @@ -43,12 +39,10 @@ export interface UserDTO { export interface UserRequest { userId: number; avatar?: string; - deptId?: number; email?: string; nickname?: string; phoneNumber?: string; password: string; - postId?: number; remark?: string; roleId?: number; sex?: number; @@ -71,8 +65,8 @@ export interface UserProfileRequest { * ResetPasswordCommand */ export interface ResetPasswordRequest { + confirmPassword?: string; newPassword?: string; - oldPassword?: string; userId?: number; } diff --git a/frontend/web/src/components/ReIcon/src/offlineIcon.ts b/frontend/web/src/components/ReIcon/src/offlineIcon.ts index ef31833..63bb9b8 100644 --- a/frontend/web/src/components/ReIcon/src/offlineIcon.ts +++ b/frontend/web/src/components/ReIcon/src/offlineIcon.ts @@ -21,7 +21,6 @@ import CheckboxCircleLine from "@iconify-icons/ri/checkbox-circle-line"; import FlUser from "@iconify-icons/ri/admin-line"; import Role from "@iconify-icons/ri/admin-fill"; import Setting from "@iconify-icons/ri/settings-3-line"; -import Dept from "@iconify-icons/ri/git-branch-line"; import Lollipop from "@iconify-icons/ep/lollipop"; import Monitor from "@iconify-icons/ep/monitor"; addIcon("ubuntuFill", UbuntuFill); @@ -40,6 +39,5 @@ addIcon("checkboxCircleLine", CheckboxCircleLine); addIcon("flUser", FlUser); addIcon("role", Role); addIcon("setting", Setting); -addIcon("dept", Dept); addIcon("lollipop", Lollipop); addIcon("monitor", Monitor); diff --git a/frontend/web/src/layout/components/tag/index.vue b/frontend/web/src/layout/components/tag/index.vue index 5957f29..46738d8 100644 --- a/frontend/web/src/layout/components/tag/index.vue +++ b/frontend/web/src/layout/components/tag/index.vue @@ -49,7 +49,6 @@ const containerDom = ref(); const scrollbarDom = ref(); const isShowArrow = ref(false); const topPath = getTopMenu()?.path; -const { VITE_HIDE_HOME } = import.meta.env; const { isFullscreen, toggle } = useFullscreen(); const dynamicTagView = async () => { @@ -188,10 +187,7 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) { other?: boolean ): void => { if (other) { - useMultiTagsStoreHook().handleTags("equal", [ - VITE_HIDE_HOME === "false" ? routerArrays[0] : toRaw(getTopMenu()), - obj - ]); + useMultiTagsStoreHook().handleTags("equal", getPinnedTags(obj)); } else { useMultiTagsStoreHook().handleTags("splice", "", { startIndex, @@ -235,6 +231,11 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) { } } +function getPinnedTags(obj: RouteConfigs) { + const pinnedTag = routerArrays[0] ?? toRaw(getTopMenu()); + return pinnedTag ? [pinnedTag, obj] : [obj]; +} + function deleteMenu(item, tag?: string) { deleteDynamicTag(item, item.path, tag); handleAliveRoute(route as ToRouteType); diff --git a/frontend/web/src/layout/types.ts b/frontend/web/src/layout/types.ts index 3038129..6734546 100644 --- a/frontend/web/src/layout/types.ts +++ b/frontend/web/src/layout/types.ts @@ -1,18 +1,6 @@ import type { IconifyIcon } from "@iconify/vue"; -const { VITE_HIDE_HOME } = import.meta.env; -export const routerArrays: Array = - VITE_HIDE_HOME === "false" - ? [ - { - path: "/welcome", - meta: { - title: "首页", - icon: "homeFilled" - } - } - ] - : []; +export const routerArrays: Array = []; export type routeMetaType = { title?: string; diff --git a/frontend/web/src/router/defaultEntry.ts b/frontend/web/src/router/defaultEntry.ts new file mode 100644 index 0000000..c3c2437 --- /dev/null +++ b/frontend/web/src/router/defaultEntry.ts @@ -0,0 +1 @@ +export const DEFAULT_ENTRY_PATH = "/collaboration/record/index"; diff --git a/frontend/web/src/router/index.ts b/frontend/web/src/router/index.ts index 9df7082..2f2399b 100644 --- a/frontend/web/src/router/index.ts +++ b/frontend/web/src/router/index.ts @@ -99,8 +99,6 @@ export function resetRouter() { /** 路由白名单 */ const whiteList = ["/login"]; -const { VITE_HIDE_HOME } = import.meta.env; - router.beforeEach((to: ToRouteType, _from, next) => { if (to.meta?.keepAlive) { handleAliveRoute(to, "add"); @@ -130,10 +128,6 @@ router.beforeEach((to: ToRouteType, _from, next) => { if (to.meta?.roles && !isOneOfArray(to.meta?.roles, [userInfo.roleKey])) { next({ path: "/error/403" }); } - // 开启隐藏首页后在浏览器地址栏手动输入首页welcome路由则跳转到404页面 - if (VITE_HIDE_HOME === "true" && to.fullPath === "/welcome") { - next({ path: "/error/404" }); - } if (_from?.name) { // name为超链接 if (externalLink) { diff --git a/frontend/web/src/router/modules/home.ts b/frontend/web/src/router/modules/home.ts index aec5455..48b1277 100644 --- a/frontend/web/src/router/modules/home.ts +++ b/frontend/web/src/router/modules/home.ts @@ -1,25 +1,16 @@ -const { VITE_HIDE_HOME } = import.meta.env; +import { DEFAULT_ENTRY_PATH } from "@/router/defaultEntry"; + const Layout = () => import("@/layout/index.vue"); export default { path: "/", name: "Home", component: Layout, - redirect: "/welcome", + redirect: DEFAULT_ENTRY_PATH, meta: { icon: "homeFilled", title: "首页", + showLink: false, rank: 0 - }, - children: [ - { - path: "/welcome", - name: "Welcome", - component: () => import("@/views/welcome/index.vue"), - meta: { - title: "首页", - showLink: VITE_HIDE_HOME === "true" ? false : true - } - } - ] + } } as RouteConfigsTable; diff --git a/frontend/web/src/router/utils.ts b/frontend/web/src/router/utils.ts index 26e254d..af2a732 100644 --- a/frontend/web/src/router/utils.ts +++ b/frontend/web/src/router/utils.ts @@ -20,6 +20,7 @@ import { getConfig } from "@/config"; import { menuType } from "@/layout/types"; import { buildHierarchyTree } from "@/utils/tree"; import { sessionKey } from "@/utils/auth"; +import { DEFAULT_ENTRY_PATH } from "@/router/defaultEntry"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; import { usePermissionStoreHook } from "@/store/modules/permission"; const IFrame = () => import("@/layout/frameView.vue"); @@ -364,10 +365,24 @@ function hasAuth(value: string | Array): boolean { return isAuths ? true : false; } -/** 获取所有菜单中的第一个菜单(顶级菜单)*/ -function getTopMenu(tag = false): menuType { - const topMenu = usePermissionStoreHook().wholeMenus[0]?.children[0]; - tag && useMultiTagsStoreHook().handleTags("push", topMenu); +function findMenuByPath(menus: menuType[], path: string): menuType | undefined { + for (const menu of menus) { + if (menu.path === path) return menu; + const matched = findMenuByPath(menu.children ?? [], path); + if (matched) return matched; + } +} + +/** 获取默认入口菜单 */ +function getTopMenu(tag = false): menuType | undefined { + const wholeMenus = usePermissionStoreHook().wholeMenus; + const topMenu = + findMenuByPath(wholeMenus, DEFAULT_ENTRY_PATH) ?? + wholeMenus[0]?.children?.[0] ?? + wholeMenus[0]; + if (tag && topMenu) { + useMultiTagsStoreHook().handleTags("push", topMenu); + } return topMenu; } diff --git a/frontend/web/src/utils/http/index.ts b/frontend/web/src/utils/http/index.ts index 8801de5..a3f2ff1 100644 --- a/frontend/web/src/utils/http/index.ts +++ b/frontend/web/src/utils/http/index.ts @@ -84,6 +84,7 @@ class PureHttp { const whiteList = [ "/refreshToken", "/login", + "/register", "/captchaImage", "/getConfig" ]; diff --git a/frontend/web/src/utils/tree.ts b/frontend/web/src/utils/tree.ts index d596bc5..05d8c28 100644 --- a/frontend/web/src/utils/tree.ts +++ b/frontend/web/src/utils/tree.ts @@ -141,7 +141,7 @@ export const appendFieldByUniqueId = ( }; /** - * 根据返回数据的status字段值判断追加是否禁用disabled字段,返回处理后的树结构,用于上级部门级联选择器的展示 + * 根据返回数据的status字段值判断追加是否禁用disabled字段,返回处理后的树结构。 *(实际开发中也是如此,不可能前端需要的每个字段后端都会返回,这时需要前端自行根据后端返回的某些字段做逻辑处理) * 这个是pure作者留下的例子, 也可以通过设置disabled 对应的字段来实现 比如disabled: 'status' (需要后端的字段为true/false) * @param treeList diff --git a/frontend/web/src/views/collaboration/record/record-form-modal.vue b/frontend/web/src/views/collaboration/record/record-form-modal.vue index 764b652..b3aa0ec 100644 --- a/frontend/web/src/views/collaboration/record/record-form-modal.vue +++ b/frontend/web/src/views/collaboration/record/record-form-modal.vue @@ -1,5 +1,6 @@ - - diff --git a/frontend/web/src/views/login/components/qrCode.vue b/frontend/web/src/views/login/components/qrCode.vue deleted file mode 100644 index 4c3e339..0000000 --- a/frontend/web/src/views/login/components/qrCode.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/frontend/web/src/views/login/components/register.vue b/frontend/web/src/views/login/components/register.vue deleted file mode 100644 index 659c7fe..0000000 --- a/frontend/web/src/views/login/components/register.vue +++ /dev/null @@ -1,189 +0,0 @@ - - - diff --git a/frontend/web/src/views/login/components/resetPassword.vue b/frontend/web/src/views/login/components/resetPassword.vue deleted file mode 100644 index 997fcdc..0000000 --- a/frontend/web/src/views/login/components/resetPassword.vue +++ /dev/null @@ -1,154 +0,0 @@ - - - diff --git a/frontend/web/src/views/login/index.vue b/frontend/web/src/views/login/index.vue index 007bb6f..9b2958d 100644 --- a/frontend/web/src/views/login/index.vue +++ b/frontend/web/src/views/login/index.vue @@ -11,21 +11,19 @@ import { import Motion from "./utils/motion"; import { useRouter } from "vue-router"; import { message } from "@/utils/message"; -import { loginRules } from "./utils/rule"; -import phone from "./components/phone.vue"; +import { buildRegisterRules, loginRules } from "./utils/rule"; import TypeIt from "@/components/ReTypeit"; -import qrCode from "./components/qrCode.vue"; -import register from "./components/register.vue"; -import resetPassword from "./components/resetPassword.vue"; import { useNav } from "@/layout/hooks/useNav"; import type { FormInstance } from "element-plus"; -import { operates, thirdParty } from "./utils/enums"; +import { ElMessage } from "element-plus"; import { useLayout } from "@/layout/hooks/useLayout"; import { rsaEncrypt } from "@/utils/crypt"; -import { getTopMenu, initRouter } from "@/router/utils"; +import { findRouteByPath, initRouter } from "@/router/utils"; import { avatar, bg, illustration } from "./utils/static"; import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange"; +import { DEFAULT_ENTRY_PATH } from "@/router/defaultEntry"; +import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; import { getIsRememberMe, getPassword, @@ -50,13 +48,14 @@ defineOptions({ const captchaCodeBase64 = ref(""); const isCaptchaOn = ref(false); +const isRegisterUserOn = ref(true); +const isRegisterMode = ref(false); const router = useRouter(); const loading = ref(false); const isRememberMe = ref(false); const ruleFormRef = ref(); -// 判断登录页面显示哪个组件(0:登录(默认)、1:手机登录、2:二维码登录、3:注册、4:忘记密码) -const currentPage = ref(0); +const registerFormRef = ref(); const { initStorage } = useLayout(); initStorage(); @@ -72,45 +71,135 @@ const ruleForm = reactive({ captchaCodeKey: "" }); -const onLogin = async (formEl: FormInstance | undefined) => { - loading.value = true; +const registerForm = reactive({ + username: "", + nickname: "", + password: "", + confirmPassword: "", + email: "", + phoneNumber: "", + captchaCode: "", + captchaCodeKey: "" +}); + +const registerRules = buildRegisterRules(() => registerForm.password); + +const onLogin = async () => { + const formEl = ruleFormRef.value; if (!formEl) return; - await formEl.validate((valid, fields) => { - if (valid) { - CommonAPI.loginByPassword({ - username: ruleForm.username, - password: rsaEncrypt(ruleForm.password), - captchaCode: ruleForm.captchaCode, - captchaCodeKey: ruleForm.captchaCodeKey - }) - .then(({ data }) => { - // 登录成功后 将token存储到sessionStorage中 - setTokenFromBackend(data); - // 获取后端路由 - initRouter().then(() => { - router.push(getTopMenu(true).path); - message("登录成功", { type: "success" }); - }); - if (isRememberMe.value) { - savePassword(ruleForm.password); - } - }) - .catch(() => { - loading.value = false; - //如果登陆失败则重新获取验证码 - getCaptchaCode(); - }); - } else { - loading.value = false; - return fields; - } - }); + loading.value = true; + const isValid = await formEl.validate().catch(() => false); + if (!isValid) { + loading.value = false; + return; + } + await submitLogin(); }; +async function submitLogin() { + try { + const { data } = await CommonAPI.loginByPassword({ + username: ruleForm.username, + password: rsaEncrypt(ruleForm.password), + captchaCode: ruleForm.captchaCode, + captchaCodeKey: ruleForm.captchaCodeKey + }); + await handleLoginSuccess(data, "", "登录成功"); + saveRememberedPassword(); + } catch { + loading.value = false; + await getCaptchaCode(); + } +} + +const onRegister = async () => { + const formEl = registerFormRef.value; + if (!formEl) { + ElMessage.error("注册表单未初始化,请刷新页面后重试"); + return; + } + loading.value = true; + const isValid = await formEl.validate().catch(() => false); + if (!isValid) { + loading.value = false; + ElMessage.error("请检查注册表单信息"); + return; + } + await submitRegister(); +}; + +async function submitRegister() { + try { + const command = toRegisterCommand(); + const { data } = await CommonAPI.registerUser(command); + await handleLoginSuccess(data, DEFAULT_ENTRY_PATH, "注册成功"); + } catch (error) { + loading.value = false; + await getCaptchaCode(); + if (error instanceof Error) { + ElMessage.error(error.message); + } + } +} + +function toRegisterCommand() { + assertRegisterFormReady(); + return { + username: registerForm.username, + nickname: registerForm.nickname, + password: rsaEncrypt(registerForm.password), + confirmPassword: rsaEncrypt(registerForm.confirmPassword), + email: registerForm.email, + phoneNumber: registerForm.phoneNumber, + captchaCode: registerForm.captchaCode, + captchaCodeKey: registerForm.captchaCodeKey + }; +} + +function assertRegisterFormReady() { + if (!registerForm.username || !registerForm.password) { + throw new Error("请输入账号和密码"); + } + if (registerForm.password !== registerForm.confirmPassword) { + throw new Error("两次输入的密码不一致"); + } +} + +async function handleLoginSuccess( + data: CommonAPI.TokenDTO, + path: string, + successMessage: string +) { + setTokenFromBackend(data); + await initRouter(); + const entryPath = path || DEFAULT_ENTRY_PATH; + pushEntryTag(entryPath); + router.push(entryPath); + message(successMessage, { type: "success" }); +} + +function pushEntryTag(entryPath: string) { + const children = router.options.routes[0]?.children ?? []; + const route = findRouteByPath(entryPath, children); + if (!route?.meta?.title) return; + const { path, name, meta } = route; + useMultiTagsStoreHook().handleTags("push", { path, name, meta }); +} + +function saveRememberedPassword() { + if (isRememberMe.value) { + savePassword(ruleForm.password); + } +} + /** 使用公共函数,避免`removeEventListener`失效 */ function onkeypress({ code }: KeyboardEvent) { if (code === "Enter") { - onLogin(ruleFormRef.value); + if (isRegisterMode.value) { + onRegister(); + return; + } + onLogin(); } } @@ -118,11 +207,32 @@ async function getCaptchaCode() { if (isCaptchaOn.value) { await CommonAPI.getCaptchaCode().then(res => { captchaCodeBase64.value = `data:image/gif;base64,${res.data.captchaCodeImg}`; - ruleForm.captchaCodeKey = res.data.captchaCodeKey; + setCaptchaCodeKey(res.data.captchaCodeKey); }); } } +function setCaptchaCodeKey(captchaCodeKey: string) { + if (isRegisterMode.value) { + registerForm.captchaCodeKey = captchaCodeKey; + return; + } + ruleForm.captchaCodeKey = captchaCodeKey; +} + +function switchMode(isRegister: boolean) { + isRegisterMode.value = isRegister; + clearCaptchaCode(); + getCaptchaCode(); +} + +function clearCaptchaCode() { + ruleForm.captchaCode = ""; + ruleForm.captchaCodeKey = ""; + registerForm.captchaCode = ""; + registerForm.captchaCodeKey = ""; +} + watch(isRememberMe, newVal => { saveIsRememberMe(newVal); if (newVal === false) { @@ -133,6 +243,7 @@ watch(isRememberMe, newVal => { onBeforeMount(async () => { await CommonAPI.getConfig().then(res => { isCaptchaOn.value = res.data.isCaptchaOn; + isRegisterUserOn.value = res.data.isRegisterUserOn !== false; useUserStoreHook().SET_DICTIONARY(res.data.dictionary); }); @@ -182,7 +293,7 @@ onBeforeUnmount(() => { {
记住密码 - - 忘记密码 + + 注册账号
登录
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
+
- {{ item.title }} + 返回登录
+ + 注册 + - - - - -

{{ "第三方登录" }}

-
-
- - - -
-
-
- - - - - - - -
diff --git a/frontend/web/src/views/login/utils/enums.ts b/frontend/web/src/views/login/utils/enums.ts deleted file mode 100644 index 72265ae..0000000 --- a/frontend/web/src/views/login/utils/enums.ts +++ /dev/null @@ -1,35 +0,0 @@ -const operates = [ - { - title: "手机登录", - page: 1 - }, - { - title: "二维码登录", - page: 2 - }, - { - title: "注册", - page: 3 - } -]; - -const thirdParty = [ - { - title: "微信登录", - icon: "wechat" - }, - { - title: "支付宝登录", - icon: "alipay" - }, - { - title: "QQ登录", - icon: "qq" - }, - { - title: "微博登录", - icon: "weibo" - } -]; - -export { operates, thirdParty }; diff --git a/frontend/web/src/views/login/utils/rule.ts b/frontend/web/src/views/login/utils/rule.ts index 5a0eb45..1da73c2 100644 --- a/frontend/web/src/views/login/utils/rule.ts +++ b/frontend/web/src/views/login/utils/rule.ts @@ -1,10 +1,5 @@ import { reactive } from "vue"; -import { isPhone } from "@pureadmin/utils"; import type { FormRules } from "element-plus"; -import { useUserStoreHook } from "@/store/modules/user"; - -/** 6位数字验证码正则 */ -export const REGEXP_SIX = /^\d{6}$/; /** 密码正则(密码格式应为8-18位数字、字母、符号的任意两种组合) */ export const REGEXP_PWD = @@ -12,116 +7,70 @@ export const REGEXP_PWD = /** 登录校验 */ const loginRules = reactive({ - password: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(new Error("请输入密码")); - } else if (!REGEXP_PWD.test(value)) { - callback( - new Error("密码格式应为8-18位数字、字母、符号的任意两种组合") - ); - } else { - callback(); - } - }, - trigger: "blur" - } - ], - verifyCode: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(new Error("请输入验证码")); - } else if (useUserStoreHook().verifyCode !== value) { - callback(new Error("请输入正确的验证码")); - } else { - callback(); - } - }, - trigger: "blur" - } - ] + password: [getLoginPasswordRule()] }); -/** 手机登录校验 */ -const phoneRules = reactive({ - phone: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(new Error("请输入手机号码")); - } else if (!isPhone(value)) { - callback(new Error("请输入正确的手机号码格式")); - } else { - callback(); - } - }, - trigger: "blur" - } - ], - verifyCode: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(new Error("请输入验证码")); - } else if (!REGEXP_SIX.test(value)) { - callback(new Error("请输入6位数字验证码")); - } else { - callback(); - } - }, - trigger: "blur" - } - ] -}); +function getLoginPasswordRule() { + return { + validator: (rule, value, callback) => { + if (value === "") { + callback(new Error("请输入密码")); + return; + } + if (!REGEXP_PWD.test(value)) { + callback(new Error("密码格式应为8-18位数字、字母、符号的任意两种组合")); + return; + } + callback(); + }, + trigger: "blur" + }; +} -/** 忘记密码校验 */ -const updateRules = reactive({ - phone: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(new Error("请输入手机号码")); - } else if (!isPhone(value)) { - callback(new Error("请输入正确的手机号码格式")); - } else { - callback(); - } - }, - trigger: "blur" - } - ], - verifyCode: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(new Error("请输入验证码")); - } else if (!REGEXP_SIX.test(value)) { - callback(new Error("请输入6位数字验证码")); - } else { - callback(); - } - }, - trigger: "blur" - } - ], - password: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(new Error("请输入密码")); - } else if (!REGEXP_PWD.test(value)) { - callback( - new Error("密码格式应为8-18位数字、字母、符号的任意两种组合") - ); - } else { - callback(); - } - }, - trigger: "blur" - } - ] -}); +function getRegisterPasswordRule() { + return { + validator: (rule, value, callback) => { + if (value === "") { + callback(new Error("请输入密码")); + return; + } + callback(); + }, + trigger: "blur" + }; +} -export { loginRules, phoneRules, updateRules }; +function buildRegisterRules(getPassword: () => string) { + return reactive({ + username: [ + { required: true, message: "请输入账号", trigger: "blur" }, + { max: 64, message: "账号长度不能超过64个字符", trigger: "blur" } + ], + nickname: [ + { max: 32, message: "昵称长度不能超过32个字符", trigger: "blur" } + ], + email: [{ type: "email", message: "邮箱格式不正确", trigger: "blur" }], + phoneNumber: [ + { max: 18, message: "手机号长度不能超过18个字符", trigger: "blur" } + ], + password: [getRegisterPasswordRule()], + confirmPassword: [ + { + validator: (rule, value, callback) => { + if (value === "") { + callback(new Error("请再次输入密码")); + return; + } + if (value !== getPassword()) { + callback(new Error("两次输入的密码不一致")); + return; + } + callback(); + }, + trigger: "blur" + } + ] + }); +} + +export { buildRegisterRules, loginRules }; diff --git a/frontend/web/src/views/login/utils/verifyCode.ts b/frontend/web/src/views/login/utils/verifyCode.ts deleted file mode 100644 index b6d89a7..0000000 --- a/frontend/web/src/views/login/utils/verifyCode.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { FormInstance, FormItemProp } from "element-plus"; -import { clone } from "@pureadmin/utils"; -import { ref } from "vue"; - -const isDisabled = ref(false); -const timer = ref(null); -const text = ref(""); - -export const useVerifyCode = () => { - const start = async ( - formEl: FormInstance | undefined, - props: FormItemProp, - time = 60 - ) => { - if (!formEl) return; - const initTime = clone(time, true); - await formEl.validateField(props, isValid => { - if (isValid) { - clearInterval(timer.value); - isDisabled.value = true; - text.value = `${time}`; - timer.value = setInterval(() => { - if (time > 0) { - time -= 1; - text.value = `${time}`; - } else { - text.value = ""; - isDisabled.value = false; - clearInterval(timer.value); - time = initTime; - } - }, 1000); - } - }); - }; - - const end = () => { - text.value = ""; - isDisabled.value = false; - clearInterval(timer.value); - }; - - return { - isDisabled, - timer, - text, - start, - end - }; -}; diff --git a/frontend/web/src/views/system/dept/form.vue b/frontend/web/src/views/system/dept/form.vue deleted file mode 100644 index 5cc322c..0000000 --- a/frontend/web/src/views/system/dept/form.vue +++ /dev/null @@ -1,134 +0,0 @@ - - - diff --git a/frontend/web/src/views/system/dept/index.vue b/frontend/web/src/views/system/dept/index.vue deleted file mode 100644 index 3139475..0000000 --- a/frontend/web/src/views/system/dept/index.vue +++ /dev/null @@ -1,149 +0,0 @@ - - - - - diff --git a/frontend/web/src/views/system/dept/utils/hook.tsx b/frontend/web/src/views/system/dept/utils/hook.tsx deleted file mode 100644 index e62a1ca..0000000 --- a/frontend/web/src/views/system/dept/utils/hook.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import dayjs from "dayjs"; -import editForm from "../form.vue"; -import { setDisabledForTreeOptions, handleTree } from "@/utils/tree"; -import { message } from "@/utils/message"; -import { - DeptDTO, - DeptRequest, - addDeptApi, - deleteDeptApi, - getDeptInfoApi, - getDeptListApi, - updateDeptApi -} from "@/api/system/dept"; -import { usePublicHooks } from "../../hooks"; -import { addDialog } from "@/components/ReDialog"; -import { reactive, ref, onMounted, h, computed } from "vue"; -import { isAllEmpty } from "@pureadmin/utils"; - -export function useHook() { - const searchFormParams = reactive({ - deptName: "", - status: null - }); - - const formRef = ref(); - - const originalDataList = ref([]); - const dataList = computed(() => { - let filterDataList = [...originalDataList.value]; - if (!isAllEmpty(searchFormParams.deptName)) { - // 前端搜索部门名称 - filterDataList = filterDataList.filter((item: DeptDTO) => - item.deptName.includes(searchFormParams.deptName) - ); - } - if (!isAllEmpty(searchFormParams.status)) { - // 前端搜索状态 - filterDataList = filterDataList.filter( - (item: DeptDTO) => item.status === searchFormParams.status - ); - } - // 处理成树结构 - return [...handleTree(filterDataList)]; - }); - const loading = ref(true); - const { tagStyle } = usePublicHooks(); - - const columns: TableColumnList = [ - { - label: "部门名称", - prop: "deptName", - width: 240, - align: "left" - }, - { - label: "部门编号", - prop: "id", - width: 100, - align: "center" - }, - - { - label: "部门负责人", - prop: "leaderName", - minWidth: 70 - }, - { - label: "状态", - prop: "status", - minWidth: 100, - cellRenderer: ({ row, props }) => ( - - {row.status === 1 ? "启用" : "停用"} - - ) - }, - { - label: "排序", - prop: "orderNum", - minWidth: 70 - }, - { - label: "创建时间", - minWidth: 200, - prop: "createTime", - formatter: ({ createTime }) => - dayjs(createTime).format("YYYY-MM-DD HH:mm:ss") - }, - { - label: "操作", - fixed: "right", - width: 240, - slot: "operation" - } - ]; - - function resetForm(formEl) { - if (!formEl) return; - formEl.resetFields(); - onSearch(); - } - - async function onSearch() { - loading.value = true; - // 这里是返回一维数组结构,前端自行处理成树结构,返回格式要求:唯一id加父节点parentId,parentId取父节点id - const { data } = await getDeptListApi().finally(() => { - loading.value = false; - }); - originalDataList.value = data; - } - - async function handleAdd(row, done) { - await addDeptApi(row).then(() => { - message(`您新增了部门:${row.deptName}`, { - type: "success" - }); - // 关闭弹框 - done(); - // 刷新列表 - onSearch(); - }); - } - - async function handleUpdate(row, done) { - await updateDeptApi(row.id, row).then(() => { - message(`您更新了部门${row.deptName}`, { - type: "success" - }); - // 关闭弹框 - done(); - // 刷新列表 - onSearch(); - }); - } - - async function openDialog(title = "新增", row?: DeptDTO) { - const { data } = await getDeptListApi(); - const treeList = setDisabledForTreeOptions(handleTree(data), "status"); - - if (title === "编辑") { - row = (await getDeptInfoApi(row.id + "")).data; - } - - // TODO 为什么声明一个formInline变量,把变量填充进去, 再给props.formInline 结果就不生效 - addDialog({ - title: `${title}部门`, - props: { - formInline: { - id: row?.id ?? 0, - parentId: row?.parentId ?? 0, - deptName: row?.deptName ?? "", - leaderName: row?.leaderName ?? "", - phone: row?.phone ?? "", - email: row?.email ?? "", - orderNum: row?.orderNum ?? 0, - status: row?.status ?? 1 - }, - higherDeptOptions: [...treeList] - }, - width: "40%", - draggable: true, - fullscreenIcon: true, - closeOnClickModal: false, - contentRenderer: () => h(editForm, { ref: formRef }), - beforeSure: (done, { options }) => { - const FormRef = formRef.value.getRef(); - const curData = options.props.formInline as DeptRequest; - - FormRef.validate(valid => { - if (valid) { - // 表单规则校验通过 - if (title === "新增") { - handleAdd(curData, done); - } else { - // 实际开发先调用编辑接口,再进行下面操作 - handleUpdate(curData, done); - } - } - }); - } - }); - } - - async function handleDelete(row) { - await deleteDeptApi(row.id).then(() => { - message(`您删除了部门${row.deptName}`, { type: "success" }); - // 刷新列表 - onSearch(); - }); - } - - onMounted(() => { - onSearch(); - }); - - return { - searchFormParams, - loading, - columns, - dataList, - onSearch, - resetForm, - openDialog, - handleDelete - }; -} diff --git a/frontend/web/src/views/system/dept/utils/rule.ts b/frontend/web/src/views/system/dept/utils/rule.ts deleted file mode 100644 index b20bf67..0000000 --- a/frontend/web/src/views/system/dept/utils/rule.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { reactive } from "vue"; -import type { FormRules } from "element-plus"; -import { isPhone, isEmail } from "@pureadmin/utils"; - -/** 自定义表单规则校验 */ -export const formRules = reactive({ - name: [{ required: true, message: "部门名称为必填项", trigger: "blur" }], - phone: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(); - } else if (!isPhone(value)) { - callback(new Error("请输入正确的手机号码格式")); - } else { - callback(); - } - }, - trigger: "blur" - // trigger: "click" // 如果想在点击确定按钮时触发这个校验,trigger 设置成 click 即可 - } - ], - email: [ - { - validator: (rule, value, callback) => { - if (value === "") { - callback(); - } else if (!isEmail(value)) { - callback(new Error("请输入正确的邮箱格式")); - } else { - callback(); - } - }, - trigger: "blur" - } - ] -}); diff --git a/frontend/web/src/views/system/log/operationLog/description.vue b/frontend/web/src/views/system/log/operationLog/description.vue index 564beb3..f93c511 100644 --- a/frontend/web/src/views/system/log/operationLog/description.vue +++ b/frontend/web/src/views/system/log/operationLog/description.vue @@ -36,9 +36,6 @@ const operationLogStatusMap = {{ props.operatorTypeStr }} - {{ - props.deptName - }} {{ props.operatorIp }} diff --git a/frontend/web/src/views/system/menu/form.vue b/frontend/web/src/views/system/menu/form.vue index d7d488c..ca3e0c4 100644 --- a/frontend/web/src/views/system/menu/form.vue +++ b/frontend/web/src/views/system/menu/form.vue @@ -31,7 +31,7 @@ const props = withDefaults(defineProps(), { const ruleFormRef = ref(); const { switchStyle } = usePublicHooks(); const newFormInline = ref(props.formInline); -const deptOptions = ref(props.higherMenuOptions); +const menuOptions = ref(props.higherMenuOptions); const typeName = computed(() => { return newFormInline.value.isButton ? "按钮" : "菜单"; @@ -57,7 +57,7 @@ defineExpose({ getRef }); - - -
diff --git a/frontend/web/src/views/system/menu/utils/rule.ts b/frontend/web/src/views/system/menu/utils/rule.ts index b20bf67..da535ad 100644 --- a/frontend/web/src/views/system/menu/utils/rule.ts +++ b/frontend/web/src/views/system/menu/utils/rule.ts @@ -4,7 +4,7 @@ import { isPhone, isEmail } from "@pureadmin/utils"; /** 自定义表单规则校验 */ export const formRules = reactive({ - name: [{ required: true, message: "部门名称为必填项", trigger: "blur" }], + name: [{ required: true, message: "菜单名称为必填项", trigger: "blur" }], phone: [ { validator: (rule, value, callback) => { diff --git a/frontend/web/src/views/system/monitor/onlineUser/utils/hook.tsx b/frontend/web/src/views/system/monitor/onlineUser/utils/hook.tsx index 103517e..0456588 100644 --- a/frontend/web/src/views/system/monitor/onlineUser/utils/hook.tsx +++ b/frontend/web/src/views/system/monitor/onlineUser/utils/hook.tsx @@ -40,11 +40,6 @@ export function useHook() { prop: "username", minWidth: 120 }, - { - label: "所属部门", - prop: "deptName", - minWidth: 120 - }, { label: "IP地址", prop: "ipAddress", diff --git a/frontend/web/src/views/system/post/index.vue b/frontend/web/src/views/system/post/index.vue deleted file mode 100644 index 9de1f0e..0000000 --- a/frontend/web/src/views/system/post/index.vue +++ /dev/null @@ -1,271 +0,0 @@ - - - - - diff --git a/frontend/web/src/views/system/post/post-form-modal.vue b/frontend/web/src/views/system/post/post-form-modal.vue deleted file mode 100644 index cac95ed..0000000 --- a/frontend/web/src/views/system/post/post-form-modal.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/frontend/web/src/views/system/post/utils/hook.tsx b/frontend/web/src/views/system/post/utils/hook.tsx deleted file mode 100644 index ca20ec7..0000000 --- a/frontend/web/src/views/system/post/utils/hook.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import dayjs from "dayjs"; -import { message } from "@/utils/message"; -import { ElMessageBox, Sort } from "element-plus"; -import { reactive, ref, onMounted, toRaw, computed } from "vue"; -import { useUserStoreHook } from "@/store/modules/user"; -import { CommonUtils } from "@/utils/common"; -import { PaginationProps } from "@pureadmin/table"; -import { - PostListCommand, - getPostListApi, - exportPostExcelApi, - deletePostApi -} from "@/api/system/post"; - -const statusMap = useUserStoreHook().dictionaryMap["common.status"]; - -export function usePostHook() { - const defaultSort: Sort = { - prop: "postSort", - order: "ascending" - }; - - const pagination: PaginationProps = { - total: 0, - pageSize: 10, - currentPage: 1, - background: true - }; - - const timeRange = computed<[string, string] | null>({ - get() { - if (searchFormParams.beginTime && searchFormParams.endTime) { - return [searchFormParams.beginTime, searchFormParams.endTime]; - } else { - return null; - } - }, - set(v) { - if (v?.length === 2) { - searchFormParams.beginTime = v[0]; - searchFormParams.endTime = v[1]; - } else { - searchFormParams.beginTime = undefined; - searchFormParams.endTime = undefined; - } - } - }); - - const searchFormParams = reactive({ - postCode: "", - postName: "", - status: undefined - }); - - const dataList = ref([]); - const pageLoading = ref(true); - const multipleSelection = ref([]); - const sortState = ref(defaultSort); - - const columns: TableColumnList = [ - { - type: "selection", - align: "left" - }, - { - label: "岗位编号", - prop: "postId", - minWidth: 100 - }, - { - label: "岗位编码", - prop: "postCode", - minWidth: 120 - }, - { - label: "岗位名称", - prop: "postName", - minWidth: 120 - }, - { - label: "岗位排序", - prop: "postSort", - sortable: "custom", - minWidth: 120 - }, - { - label: "状态", - prop: "status", - minWidth: 120, - cellRenderer: ({ row, props }) => ( - - {statusMap[row.status].label} - - ) - }, - { - label: "创建时间", - minWidth: 160, - prop: "createTime", - sortable: "custom", - formatter: ({ createTime }) => - dayjs(createTime).format("YYYY-MM-DD HH:mm:ss") - }, - { - label: "操作", - fixed: "right", - width: 140, - slot: "operation" - } - ]; - - function onSortChanged(sort: Sort) { - sortState.value = sort; - // 表格列的排序变化的时候,需要重置分页 - pagination.currentPage = 1; - getPostList(); - } - - async function onSearch(tableRef) { - // 点击搜索的时候,需要重置排序,重新排序的时候会重置分页并发起查询请求 - tableRef.getTableRef().sort("postSort", "ascending"); - } - - function resetForm(formEl, tableRef) { - if (!formEl) return; - // 清空查询参数 - formEl.resetFields(); - // 清空时间查询 TODO 这块有点繁琐 有可以优化的地方吗? - // Form组件的resetFields方法无法清除datepicker里面的数据。 - searchFormParams.beginTime = undefined; - searchFormParams.endTime = undefined; - // 重置分页并查询 - onSearch(tableRef); - } - - async function getPostList() { - pageLoading.value = true; - CommonUtils.fillSortParams(searchFormParams, sortState.value); - CommonUtils.fillPaginationParams(searchFormParams, pagination); - - const { data } = await getPostListApi(toRaw(searchFormParams)).finally( - () => { - pageLoading.value = false; - } - ); - dataList.value = data.rows; - pagination.total = data.total; - } - - async function exportAllExcel() { - if (sortState.value != null) { - CommonUtils.fillSortParams(searchFormParams, sortState.value); - } - CommonUtils.fillPaginationParams(searchFormParams, pagination); - CommonUtils.fillTimeRangeParams(searchFormParams, timeRange.value); - - exportPostExcelApi(toRaw(searchFormParams), "岗位数据.xlsx"); - } - - async function handleDelete(row) { - await deletePostApi([row.postId]).then(() => { - message(`您删除了编号为${row.postId}的这条岗位数据`, { - type: "success" - }); - // 刷新列表 - getPostList(); - }); - } - - async function handleBulkDelete(tableRef) { - if (multipleSelection.value.length === 0) { - message("请选择需要删除的数据", { type: "warning" }); - return; - } - - ElMessageBox.confirm( - `确认要删除编号为[ ${multipleSelection.value} ]的岗位数据吗?`, - "系统提示", - { - confirmButtonText: "确定", - cancelButtonText: "取消", - type: "warning", - dangerouslyUseHTMLString: true, - draggable: true - } - ) - .then(async () => { - await deletePostApi(multipleSelection.value).then(() => { - message(`您删除了编号为[ ${multipleSelection.value} ]的岗位数据`, { - type: "success" - }); - // 刷新列表 - getPostList(); - }); - }) - .catch(() => { - message("取消删除", { - type: "info" - }); - // 清空checkbox选择的数据 - tableRef.getTableRef().clearSelection(); - }); - } - - onMounted(getPostList); - - return { - searchFormParams, - pageLoading, - columns, - dataList, - pagination, - defaultSort, - timeRange, - multipleSelection, - onSearch, - onSortChanged, - exportAllExcel, - // exportExcel, - getPostList, - resetForm, - handleDelete, - handleBulkDelete - }; -} diff --git a/frontend/web/src/views/system/role/index.vue b/frontend/web/src/views/system/role/index.vue index a8e3fb1..9e9f29b 100644 --- a/frontend/web/src/views/system/role/index.vue +++ b/frontend/web/src/views/system/role/index.vue @@ -44,7 +44,7 @@ const roleFormRef = ref(); function getRoleFormData(row?: RoleDTO) { return { roleId: row?.roleId ?? 0, - dataScope: row?.dataScope?.toString() ?? "", + dataScope: row?.dataScope?.toString() ?? "5", menuIds: row?.selectedMenuList ?? [], remark: row?.remark ?? "", roleKey: row?.roleKey ?? "", @@ -75,7 +75,6 @@ async function openDialog(type: "add" | "update", row?: RoleDTO) { if (row) { const { data } = await getRoleInfoApi(row.roleId); row.selectedMenuList = data.selectedMenuList; - row.selectedDeptList = data.selectedDeptList; } } catch (e) { console.error(e); diff --git a/frontend/web/src/views/system/role/role-form-modal.vue b/frontend/web/src/views/system/role/role-form-modal.vue index 098c635..3cee189 100644 --- a/frontend/web/src/views/system/role/role-form-modal.vue +++ b/frontend/web/src/views/system/role/role-form-modal.vue @@ -13,7 +13,7 @@ interface Props { const props = withDefaults(defineProps(), { formInline: () => ({ roleId: 0, - dataScope: "", + dataScope: "5", menuIds: [], remark: "", roleKey: "", diff --git a/frontend/web/src/views/system/user/form.vue b/frontend/web/src/views/system/user/form.vue index 90fb2f0..c9d5eb7 100644 --- a/frontend/web/src/views/system/user/form.vue +++ b/frontend/web/src/views/system/user/form.vue @@ -3,14 +3,11 @@ import { ref } from "vue"; import ReCol from "@/components/ReCol"; import { formRules } from "./rule"; import { UserRequest } from "@/api/system/user"; -import { PostPageResponse } from "@/api/system/post"; import { RoleDTO } from "@/api/system/role"; import { useUserStoreHook } from "@/store/modules/user"; interface FormProps { formInline: UserRequest; - deptOptions: any[]; - postOptions: PostPageResponse[]; roleOptions: RoleDTO[]; } @@ -19,25 +16,19 @@ const props = withDefaults(defineProps(), { userId: 0, username: "", nickname: "", - deptId: 0, phone: "", email: "", password: "", sex: 0, status: 1, - postId: 0, roleId: 0, remark: "" }), - deptOptions: () => [], - postOptions: () => [], roleOptions: () => [] }); const newFormInline = ref(props.formInline); -const deptOptions = ref(props.deptOptions); const roleOptions = ref(props.roleOptions); -const postOptions = ref(props.postOptions); const formRuleRef = ref(); @@ -65,26 +56,6 @@ defineExpose({ getFormRuleRef }); /> - - - - - - - - - - - - - - ({ - deptId: null, phoneNumber: undefined, status: undefined, username: undefined, @@ -47,8 +43,6 @@ export function useHook() { background: true }); - const deptTreeList = ref([]); - const postOptions = ref([]); const roleOptions = ref([]); const columns: TableColumnList = [ @@ -82,17 +76,6 @@ export function useHook() { ) }, - { - label: "部门ID", - prop: "deptId", - minWidth: 130, - hide: true - }, - { - label: "部门", - prop: "deptName", - minWidth: 130 - }, { label: "手机号码", prop: "phoneNumber", @@ -252,18 +235,14 @@ export function useHook() { userId: row?.userId ?? 0, username: row?.username ?? "", nickname: row?.nickname ?? "", - deptId: row?.deptId ?? undefined, phoneNumber: row?.phoneNumber ?? "", email: row?.email ?? "", password: title == "新增" ? "" : undefined, sex: row?.sex ?? undefined, status: row?.status ?? undefined, - postId: row?.postId ?? undefined, roleId: row?.roleId ?? undefined, remark: row?.remark ?? "" }, - deptOptions: deptTreeList, - postOptions: postOptions, roleOptions: roleOptions }, @@ -356,15 +335,6 @@ export function useHook() { onMounted(async () => { onSearch(); - const deptResponse = await getDeptListApi(); - deptTreeList.value = await setDisabledForTreeOptions( - handleTree(deptResponse.data), - "status" - ); - - const postResponse = await getPostListApi({}); - postOptions.value = postResponse.data.rows; - const roleResponse = await getRoleListApi({}); roleOptions.value = roleResponse.data.rows; }); diff --git a/frontend/web/src/views/system/user/index.vue b/frontend/web/src/views/system/user/index.vue index 272a71d..d4519b5 100644 --- a/frontend/web/src/views/system/user/index.vue +++ b/frontend/web/src/views/system/user/index.vue @@ -1,6 +1,5 @@