Compare commits

..

10 Commits

Author SHA1 Message Date
731d7420f1 修复sql初始化的编码问题 2026-01-31 20:23:29 +08:00
3a6f764819 pnpm install 2026-01-31 20:11:00 +08:00
0989bb2209 修改配置文件,使用docker启动mysql和redis 2026-01-31 20:01:06 +08:00
3d77f7a3dc 添加 CLAUDE.md 文件,为 Claude Code 提供项目开发指南
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 02:00:37 +08:00
RuoYi
8a1cf9ed55 update README.md 2026-01-28 14:27:46 +08:00
RuoYi
600e06904b update README.md 2026-01-28 13:59:34 +08:00
RuoYi
6281609d9e 添加新群号:127358632 2026-01-28 13:49:51 +08:00
RuoYi
2cf825dd3d 优化代码 2026-01-28 13:42:42 +08:00
RuoYi
245baa705b 添加菜单路由地址和名称的校验规则 2026-01-09 11:13:58 +08:00
RuoYi
cfe076ebd0 优化防重提交间隔时间可自定义 2026-01-08 13:39:16 +08:00
36 changed files with 11737 additions and 64 deletions

4
.gitignore vendored
View File

@ -45,3 +45,7 @@ nbdist/
!*/build/*.java
!*/build/*.html
!*/build/*.xml
# 项目运行时生成的目录
uploads/
logs/

150
CLAUDE.md Normal file
View 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`

View File

@ -18,9 +18,8 @@
* 权限认证使用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),保持同步更新。
* 提供了单应用版本[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)
* 提供了技术栈Vue3 Element Plus Vite的 [RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3)版本以及技术栈TypeScript的 [RuoYi-Vue3-TypeScript](https://gitcode.com/yangzongzhuan/RuoYi-Vue3/tree/typescript)版本,两者保持同步更新。
* 提供了适配 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),均保持同步更新。
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
## 内置功能
@ -44,6 +43,21 @@
17. 在线构建器拖动表单元素生成相应的HTML代码。
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
@ -92,4 +106,4 @@
## 若依前后端分离交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/已满-136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [![加入QQ群](https://img.shields.io/badge/已满-143961921-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [![加入QQ群](https://img.shields.io/badge/已满-174951577-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [![加入QQ群](https://img.shields.io/badge/已满-161281055-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [![加入QQ群](https://img.shields.io/badge/已满-138988063-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [![加入QQ群](https://img.shields.io/badge/已满-151450850-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [![加入QQ群](https://img.shields.io/badge/已满-224622315-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [![加入QQ群](https://img.shields.io/badge/已满-287842588-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [![加入QQ群](https://img.shields.io/badge/已满-187944233-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [![加入QQ群](https://img.shields.io/badge/已满-228578329-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [![加入QQ群](https://img.shields.io/badge/已满-191164766-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [![加入QQ群](https://img.shields.io/badge/174569686-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) 点击按钮入群。
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/已满-136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [![加入QQ群](https://img.shields.io/badge/已满-143961921-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [![加入QQ群](https://img.shields.io/badge/已满-174951577-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [![加入QQ群](https://img.shields.io/badge/已满-161281055-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [![加入QQ群](https://img.shields.io/badge/已满-138988063-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [![加入QQ群](https://img.shields.io/badge/已满-151450850-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [![加入QQ群](https://img.shields.io/badge/已满-224622315-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [![加入QQ群](https://img.shields.io/badge/已满-287842588-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [![加入QQ群](https://img.shields.io/badge/已满-187944233-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [![加入QQ群](https://img.shields.io/badge/已满-228578329-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [![加入QQ群](https://img.shields.io/badge/已满-191164766-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [![加入QQ群](https://img.shields.io/badge/已满-174569686-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) [![加入QQ群](https://img.shields.io/badge/127358632-blue.svg)](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
View 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

View File

@ -93,6 +93,10 @@ public class SysMenuController extends BaseController
{
return error("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
}
else if (!menuService.checkRouteConfigUnique(menu))
{
return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
}
menu.setCreateBy(getUsername());
return toAjax(menuService.insertMenu(menu));
}
@ -117,6 +121,10 @@ public class SysMenuController extends BaseController
{
return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
}
else if (!menuService.checkRouteConfigUnique(menu))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
}
menu.setUpdateBy(getUsername());
return toAjax(menuService.updateMenu(menu));
}

View File

@ -6,8 +6,8 @@ ruoyi:
version: 3.9.1
# 版权年份
copyrightYear: 2026
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:/ruoyi/uploadPath
# 文件路径(相对路径,基于项目根目录
profile: ./uploads
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<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" />

View File

@ -122,4 +122,13 @@ public interface SysMenuMapper
* @return 结果
*/
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);
}

