Compare commits
10 Commits
1f2f11f80f
...
731d7420f1
| Author | SHA1 | Date | |
|---|---|---|---|
| 731d7420f1 | |||
| 3a6f764819 | |||
| 0989bb2209 | |||
| 3d77f7a3dc | |||
|
|
8a1cf9ed55 | ||
|
|
600e06904b | ||
|
|
6281609d9e | ||
|
|
2cf825dd3d | ||
|
|
245baa705b | ||
|
|
cfe076ebd0 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -45,3 +45,7 @@ nbdist/
|
|||||||
!*/build/*.java
|
!*/build/*.java
|
||||||
!*/build/*.html
|
!*/build/*.html
|
||||||
!*/build/*.xml
|
!*/build/*.xml
|
||||||
|
|
||||||
|
# 项目运行时生成的目录
|
||||||
|
uploads/
|
||||||
|
logs/
|
||||||
|
|||||||
150
CLAUDE.md
Normal file
150
CLAUDE.md
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
RuoYi-Vue v3.9.1 is a rapid development platform with Spring Boot + Vue.js separated architecture. It provides a complete admin dashboard system with JWT authentication, role-based access control, code generation, and 18 built-in functional modules.
|
||||||
|
|
||||||
|
**Technology Stack:**
|
||||||
|
- Backend: Spring Boot 2.5.15, Spring Security 5.7.14, MyBatis, Redis, JWT
|
||||||
|
- Frontend: Vue 2.6.12, Element UI 2.15.14, Vuex 3.6.0, Vue Router 3.4.9
|
||||||
|
- Database: MySQL with Druid connection pool
|
||||||
|
- Build: Maven (backend), Vue CLI 4.4.6 (frontend)
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
RuoYi-Vue/
|
||||||
|
├── pom.xml # Root Maven configuration
|
||||||
|
├── ruoyi-admin/ # Web service entry point (Controllers, Config)
|
||||||
|
├── ruoyi-framework/ # Core framework (Security, AOP, Interceptors)
|
||||||
|
├── ruoyi-system/ # System business logic (Services, Mappers)
|
||||||
|
├── ruoyi-common/ # Common utilities, constants, exceptions
|
||||||
|
├── ruoyi-quartz/ # Scheduled tasks module
|
||||||
|
├── ruoyi-generator/ # Code generation module
|
||||||
|
└── ruoyi-ui/ # Frontend Vue.js application
|
||||||
|
├── package.json
|
||||||
|
├── vue.config.js # Webpack config with proxy to backend
|
||||||
|
├── .env.development # Dev environment (VUE_APP_BASE_API=/dev-api)
|
||||||
|
├── .env.production # Prod environment (VUE_APP_BASE_API=/prod-api)
|
||||||
|
└── src/
|
||||||
|
├── api/ # API service layer
|
||||||
|
├── components/ # Reusable components
|
||||||
|
├── directive/ # Custom directives (permission, etc.)
|
||||||
|
├── layout/ # Layout components
|
||||||
|
├── plugins/ # Plugins (cache, modal, download)
|
||||||
|
├── router/ # Vue Router configuration
|
||||||
|
├── store/ # Vuex store modules
|
||||||
|
├── utils/ # Utility functions
|
||||||
|
└── views/ # Page views (login, system, monitor, tool)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
### Backend (Maven)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Package application (skips tests)
|
||||||
|
mvn clean package -Dmaven.test.skip=true
|
||||||
|
|
||||||
|
# Run application from JAR
|
||||||
|
cd ruoyi-admin/target
|
||||||
|
java -jar ruoyi-admin.jar
|
||||||
|
|
||||||
|
# Or use provided scripts from project root
|
||||||
|
./ry.sh start|stop|restart|status # Unix
|
||||||
|
ry.bat # Windows
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend (npm)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ruoyi-ui
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Development server (runs on port 80, proxies /dev-api to localhost:8080)
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Production build
|
||||||
|
npm run build:prod
|
||||||
|
|
||||||
|
# Staging build
|
||||||
|
npm run build:stage
|
||||||
|
|
||||||
|
# Preview production build
|
||||||
|
npm run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture Patterns
|
||||||
|
|
||||||
|
### Backend Architecture
|
||||||
|
|
||||||
|
**Module Dependencies:**
|
||||||
|
- `ruoyi-admin` → `ruoyi-framework` → `ruoyi-system` → `ruoyi-common`
|
||||||
|
- `ruoyi-generator` and `ruoyi-quartz` are independent modules
|
||||||
|
|
||||||
|
**Key Patterns:**
|
||||||
|
1. **Layered Architecture:** Controller → Service → Mapper → Domain
|
||||||
|
2. **Security:** JWT + Spring Security with role-based access control
|
||||||
|
3. **Dynamic Datasource:** Primary/secondary database support via Druid
|
||||||
|
4. **AOP:** Aspect-oriented logging (`@Log` annotation) and data scope filtering
|
||||||
|
5. **Global Exception Handling:** `GlobalExceptionHandler` with `AjaxResult` wrapper
|
||||||
|
6. **XSS Prevention:** Built-in XSS filtering via `XssFilter`
|
||||||
|
7. **Repeat Submit Prevention:** `@RepeatSubmit` annotation with interceptor
|
||||||
|
|
||||||
|
**Key Files:**
|
||||||
|
- `ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java` - Entry point
|
||||||
|
- `ruoyi-admin/src/main/resources/application.yml` - Main configuration
|
||||||
|
- `ruoyi-admin/src/main/resources/application-druid.yml` - Database configuration
|
||||||
|
- `ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java` - Security config
|
||||||
|
- `ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java` - Logging aspect
|
||||||
|
|
||||||
|
### Frontend Architecture
|
||||||
|
|
||||||
|
**Key Patterns:**
|
||||||
|
1. **Route Guards:** `permission.js` handles JWT token validation and dynamic route generation
|
||||||
|
2. **Axios Interceptors:** Request/response handling in `utils/request.js`
|
||||||
|
3. **Global Methods:** Mounted on Vue prototype (e.g., `this.getDicts()`, `this.parseTime()`)
|
||||||
|
4. **Global Components:** `DictTag`, `Pagination`, `RightToolbar`, `Editor`, `FileUpload`, `ImageUpload`
|
||||||
|
5. **Store Modules:** `user`, `app`, `tagsView`, `permission`, `settings`
|
||||||
|
6. **Directives:** `v-hasPermi`, `v-hasRole`, `v-debounce`, `v-copy`, `v-ellipsis`
|
||||||
|
|
||||||
|
**API Proxy Configuration:**
|
||||||
|
- Development: `/dev-api` → `http://localhost:8080`
|
||||||
|
- Production: `/prod-api` → configured via nginx or context
|
||||||
|
|
||||||
|
**Key Files:**
|
||||||
|
- `ruoyi-ui/src/main.js` - Entry point with global registrations
|
||||||
|
- `ruoyi-ui/src/permission.js` - Route permission control
|
||||||
|
- `ruoyi-ui/src/utils/request.js` - Axios configuration
|
||||||
|
- `ruoyi-ui/src/utils/ruoyi.js` - Common utility functions
|
||||||
|
- `ruoyi-ui/src/store/modules/permission.js` - Dynamic route generation
|
||||||
|
|
||||||
|
## Code Generation
|
||||||
|
|
||||||
|
The code generator creates CRUD operations from database tables:
|
||||||
|
|
||||||
|
1. Access the generator UI at System → Code Generator
|
||||||
|
2. Import a table from the database
|
||||||
|
3. Configure field types, validation, and UI options
|
||||||
|
4. Generate code (creates backend + frontend files)
|
||||||
|
5. Copy generated files to appropriate directories
|
||||||
|
|
||||||
|
Templates are in `ruoyi-generator/src/main/resources/vm/`
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
- Main schema: `sql/ry_20250522.sql`
|
||||||
|
- Quartz tables: `sql/quartz.sql`
|
||||||
|
- Default login: admin/admin123
|
||||||
|
|
||||||
|
## Common Development Notes
|
||||||
|
|
||||||
|
- Backend runs on port 8080 by default
|
||||||
|
- Frontend dev server runs on port 80 with proxy to backend
|
||||||
|
- Swagger API docs available at `/swagger-ui/index.html` when enabled
|
||||||
|
- Redis required for caching and session storage
|
||||||
|
- File upload path configured in `application.yml` under `ruoyi.profile`
|
||||||
22
README.md
22
README.md
@ -18,9 +18,8 @@
|
|||||||
* 权限认证使用Jwt,支持多终端认证系统。
|
* 权限认证使用Jwt,支持多终端认证系统。
|
||||||
* 支持加载动态权限菜单,多方式轻松权限控制。
|
* 支持加载动态权限菜单,多方式轻松权限控制。
|
||||||
* 高效率开发,使用代码生成器可以一键生成前后端代码。
|
* 高效率开发,使用代码生成器可以一键生成前后端代码。
|
||||||
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
|
* 提供了技术栈(Vue3 Element Plus Vite)的 [RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3)版本,以及技术栈(TypeScript)的 [RuoYi-Vue3-TypeScript](https://gitcode.com/yangzongzhuan/RuoYi-Vue3/tree/typescript)版本,两者保持同步更新。
|
||||||
* 提供了单应用版本[RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast),Oracle版本[RuoYi-Vue-Oracle](https://gitcode.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
|
* 提供了适配 Spring Boot 3 的版本分支 [RuoYi-Vue (springboot3)](https://gitee.com/y_project/RuoYi-Vue/tree/springboot3),以及特定需求的 单应用版本 [RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast) 与 Oracle数据库版本 [RuoYi-Vue-Oracle](https://gitcode.com/yangzongzhuan/RuoYi-Vue-Oracle),均保持同步更新。
|
||||||
* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
|
|
||||||
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)
|
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)
|
||||||
|
|
||||||
## 内置功能
|
## 内置功能
|
||||||
@ -44,6 +43,21 @@
|
|||||||
17. 在线构建器:拖动表单元素生成相应的HTML代码。
|
17. 在线构建器:拖动表单元素生成相应的HTML代码。
|
||||||
18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
|
18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
|
||||||
|
|
||||||
|
# 版本对比
|
||||||
|
|
||||||
|
RuoYi-Vue 前端项目的三个主要演进版本,方便你直观对比其技术栈差异(并行开发维护)。
|
||||||
|
|
||||||
|
| 项目名称 | **RuoYi-Vue** | **RuoYi-Vue3** | **RuoYi-Vue3-TypeScript** |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **前端框架** | Vue 2 | Vue 3 | Vue 3 |
|
||||||
|
| **脚本语言** | JavaScript | JavaScript | TypeScript |
|
||||||
|
| **构建工具** | Vue CLI | Vite | Vite |
|
||||||
|
| **UI 组件库** | Element UI | Element Plus | Element Plus |
|
||||||
|
| **状态管理** | Vuex | Pinia | Pinia |
|
||||||
|
| **路由管理** | Vue Router 3 | Vue Router 4 | Vue Router 4 |
|
||||||
|
| **核心特点** | 1. 技术栈经典稳定<br>2. 社区资料丰富<br>3. 当前维护重心已转移 | 1. 现代前端技术栈<br>2. 开发体验与性能更优<br>3. 官方主推的活跃版本 | 1. 类型加持,减少沟通成本<br>2. 开发时有提示,效率更高<br>3. 多人协作企业级开发项目 |
|
||||||
|
| **仓库地址** | [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) | [RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3) | [RuoYi-Vue3-TypeScript](https://gitcode.com/yangzongzhuan/RuoYi-Vue3/tree/typescript) |
|
||||||
|
|
||||||
## 在线体验
|
## 在线体验
|
||||||
|
|
||||||
- admin/admin123
|
- admin/admin123
|
||||||
@ -92,4 +106,4 @@
|
|||||||
|
|
||||||
## 若依前后端分离交流群
|
## 若依前后端分离交流群
|
||||||
|
|
||||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [](https://jq.qq.com/?_wv=1027&k=SpyH2875) [](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) 点击按钮入群。
|
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [](https://jq.qq.com/?_wv=1027&k=SpyH2875) [](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=M9y5NjAl44lAL_Vh2crmEehZU_PMU6KS&authKey=ZSDz8hEREWSaPuxQV3gEwqGIaGjfRNnkB4rJjf0IvXhrSUGSGwQFmBA%2Boe8HFxyl&noverify=0&group_code=127358632) 点击按钮入群。
|
||||||
79
docker-compose.yml
Normal file
79
docker-compose.yml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: ruoyi-mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: password
|
||||||
|
MYSQL_DATABASE: ry-vue
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
- ./sql/ry_20250522.sql:/docker-entrypoint-initdb.d/01-ry_20250522.sql
|
||||||
|
- ./sql/quartz.sql:/docker-entrypoint-initdb.d/02-quartz.sql
|
||||||
|
command: >
|
||||||
|
--default-authentication-plugin=mysql_native_password
|
||||||
|
--character-set-server=utf8mb4
|
||||||
|
--collation-server=utf8mb4_unicode_ci
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-ppassword"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: ruoyi-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin:5
|
||||||
|
container_name: ruoyi-phpmyadmin
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8081:80"
|
||||||
|
environment:
|
||||||
|
PMA_HOST: mysql
|
||||||
|
PMA_PORT: 3306
|
||||||
|
MYSQL_ROOT_PASSWORD: password
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
|
||||||
|
redisinsight:
|
||||||
|
image: redis/redisinsight:2.64
|
||||||
|
container_name: ruoyi-redisinsight
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8001:5540"
|
||||||
|
volumes:
|
||||||
|
- redisinsight_data:/data
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql_data:
|
||||||
|
redis_data:
|
||||||
|
redisinsight_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
ruoyi-network:
|
||||||
|
driver: bridge
|
||||||
@ -93,6 +93,10 @@ public class SysMenuController extends BaseController
|
|||||||
{
|
{
|
||||||
return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
|
return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
|
||||||
}
|
}
|
||||||
|
else if (!menuService.checkRouteConfigUnique(menu))
|
||||||
|
{
|
||||||
|
return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
|
||||||
|
}
|
||||||
menu.setCreateBy(getUsername());
|
menu.setCreateBy(getUsername());
|
||||||
return toAjax(menuService.insertMenu(menu));
|
return toAjax(menuService.insertMenu(menu));
|
||||||
}
|
}
|
||||||
@ -117,6 +121,10 @@ public class SysMenuController extends BaseController
|
|||||||
{
|
{
|
||||||
return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
|
return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
|
||||||
}
|
}
|
||||||
|
else if (!menuService.checkRouteConfigUnique(menu))
|
||||||
|
{
|
||||||
|
return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
|
||||||
|
}
|
||||||
menu.setUpdateBy(getUsername());
|
menu.setUpdateBy(getUsername());
|
||||||
return toAjax(menuService.updateMenu(menu));
|
return toAjax(menuService.updateMenu(menu));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,8 @@ ruoyi:
|
|||||||
version: 3.9.1
|
version: 3.9.1
|
||||||
# 版权年份
|
# 版权年份
|
||||||
copyrightYear: 2026
|
copyrightYear: 2026
|
||||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
# 文件路径(相对路径,基于项目根目录)
|
||||||
profile: D:/ruoyi/uploadPath
|
profile: ./uploads
|
||||||
# 获取ip地址开关
|
# 获取ip地址开关
|
||||||
addressEnabled: false
|
addressEnabled: false
|
||||||
# 验证码类型 math 数字计算 char 字符验证
|
# 验证码类型 math 数字计算 char 字符验证
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- 日志存放路径 -->
|
<!-- 日志存放路径 -->
|
||||||
<property name="log.path" value="/home/ruoyi/logs" />
|
<property name="log.path" value="./logs" />
|
||||||
<!-- 日志输出格式 -->
|
<!-- 日志输出格式 -->
|
||||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||||
|
|
||||||
|
|||||||
@ -122,4 +122,13 @@ public interface SysMenuMapper
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
|
public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据路由路径或名称查询菜单信息(用于唯一性校验)
|
||||||
|
*
|
||||||
|
* @param path 路由地址
|
||||||
|
* @param routeName 路由名称
|
||||||
|
* @return 匹配的菜单列表
|
||||||
|
*/
|
||||||
|
public List<SysMenu> selectMenusByPathOrRouteName(@Param("path") String path, @Param("routeName") String routeName);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,4 +141,12 @@ public interface ISysMenuService
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public boolean checkMenuNameUnique(SysMenu menu);
|
public boolean checkMenuNameUnique(SysMenu menu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验路由组合是否唯一
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public boolean checkRouteConfigUnique(SysMenu menu);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
@ -32,8 +34,12 @@ import com.ruoyi.system.service.ISysMenuService;
|
|||||||
@Service
|
@Service
|
||||||
public class SysMenuServiceImpl implements ISysMenuService
|
public class SysMenuServiceImpl implements ISysMenuService
|
||||||
{
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SysMenuServiceImpl.class);
|
||||||
|
|
||||||
public static final String PREMISSION_STRING = "perms[\"{0}\"]";
|
public static final String PREMISSION_STRING = "perms[\"{0}\"]";
|
||||||
|
|
||||||
|
public static final Long MENU_ROOT_ID = 0L;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SysMenuMapper menuMapper;
|
private SysMenuMapper menuMapper;
|
||||||
|
|
||||||
@ -138,7 +144,7 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
{
|
{
|
||||||
menus = menuMapper.selectMenuTreeByUserId(userId);
|
menus = menuMapper.selectMenuTreeByUserId(userId);
|
||||||
}
|
}
|
||||||
return getChildPerms(menus, 0);
|
return getChildPerms(menus, MENU_ROOT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,7 +199,7 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
childrenList.add(children);
|
childrenList.add(children);
|
||||||
router.setChildren(childrenList);
|
router.setChildren(childrenList);
|
||||||
}
|
}
|
||||||
else if (menu.getParentId().intValue() == 0 && isInnerLink(menu))
|
else if (menu.getParentId().intValue() == MENU_ROOT_ID && isInnerLink(menu))
|
||||||
{
|
{
|
||||||
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
|
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
|
||||||
router.setPath("/");
|
router.setPath("/");
|
||||||
@ -345,6 +351,47 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
return UserConstants.UNIQUE;
|
return UserConstants.UNIQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验路由名称是否唯一
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean checkRouteConfigUnique(SysMenu menu)
|
||||||
|
{
|
||||||
|
Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
|
||||||
|
Long parentId = menu.getParentId();
|
||||||
|
String path = menu.getPath();
|
||||||
|
String routeName = StringUtils.isEmpty(menu.getRouteName()) ? path : menu.getRouteName();
|
||||||
|
List<SysMenu> sysMenuList = menuMapper.selectMenusByPathOrRouteName(path, routeName);
|
||||||
|
for (SysMenu sysMenu : sysMenuList)
|
||||||
|
{
|
||||||
|
if (sysMenu.getMenuId().longValue() != menuId.longValue())
|
||||||
|
{
|
||||||
|
Long dbParentId = sysMenu.getParentId();
|
||||||
|
String dbPath = sysMenu.getPath();
|
||||||
|
String dbRouteName = StringUtils.isEmpty(sysMenu.getRouteName()) ? dbPath : sysMenu.getRouteName();
|
||||||
|
if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == dbParentId.longValue())
|
||||||
|
{
|
||||||
|
log.warn("[同级路由冲突] 同级下已存在相同路由路径 '{}',冲突菜单:{}", dbPath, sysMenu.getMenuName());
|
||||||
|
return UserConstants.NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
else if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == MENU_ROOT_ID)
|
||||||
|
{
|
||||||
|
log.warn("[根目录路由冲突] 根目录下路由 '{}' 必须唯一,已被菜单 '{}' 占用", path, sysMenu.getMenuName());
|
||||||
|
return UserConstants.NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
else if (StringUtils.equalsAnyIgnoreCase(routeName, dbRouteName))
|
||||||
|
{
|
||||||
|
log.warn("[路由名称冲突] 路由名称 '{}' 需全局唯一,已被菜单 '{}' 使用", routeName, sysMenu.getMenuName());
|
||||||
|
return UserConstants.NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UserConstants.UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取路由名称
|
* 获取路由名称
|
||||||
*
|
*
|
||||||
@ -384,12 +431,12 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
{
|
{
|
||||||
String routerPath = menu.getPath();
|
String routerPath = menu.getPath();
|
||||||
// 内链打开外网方式
|
// 内链打开外网方式
|
||||||
if (menu.getParentId().intValue() != 0 && isInnerLink(menu))
|
if (menu.getParentId().intValue() != MENU_ROOT_ID && isInnerLink(menu))
|
||||||
{
|
{
|
||||||
routerPath = innerLinkReplaceEach(routerPath);
|
routerPath = innerLinkReplaceEach(routerPath);
|
||||||
}
|
}
|
||||||
// 非外链并且是一级目录(类型为目录)
|
// 非外链并且是一级目录(类型为目录)
|
||||||
if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
|
if (MENU_ROOT_ID == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
|
||||||
&& UserConstants.NO_FRAME.equals(menu.getIsFrame()))
|
&& UserConstants.NO_FRAME.equals(menu.getIsFrame()))
|
||||||
{
|
{
|
||||||
routerPath = "/" + menu.getPath();
|
routerPath = "/" + menu.getPath();
|
||||||
@ -415,7 +462,7 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
{
|
{
|
||||||
component = menu.getComponent();
|
component = menu.getComponent();
|
||||||
}
|
}
|
||||||
else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu))
|
else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != MENU_ROOT_ID && isInnerLink(menu))
|
||||||
{
|
{
|
||||||
component = UserConstants.INNER_LINK;
|
component = UserConstants.INNER_LINK;
|
||||||
}
|
}
|
||||||
@ -434,10 +481,21 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
*/
|
*/
|
||||||
public boolean isMenuFrame(SysMenu menu)
|
public boolean isMenuFrame(SysMenu menu)
|
||||||
{
|
{
|
||||||
return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType())
|
return menu.getParentId().intValue() == MENU_ROOT_ID && UserConstants.TYPE_MENU.equals(menu.getMenuType())
|
||||||
&& menu.getIsFrame().equals(UserConstants.NO_FRAME);
|
&& menu.getIsFrame().equals(UserConstants.NO_FRAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为parent_view组件
|
||||||
|
*
|
||||||
|
* @param menu 菜单信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public boolean isParentView(SysMenu menu)
|
||||||
|
{
|
||||||
|
return menu.getParentId().intValue() != MENU_ROOT_ID && UserConstants.TYPE_DIR.equals(menu.getMenuType());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否为内链组件
|
* 是否为内链组件
|
||||||
*
|
*
|
||||||
@ -449,17 +507,6 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath());
|
return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为parent_view组件
|
|
||||||
*
|
|
||||||
* @param menu 菜单信息
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public boolean isParentView(SysMenu menu)
|
|
||||||
{
|
|
||||||
return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据父节点的ID获取所有子节点
|
* 根据父节点的ID获取所有子节点
|
||||||
*
|
*
|
||||||
@ -467,7 +514,7 @@ public class SysMenuServiceImpl implements ISysMenuService
|
|||||||
* @param parentId 传入的父节点ID
|
* @param parentId 传入的父节点ID
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId)
|
public List<SysMenu> getChildPerms(List<SysMenu> list, long parentId)
|
||||||
{
|
{
|
||||||
List<SysMenu> returnList = new ArrayList<SysMenu>();
|
List<SysMenu> returnList = new ArrayList<SysMenu>();
|
||||||
for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)
|
for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)
|
||||||
|
|||||||
@ -133,6 +133,11 @@
|
|||||||
where menu_name= #{menuName} and parent_id = #{parentId} limit 1
|
where menu_name= #{menuName} and parent_id = #{parentId} limit 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectMenusByPathOrRouteName" parameterType="SysMenu" resultMap="SysMenuResult">
|
||||||
|
<include refid="selectMenuVo"/>
|
||||||
|
where menu_type in ('M', 'C') and (path = #{path} or path = #{routeName} or route_name = #{path} or route_name = #{routeName})
|
||||||
|
</select>
|
||||||
|
|
||||||
<update id="updateMenu" parameterType="SysMenu">
|
<update id="updateMenu" parameterType="SysMenu">
|
||||||
update sys_menu
|
update sys_menu
|
||||||
<set>
|
<set>
|
||||||
|
|||||||
@ -68,5 +68,6 @@
|
|||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions"
|
"last 2 versions"
|
||||||
]
|
],
|
||||||
|
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
|
||||||
}
|
}
|
||||||
|
|||||||
11342
ruoyi-ui/pnpm-lock.yaml
Normal file
11342
ruoyi-ui/pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
5
ruoyi-ui/pnpm-workspace.yaml
Normal file
5
ruoyi-ui/pnpm-workspace.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
onlyBuiltDependencies:
|
||||||
|
- core-js
|
||||||
|
- ejs
|
||||||
|
- fsevents
|
||||||
|
- highlight.js
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import { parseStrEmpty } from "@/utils/ruoyi";
|
import { parseStrEmpty } from "@/utils/ruoyi"
|
||||||
|
|
||||||
// 查询用户列表
|
// 查询用户列表
|
||||||
export function listUser(query) {
|
export function listUser(query) {
|
||||||
|
|||||||
@ -118,8 +118,6 @@ export default {
|
|||||||
this.fuse = new Fuse(list, {
|
this.fuse = new Fuse(list, {
|
||||||
shouldSort: true,
|
shouldSort: true,
|
||||||
threshold: 0.4,
|
threshold: 0.4,
|
||||||
location: 0,
|
|
||||||
distance: 100,
|
|
||||||
minMatchCharLength: 1,
|
minMatchCharLength: 1,
|
||||||
keys: [{
|
keys: [{
|
||||||
name: 'title',
|
name: 'title',
|
||||||
|
|||||||
@ -26,6 +26,8 @@ service.interceptors.request.use(config => {
|
|||||||
const isToken = (config.headers || {}).isToken === false
|
const isToken = (config.headers || {}).isToken === false
|
||||||
// 是否需要防止数据重复提交
|
// 是否需要防止数据重复提交
|
||||||
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
|
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
|
||||||
|
// 间隔时间(ms),小于此时间视为重复提交
|
||||||
|
const interval = (config.headers || {}).interval || 1000
|
||||||
if (getToken() && !isToken) {
|
if (getToken() && !isToken) {
|
||||||
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||||
}
|
}
|
||||||
@ -55,7 +57,6 @@ service.interceptors.request.use(config => {
|
|||||||
const s_url = sessionObj.url // 请求地址
|
const s_url = sessionObj.url // 请求地址
|
||||||
const s_data = sessionObj.data // 请求数据
|
const s_data = sessionObj.data // 请求数据
|
||||||
const s_time = sessionObj.time // 请求时间
|
const s_time = sessionObj.time // 请求时间
|
||||||
const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
|
|
||||||
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
|
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
|
||||||
const message = '数据正在处理,请勿重复提交'
|
const message = '数据正在处理,请勿重复提交'
|
||||||
console.warn(`[${s_url}]: ` + message)
|
console.warn(`[${s_url}]: ` + message)
|
||||||
@ -115,7 +116,7 @@ service.interceptors.response.use(res => {
|
|||||||
} else if (message.includes("timeout")) {
|
} else if (message.includes("timeout")) {
|
||||||
message = "系统接口请求超时"
|
message = "系统接口请求超时"
|
||||||
} else if (message.includes("Request failed with status code")) {
|
} else if (message.includes("Request failed with status code")) {
|
||||||
message = "系统接口" + message.substr(message.length - 3) + "异常"
|
message = "系统接口" + message.slice(-3) + "异常"
|
||||||
}
|
}
|
||||||
Message({ message: message, type: 'error', duration: 5 * 1000 })
|
Message({ message: message, type: 'error', duration: 5 * 1000 })
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
|
|||||||
@ -88,7 +88,7 @@
|
|||||||
<s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s>
|
<s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s>
|
||||||
<s> 满161281055 </s> <s> 满138988063 </s> <s> 满151450850 </s> <s> 满224622315 </s>
|
<s> 满161281055 </s> <s> 满138988063 </s> <s> 满151450850 </s> <s> 满224622315 </s>
|
||||||
<s> 满287842588 </s> <s> 满187944233 </s> <s> 满228578329 </s> <s> 满191164766 </s>
|
<s> 满287842588 </s> <s> 满187944233 </s> <s> 满228578329 </s> <s> 满191164766 </s>
|
||||||
<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=EeCBXu51I1zPWRia2uskpjDRx6VrbnFN&authKey=Xm8yDxk0%2FyYGI11oxhXaQnTn4K7UwCk7Kn2MZTh3P1JxLctollAkyeySjnaILDkb&noverify=0&group_code=174569686" target="_blank">174569686</a>
|
<s> 满174569686 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=M9y5NjAl44lAL_Vh2crmEehZU_PMU6KS&authKey=ZSDz8hEREWSaPuxQV3gEwqGIaGjfRNnkB4rJjf0IvXhrSUGSGwQFmBA%2Boe8HFxyl&noverify=0&group_code=127358632" target="_blank">127358632</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<i class="el-icon-chat-dot-round"></i> 微信:<a
|
<i class="el-icon-chat-dot-round"></i> 微信:<a
|
||||||
|
|||||||
@ -477,13 +477,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.jobId != undefined) {
|
if (this.form.jobId != undefined) {
|
||||||
updateJob(this.form).then(response => {
|
updateJob(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addJob(this.form).then(response => {
|
addJob(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -128,7 +128,7 @@ export default {
|
|||||||
this.$refs.registerForm.validate(valid => {
|
this.$refs.registerForm.validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
register(this.registerForm).then(res => {
|
register(this.registerForm).then(() => {
|
||||||
const username = this.registerForm.username
|
const username = this.registerForm.username
|
||||||
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
|
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
|
|||||||
@ -301,13 +301,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.configId != undefined) {
|
if (this.form.configId != undefined) {
|
||||||
updateConfig(this.form).then(response => {
|
updateConfig(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addConfig(this.form).then(response => {
|
addConfig(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -311,13 +311,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.deptId != undefined) {
|
if (this.form.deptId != undefined) {
|
||||||
updateDept(this.form).then(response => {
|
updateDept(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addDept(this.form).then(response => {
|
addDept(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -363,14 +363,14 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.dictCode != undefined) {
|
if (this.form.dictCode != undefined) {
|
||||||
updateData(this.form).then(response => {
|
updateData(this.form).then(() => {
|
||||||
this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
|
this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addData(this.form).then(response => {
|
addData(this.form).then(() => {
|
||||||
this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
|
this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
|
|||||||
@ -304,13 +304,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.dictId != undefined) {
|
if (this.form.dictId != undefined) {
|
||||||
updateType(this.form).then(response => {
|
updateType(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addType(this.form).then(response => {
|
addType(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -448,13 +448,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.menuId != undefined) {
|
if (this.form.menuId != undefined) {
|
||||||
updateMenu(this.form).then(response => {
|
updateMenu(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addMenu(this.form).then(response => {
|
addMenu(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -282,13 +282,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.noticeId != undefined) {
|
if (this.form.noticeId != undefined) {
|
||||||
updateNotice(this.form).then(response => {
|
updateNotice(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addNotice(this.form).then(response => {
|
addNotice(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -273,13 +273,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.postId != undefined) {
|
if (this.form.postId != undefined) {
|
||||||
updatePost(this.form).then(response => {
|
updatePost(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addPost(this.form).then(response => {
|
addPost(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -184,7 +184,7 @@ export default {
|
|||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
/** 批量取消授权按钮操作 */
|
/** 批量取消授权按钮操作 */
|
||||||
cancelAuthUserAll(row) {
|
cancelAuthUserAll() {
|
||||||
const roleId = this.queryParams.roleId
|
const roleId = this.queryParams.roleId
|
||||||
const userIds = this.userIds.join(",")
|
const userIds = this.userIds.join(",")
|
||||||
this.$modal.confirm('是否取消选中用户授权数据项?').then(function() {
|
this.$modal.confirm('是否取消选中用户授权数据项?').then(function() {
|
||||||
|
|||||||
@ -557,14 +557,14 @@ export default {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.roleId != undefined) {
|
if (this.form.roleId != undefined) {
|
||||||
this.form.menuIds = this.getMenuAllCheckedKeys()
|
this.form.menuIds = this.getMenuAllCheckedKeys()
|
||||||
updateRole(this.form).then(response => {
|
updateRole(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.form.menuIds = this.getMenuAllCheckedKeys()
|
this.form.menuIds = this.getMenuAllCheckedKeys()
|
||||||
addRole(this.form).then(response => {
|
addRole(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
@ -577,7 +577,7 @@ export default {
|
|||||||
submitDataScope: function() {
|
submitDataScope: function() {
|
||||||
if (this.form.roleId != undefined) {
|
if (this.form.roleId != undefined) {
|
||||||
this.form.deptIds = this.getDeptAllCheckedKeys()
|
this.form.deptIds = this.getDeptAllCheckedKeys()
|
||||||
dataScope(this.form).then(response => {
|
dataScope(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.openDataScope = false
|
this.openDataScope = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -108,7 +108,7 @@ export default {
|
|||||||
submitForm() {
|
submitForm() {
|
||||||
const userId = this.form.userId
|
const userId = this.form.userId
|
||||||
const roleIds = this.roleIds.join(",")
|
const roleIds = this.roleIds.join(",")
|
||||||
updateAuthRole({ userId: userId, roleIds: roleIds }).then((response) => {
|
updateAuthRole({ userId: userId, roleIds: roleIds }).then(() => {
|
||||||
this.$modal.msgSuccess("授权成功")
|
this.$modal.msgSuccess("授权成功")
|
||||||
this.close()
|
this.close()
|
||||||
})
|
})
|
||||||
|
|||||||
@ -476,7 +476,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}).then(({ value }) => {
|
}).then(({ value }) => {
|
||||||
resetUserPwd(row.userId, value).then(response => {
|
resetUserPwd(row.userId, value).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功,新密码是:" + value)
|
this.$modal.msgSuccess("修改成功,新密码是:" + value)
|
||||||
})
|
})
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
@ -491,13 +491,13 @@ export default {
|
|||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.userId != undefined) {
|
if (this.form.userId != undefined) {
|
||||||
updateUser(this.form).then(response => {
|
updateUser(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addUser(this.form).then(response => {
|
addUser(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("新增成功")
|
this.$modal.msgSuccess("新增成功")
|
||||||
this.open = false
|
this.open = false
|
||||||
this.getList()
|
this.getList()
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export default {
|
|||||||
submit() {
|
submit() {
|
||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
|
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,7 +72,7 @@ export default {
|
|||||||
submit() {
|
submit() {
|
||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
updateUserProfile(this.form).then(response => {
|
updateUserProfile(this.form).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
this.user.phonenumber = this.form.phonenumber
|
this.user.phonenumber = this.form.phonenumber
|
||||||
this.user.email = this.form.email
|
this.user.email = this.form.email
|
||||||
|
|||||||
@ -98,9 +98,9 @@
|
|||||||
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
|
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" width="120" />
|
<el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" width="140" />
|
||||||
<el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" width="120" />
|
<el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" width="140" />
|
||||||
<el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" width="120" />
|
<el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" width="140" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="160" />
|
<el-table-column label="创建时间" align="center" prop="createTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="160" />
|
||||||
<el-table-column label="更新时间" align="center" prop="updateTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="160" />
|
<el-table-column label="更新时间" align="center" prop="updateTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="160" />
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
@ -262,7 +262,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(row.genType === "1") {
|
if(row.genType === "1") {
|
||||||
genCode(row.tableName).then(response => {
|
genCode(row.tableName).then(() => {
|
||||||
this.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath)
|
this.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
SET NAMES 'utf8';
|
||||||
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
|
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
|
||||||
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
|
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
|
||||||
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
|
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
SET NAMES 'utf8';
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 1、部门表
|
-- 1、部门表
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user