View File

@ -141,4 +141,12 @@ public interface ISysMenuService
* @return 结果
*/
public boolean checkMenuNameUnique(SysMenu menu);
/**
* 校验路由组合是否唯一
*
* @param menu 菜单信息
* @return 结果
*/
public boolean checkRouteConfigUnique(SysMenu menu);
}

View File

@ -8,6 +8,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.constant.Constants;
@ -32,8 +34,12 @@ import com.ruoyi.system.service.ISysMenuService;
@Service
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 Long MENU_ROOT_ID = 0L;
@Autowired
private SysMenuMapper menuMapper;
@ -138,7 +144,7 @@ public class SysMenuServiceImpl implements ISysMenuService
{
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);
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.setPath("/");
@ -345,6 +351,47 @@ public class SysMenuServiceImpl implements ISysMenuService
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();
// 内链打开外网方式
if (menu.getParentId().intValue() != 0 && isInnerLink(menu))
if (menu.getParentId().intValue() != MENU_ROOT_ID && isInnerLink(menu))
{
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()))
{
routerPath = "/" + menu.getPath();
@ -415,7 +462,7 @@ public class SysMenuServiceImpl implements ISysMenuService
{
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;
}
@ -434,10 +481,21 @@ public class SysMenuServiceImpl implements ISysMenuService
*/
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);
}
/**
* 是否为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());
}
/**
* 是否为parent_view组件
*
* @param menu 菜单信息
* @return 结果
*/
public boolean isParentView(SysMenu menu)
{
return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType());
}
/**
* 根据父节点的ID获取所有子节点
*
@ -467,7 +514,7 @@ public class SysMenuServiceImpl implements ISysMenuService
* @param parentId 传入的父节点ID
* @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>();
for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)

View File

@ -130,7 +130,12 @@
<select id="checkMenuNameUnique" parameterType="SysMenu" resultMap="SysMenuResult">
<include refid="selectMenuVo"/>
where menu_name=#{menuName} and parent_id = #{parentId} limit 1
where menu_name= #{menuName} and parent_id = #{parentId} limit 1
</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">

View File

@ -68,5 +68,6 @@
"browserslist": [
"> 1%",
"last 2 versions"
]
],
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
}

11342
ruoyi-ui/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
onlyBuiltDependencies:
- core-js
- ejs
- fsevents
- highlight.js

View File

@ -1,5 +1,5 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
import { parseStrEmpty } from "@/utils/ruoyi"
// 查询用户列表
export function listUser(query) {

View File

@ -118,8 +118,6 @@ export default {
this.fuse = new Fuse(list, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
minMatchCharLength: 1,
keys: [{
name: 'title',

View File

@ -26,6 +26,8 @@ service.interceptors.request.use(config => {
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
// 间隔时间(ms),小于此时间视为重复提交
const interval = (config.headers || {}).interval || 1000
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
@ -55,7 +57,6 @@ service.interceptors.request.use(config => {
const s_url = sessionObj.url // 请求地址
const s_data = sessionObj.data // 请求数据
const s_time = sessionObj.time // 请求时间
const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交'
console.warn(`[${s_url}]: ` + message)
@ -115,7 +116,7 @@ service.interceptors.response.use(res => {
} else if (message.includes("timeout")) {
message = "系统接口请求超时"
} 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 })
return Promise.reject(error)

View File

@ -88,7 +88,7 @@
<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> 满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>
<i class="el-icon-chat-dot-round"></i> 微信<a

View File

@ -477,13 +477,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.jobId != undefined) {
updateJob(this.form).then(response => {
updateJob(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addJob(this.form).then(response => {
addJob(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -128,7 +128,7 @@ export default {
this.$refs.registerForm.validate(valid => {
if (valid) {
this.loading = true
register(this.registerForm).then(res => {
register(this.registerForm).then(() => {
const username = this.registerForm.username
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
dangerouslyUseHTMLString: true,

View File

@ -301,13 +301,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.configId != undefined) {
updateConfig(this.form).then(response => {
updateConfig(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addConfig(this.form).then(response => {
addConfig(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -311,13 +311,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.deptId != undefined) {
updateDept(this.form).then(response => {
updateDept(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addDept(this.form).then(response => {
addDept(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -363,14 +363,14 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.dictCode != undefined) {
updateData(this.form).then(response => {
updateData(this.form).then(() => {
this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addData(this.form).then(response => {
addData(this.form).then(() => {
this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
this.$modal.msgSuccess("新增成功")
this.open = false

View File

@ -304,13 +304,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.dictId != undefined) {
updateType(this.form).then(response => {
updateType(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addType(this.form).then(response => {
addType(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -448,13 +448,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.menuId != undefined) {
updateMenu(this.form).then(response => {
updateMenu(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addMenu(this.form).then(response => {
addMenu(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -282,13 +282,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.noticeId != undefined) {
updateNotice(this.form).then(response => {
updateNotice(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addNotice(this.form).then(response => {
addNotice(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -273,13 +273,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.postId != undefined) {
updatePost(this.form).then(response => {
updatePost(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addPost(this.form).then(response => {
addPost(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -184,7 +184,7 @@ export default {
}).catch(() => {})
},
/** 批量取消授权按钮操作 */
cancelAuthUserAll(row) {
cancelAuthUserAll() {
const roleId = this.queryParams.roleId
const userIds = this.userIds.join(",")
this.$modal.confirm('是否取消选中用户授权数据项?').then(function() {

View File

@ -557,14 +557,14 @@ export default {
if (valid) {
if (this.form.roleId != undefined) {
this.form.menuIds = this.getMenuAllCheckedKeys()
updateRole(this.form).then(response => {
updateRole(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
this.form.menuIds = this.getMenuAllCheckedKeys()
addRole(this.form).then(response => {
addRole(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
@ -577,7 +577,7 @@ export default {
submitDataScope: function() {
if (this.form.roleId != undefined) {
this.form.deptIds = this.getDeptAllCheckedKeys()
dataScope(this.form).then(response => {
dataScope(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.openDataScope = false
this.getList()

View File

@ -108,7 +108,7 @@ export default {
submitForm() {
const userId = this.form.userId
const roleIds = this.roleIds.join(",")
updateAuthRole({ userId: userId, roleIds: roleIds }).then((response) => {
updateAuthRole({ userId: userId, roleIds: roleIds }).then(() => {
this.$modal.msgSuccess("授权成功")
this.close()
})

View File

@ -476,7 +476,7 @@ export default {
}
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
resetUserPwd(row.userId, value).then(() => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
@ -491,13 +491,13 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
updateUser(this.form).then(response => {
updateUser(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
addUser(this.form).then(() => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()

View File

@ -55,7 +55,7 @@ export default {
submit() {
this.$refs["form"].validate(valid => {
if (valid) {
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(() => {
this.$modal.msgSuccess("修改成功")
})
}

View File

@ -72,7 +72,7 @@ export default {
submit() {
this.$refs["form"].validate(valid => {
if (valid) {
updateUserProfile(this.form).then(response => {
updateUserProfile(this.form).then(() => {
this.$modal.msgSuccess("修改成功")
this.user.phonenumber = this.form.phonenumber
this.user.email = this.form.email

View File

@ -98,9 +98,9 @@
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
</template>
</el-table-column>
<el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" width="120" />
<el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" width="120" />
<el-table-column label="实体" align="center" prop="className" :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="140" />
<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="updateTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="160" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -262,7 +262,7 @@ export default {
return
}
if(row.genType === "1") {
genCode(row.tableName).then(response => {
genCode(row.tableName).then(() => {
this.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath)
})
} else {

View File

@ -1,3 +1,4 @@
SET NAMES 'utf8';
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;

View File

@ -1,3 +1,4 @@
SET NAMES 'utf8';
-- ----------------------------
-- 1、部门表
-- ----------------------------